1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.maxur.perfmodel.backend.infrastructure;
17
18 import org.iq80.leveldb.WriteBatch;
19 import org.jvnet.hk2.annotations.Service;
20 import org.maxur.perfmodel.backend.domain.ConflictException;
21 import org.maxur.perfmodel.backend.domain.Project;
22 import org.maxur.perfmodel.backend.domain.Repository;
23 import org.maxur.perfmodel.backend.service.Benchmark;
24 import org.maxur.perfmodel.backend.service.DataSource;
25 import org.slf4j.Logger;
26
27 import javax.inject.Inject;
28 import java.io.IOException;
29 import java.util.Collection;
30 import java.util.Optional;
31
32 import static java.lang.String.format;
33 import static java.util.Optional.empty;
34 import static org.slf4j.LoggerFactory.getLogger;
35
36
37
38
39
40
41
42
43 @Service
44 public class ProjectRepositoryLevelDbImpl implements Repository<Project> {
45
46 private static final Logger LOGGER = getLogger(ProjectRepositoryLevelDbImpl.class);
47
48 public static final String ROOT_PREFIX = "/";
49
50 @Inject
51 private DataSource dataSource;
52
53 @Override
54 @Benchmark
55 public Optional<Project> get(final String key) {
56 try {
57 return dataSource.get(key);
58 } catch (IOException | ClassNotFoundException e) {
59 return throwError(e, "Cannot find project by id '%s'", key);
60 }
61 }
62
63 @Override
64 @Benchmark
65 public Collection<Project> findAll() {
66 try {
67 return dataSource.findAllByPrefix(ROOT_PREFIX);
68 } catch (IOException | ClassNotFoundException e) {
69 return throwError(e, "Cannot get all projects");
70 }
71 }
72
73 @Override
74 @Benchmark
75 public Optional<Project> findByName(final String name) {
76 try {
77 return dataSource.get(path(name));
78 } catch (IOException | ClassNotFoundException e) {
79 return throwError(e, "Cannot find project by name '%s'", name);
80 }
81 }
82
83 @Override
84 @Benchmark
85 public Optional<Project> remove(final String key) {
86 try (WriteBatch batch = dataSource.createWriteBatch()) {
87 final Optional<Project> result = dataSource.get(key);
88 if (result.isPresent()) {
89 dataSource.delete(key);
90 dataSource.delete(path(result.get().getName()));
91 dataSource.commit(batch);
92 }
93 return result;
94 } catch (IOException | ClassNotFoundException e) {
95 return throwError(e, "Cannot remove project '%s'", key);
96 }
97
98 }
99
100 @Override
101 @Benchmark
102 public Optional<Project> add(final Project value) throws ConflictException {
103 final String id = value.getId();
104 final String newName = value.getName();
105 try (WriteBatch batch = dataSource.createWriteBatch()) {
106 final Optional<Project> other = dataSource.get(id);
107 if (value.isSame(other)) {
108 return other;
109 }
110 value.checkUniqueId(other);
111 value.checkNamesakes(findByName(newName));
112 value.makeVersion();
113 dataSource.put(id, value);
114 dataSource.put(path(newName), value.brief());
115 dataSource.commit(batch);
116 return Optional.of(value);
117 } catch (IOException | ClassNotFoundException e) {
118 return throwError(e, "Cannot save project '%s'", newName);
119 }
120 }
121
122 @Override
123 @Benchmark
124
125 public Optional<Project> amend(final Project value) throws ConflictException {
126 final String id = value.getId();
127 final String newName = value.getName();
128 value.incVersion();
129
130 try (WriteBatch batch = dataSource.createWriteBatch()) {
131 final Optional<Project> prev = dataSource.get(id);
132 if (!prev.isPresent()) {
133 return empty();
134 }
135 if (value.isSame(prev)) {
136 return prev;
137 }
138 value.checkConflictWith(prev);
139 final boolean mustBeRenamed = !prev.get().getName().equals(newName);
140 if (mustBeRenamed) {
141 value.checkNamesakes(findByName(newName));
142 dataSource.delete(path(prev.get().getName()));
143 }
144 dataSource.put(id, value);
145 dataSource.put(path(newName), value.brief());
146 dataSource.commit(batch);
147 return Optional.of(value);
148 } catch (IOException | ClassNotFoundException e) {
149 return throwError(e, "Cannot save project '%s'", newName);
150 }
151 }
152
153 private String path(final String name) {
154 return ROOT_PREFIX + name;
155 }
156
157 private static <T> T throwError(final Exception e, final String message, final String... args) {
158 final String msg = format(message, args);
159 LOGGER.error(msg, e);
160 throw new IllegalStateException(msg, e);
161 }
162
163 }