1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package eu.ehri.project.core.impl;
21
22 import com.google.common.base.Preconditions;
23 import com.google.common.collect.Iterables;
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Maps;
26 import com.tinkerpop.blueprints.CloseableIterable;
27 import com.tinkerpop.blueprints.Element;
28 import com.tinkerpop.blueprints.Graph;
29 import com.tinkerpop.blueprints.Vertex;
30 import com.tinkerpop.blueprints.util.WrappingCloseableIterable;
31 import com.tinkerpop.frames.FramedGraph;
32 import eu.ehri.project.core.GraphManager;
33 import eu.ehri.project.exceptions.IntegrityError;
34 import eu.ehri.project.exceptions.ItemNotFound;
35 import eu.ehri.project.models.EntityClass;
36 import eu.ehri.project.models.annotations.EntityType;
37 import eu.ehri.project.models.base.Entity;
38
39 import java.util.List;
40 import java.util.Map;
41 import java.util.NoSuchElementException;
42
43
44
45
46
47
48
49 public class BlueprintsGraphManager<T extends Graph> implements GraphManager {
50
51 protected static final String METADATA_PREFIX = "_";
52
53 protected final FramedGraph<T> graph;
54
55 public FramedGraph<T> getGraph() {
56 return graph;
57 }
58
59 public BlueprintsGraphManager(FramedGraph<T> graph) {
60 this.graph = graph;
61 }
62
63 @Override
64 public String getId(Vertex vertex) {
65 return vertex.getProperty(EntityType.ID_KEY);
66 }
67
68 @Override
69 public String getType(Vertex vertex) {
70 return vertex.getProperty(EntityType.TYPE_KEY);
71 }
72
73 @Override
74 public Map<String, Object> getProperties(Vertex vertex) {
75 Map<String, Object> props = Maps.newHashMap();
76 for (String key : vertex.getPropertyKeys()) {
77 if (!key.startsWith(METADATA_PREFIX)) {
78 props.put(key, vertex.getProperty(key));
79 }
80 }
81 return props;
82 }
83
84 @Override
85 public EntityClass getEntityClass(Vertex vertex) {
86 Preconditions.checkNotNull(vertex);
87 return EntityClass.withName(getType(vertex));
88 }
89
90 @Override
91 public EntityClass getEntityClass(Entity entity) {
92 Preconditions.checkNotNull(entity);
93 return EntityClass.withName(entity.getType());
94 }
95
96 @Override
97 public boolean exists(String id) {
98 Preconditions.checkNotNull(id,
99 "attempt determine existence of a vertex with a null id");
100 return graph.getVertices(EntityType.ID_KEY, id).iterator().hasNext();
101 }
102
103 @Override
104 public <E> E getEntity(String id, Class<E> cls) throws ItemNotFound {
105 return graph.frame(getVertex(id), cls);
106 }
107
108 @Override
109 public <E> E getEntity(String id, EntityClass type, Class<E> cls)
110 throws ItemNotFound {
111 return graph.frame(getVertex(id), cls);
112 }
113
114 @Override
115 public <E> CloseableIterable<E> getEntities(EntityClass type, Class<E> cls) {
116 return new WrappingCloseableIterable<>(
117 graph.frameVertices(getVertices(type), cls));
118 }
119
120 @Override
121 public <E> CloseableIterable<E> getEntities(String key, Object value, EntityClass type, Class<E> cls) {
122 return new WrappingCloseableIterable<>(
123 graph.frameVertices(getVertices(key, value, type), cls));
124 }
125
126 @Override
127 public Vertex getVertex(String id) throws ItemNotFound {
128 Preconditions
129 .checkNotNull(id, "attempt to fetch vertex with a null id");
130 try {
131 return graph.getVertices(EntityType.ID_KEY, id).iterator().next();
132 } catch (NoSuchElementException e) {
133 throw new ItemNotFound(id);
134 }
135 }
136
137 @Override
138 public CloseableIterable<Vertex> getVertices(EntityClass type) {
139 return new WrappingCloseableIterable<>(
140 graph.getVertices(EntityType.TYPE_KEY, type.getName()));
141 }
142
143 @Override
144 public CloseableIterable<Vertex> getVertices(Iterable<String> ids) {
145 Iterable<Vertex> verts = Iterables.transform(ids, id -> {
146 try {
147 return getVertex(id);
148 } catch (ItemNotFound e) {
149 return null;
150 }
151 });
152 return new WrappingCloseableIterable<>(verts);
153 }
154
155 @Override
156 public CloseableIterable<Vertex> getVertices(String key, Object value, EntityClass type) {
157
158 List<Vertex> elems = Lists.newArrayList();
159 for (Vertex v : graph.getVertices(key, value)) {
160 if (getEntityClass(v).equals(type)) {
161 elems.add(v);
162 }
163 }
164 return new WrappingCloseableIterable<>(elems);
165 }
166
167 @Override
168 public Vertex createVertex(String id, EntityClass type,
169 Map<String, ?> data) throws IntegrityError {
170 Preconditions
171 .checkNotNull(id, "null vertex ID given for item creation");
172 Map<String, ?> indexData = getVertexData(id, type, data);
173 checkExists(id);
174 Vertex node = graph.addVertex(null);
175 for (Map.Entry<String, ?> entry : indexData.entrySet()) {
176 if (entry.getValue() == null)
177 continue;
178 node.setProperty(entry.getKey(), entry.getValue());
179 }
180 return node;
181 }
182
183 @Override
184 public Vertex updateVertex(String id, EntityClass type,
185 Map<String, ?> data) throws ItemNotFound {
186 Preconditions.checkNotNull(id, "null vertex ID given for item update");
187 Map<String, ?> indexData = getVertexData(id, type, data);
188 try {
189 Vertex node = getVertex(id);
190 replaceProperties(node, indexData);
191 return node;
192 } catch (NoSuchElementException e) {
193 throw new ItemNotFound(id);
194 }
195 }
196
197 @Override
198 public void setProperty(Vertex vertex, String key, Object value) {
199 Preconditions.checkNotNull(vertex);
200 Preconditions.checkNotNull(key);
201 Preconditions.checkArgument(
202 !(key.trim().isEmpty() ||
203 key.equals(EntityType.ID_KEY) || key.equals(EntityType.TYPE_KEY)),
204 "Invalid property key: %s", key);
205 if (value == null) {
206 vertex.removeProperty(key);
207 } else {
208 vertex.setProperty(key, value);
209 }
210 }
211
212 @Override
213 public void renameVertex(Vertex vertex, String oldId, String newId) {
214 Preconditions.checkNotNull(vertex);
215 Preconditions.checkNotNull(newId);
216 vertex.setProperty(EntityType.ID_KEY, newId);
217 }
218
219 @Override
220 public void deleteVertex(String id) throws ItemNotFound {
221 deleteVertex(getVertex(id));
222 }
223
224 @Override
225 public void deleteVertex(Vertex vertex) {
226 vertex.remove();
227 }
228
229 @Override
230 public void initialize() {
231 }
232
233 private <E extends Element> void replaceProperties(E item, Map<String, ?> data) {
234
235 for (String key : item.getPropertyKeys()) {
236 if (!key.startsWith(METADATA_PREFIX)) {
237 item.removeProperty(key);
238 }
239 }
240
241
242 addProperties(item, data);
243 }
244
245 private <E extends Element> void addProperties(E item, Map<String, ?> data) {
246 Preconditions.checkNotNull(data, "Data map cannot be null");
247 for (Map.Entry<String, ?> entry : data.entrySet()) {
248 if (entry.getValue() == null)
249 continue;
250 item.setProperty(entry.getKey(), entry.getValue());
251 }
252 }
253
254 private void checkExists(String id) throws IntegrityError {
255 if (exists(id)) {
256 throw new IntegrityError(id);
257 }
258 }
259
260 private Map<String, ?> getVertexData(String id, EntityClass type,
261 Map<String, ?> data) {
262 Map<String, Object> vdata = Maps.newHashMap(data);
263 vdata.put(EntityType.ID_KEY, id);
264 vdata.put(EntityType.TYPE_KEY, type.getName());
265 return vdata;
266 }
267 }