1
2
3
4
5
6
7
8
9
10 package de.uni_leipzig.wifa.iwi.mr3.dao.neo4j.impl;
11
12 import java.io.File;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 import org.apache.log4j.Logger;
20 import org.eclipse.emf.common.util.URI;
21 import org.eclipse.emf.ecore.EObject;
22 import org.eclipse.emf.ecore.EPackage;
23 import org.eclipse.emf.ecore.EcorePackage;
24 import org.eclipse.emf.ecore.resource.Resource;
25 import org.eclipse.emf.ecore.resource.ResourceSet;
26 import org.eclipse.emf.ecore.resource.Resource.Factory;
27 import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
28 import org.eclipse.emf.ecore.xmi.XMIResource;
29 import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
30 import org.neo4j.api.core.Direction;
31 import org.neo4j.api.core.EmbeddedNeo;
32 import org.neo4j.api.core.NeoService;
33 import org.neo4j.api.core.Node;
34 import org.neo4j.api.core.Relationship;
35 import org.neo4j.api.core.ReturnableEvaluator;
36 import org.neo4j.api.core.StopEvaluator;
37 import org.neo4j.api.core.Transaction;
38 import org.neo4j.api.core.Traverser.Order;
39
40 import de.uni_leipzig.wifa.iwi.mr3.common.Match;
41 import de.uni_leipzig.wifa.iwi.mr3.dao.Constants;
42 import de.uni_leipzig.wifa.iwi.mr3.dao.LoadProcessor;
43 import de.uni_leipzig.wifa.iwi.mr3.dao.ModelRepositoryDao;
44 import de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor;
45 import de.uni_leipzig.wifa.iwi.mr3.dao.SearchProcessor;
46 import de.uni_leipzig.wifa.iwi.mr3.dao.neo4j.EcoreRelationshipType;
47 import de.uni_leipzig.wifa.iwi.mr3.service.MRException;
48
49
50
51
52 public class ModelRepositoryDaoNeo4jImpl implements ModelRepositoryDao
53 {
54
55 private static final Logger LOG = Logger.getLogger(ModelRepositoryDaoNeo4jImpl.class);
56
57
58 private NeoService neo;
59
60
61 private String databasePath;
62
63
64 private NeoHelper helper;
65
66
67 private SearchProcessor searchProcessor;
68
69
70 private LoadProcessor loadProcessor;
71
72
73 private SaveProcessor saveProcessorPhaseOne;
74
75
76 private SaveProcessor saveProcessorPhaseTwo;
77
78
79 private static final String DEFAULT_CONTENT_TYPE = "*";
80
81
82 private static final Factory RESOURCE_FACTORY = new XMIResourceFactoryImpl();
83
84
85
86
87
88
89
90 public void setDatabasePath(final String databasePath)
91 {
92 this.databasePath = databasePath;
93 }
94
95
96
97
98
99
100 public String getDatabasePath()
101 {
102 return databasePath;
103 }
104
105
106
107
108 @Override
109 public void startUp()
110 {
111 LOG.debug("Initialize database.");
112 if (neo != null)
113 {
114 shutDown();
115 }
116 if (LOG.isInfoEnabled())
117 {
118 LOG.info("Using neo4j database location at " + new File(databasePath).getAbsolutePath());
119 }
120 neo = new EmbeddedNeo(databasePath);
121
122 helper = new NeoHelper();
123 helper.setNeo(neo);
124
125 final PhaseOneSaveProcessor spp1 = new PhaseOneSaveProcessor();
126 spp1.setHelper(helper);
127 saveProcessorPhaseOne = spp1;
128
129 final PhaseTwoSaveProcessor spp2 = new PhaseTwoSaveProcessor();
130 spp2.setHelper(helper);
131 saveProcessorPhaseTwo = spp2;
132
133 final LoadProcessorImpl lp = new LoadProcessorImpl();
134 loadProcessor = lp;
135
136 final SearchProcessorImpl sp = new SearchProcessorImpl();
137 sp.setHelper(helper);
138 searchProcessor = sp;
139 }
140
141
142
143
144 @Override
145 public void shutDown()
146 {
147 LOG.debug("Shutdown neo4j DAO.");
148 neo.shutdown();
149 neo = null;
150 }
151
152
153
154
155
156
157
158 public void setNeo(final NeoService neo)
159 {
160 this.neo = neo;
161 }
162
163
164
165
166
167
168 public NeoService getNeo()
169 {
170 return neo;
171 }
172
173
174
175
176
177
178
179 public void setHelper(final NeoHelper helper)
180 {
181 this.helper = helper;
182 }
183
184
185
186
187
188
189 public NeoHelper getHelper()
190 {
191 return helper;
192 }
193
194
195
196
197
198
199
200 public void setSaveProcessorPhaseOne(final SaveProcessor saveProcessorPhaseOne)
201 {
202 this.saveProcessorPhaseOne = saveProcessorPhaseOne;
203 }
204
205
206
207
208
209
210 public SaveProcessor getSaveProcessorPhaseOne()
211 {
212 return saveProcessorPhaseOne;
213 }
214
215
216
217
218
219
220
221 public void setSaveProcessorPhaseTwo(final SaveProcessor saveProcessorPhaseTwo)
222 {
223 this.saveProcessorPhaseTwo = saveProcessorPhaseTwo;
224 }
225
226
227
228
229
230
231 public SaveProcessor getSaveProcessorPhaseTwo()
232 {
233 return saveProcessorPhaseTwo;
234 }
235
236
237
238
239
240
241
242 public void setLoadProcessor(final LoadProcessor loadProcessor)
243 {
244 this.loadProcessor = loadProcessor;
245 }
246
247
248
249
250
251
252 public LoadProcessor getLoadProcessor()
253 {
254 return loadProcessor;
255 }
256
257
258
259
260
261
262
263 public void setSearchProcessor(final SearchProcessor searchProcessor)
264 {
265 this.searchProcessor = searchProcessor;
266 }
267
268
269
270
271
272
273 public SearchProcessor getSearchProcessor()
274 {
275 return searchProcessor;
276 }
277
278
279
280
281
282
283
284
285
286 @Override
287 public String[] getInstanceModels(final String metaNsUri)
288 {
289 final Transaction tx = neo.beginTx();
290 try
291 {
292 final List<String> instanceModels = new ArrayList<String>();
293
294 final Iterable<Node> models = helper.getSubrefNodeChildren(EcoreRelationshipType.RESOURCES);
295
296 for (final Node model : models)
297 {
298
299 if (null == metaNsUri || "".equals(metaNsUri))
300 {
301
302
303 if (!model.getRelationships(EcoreRelationshipType.INSTANCE_MODEL, Direction.INCOMING).iterator().hasNext())
304 {
305 instanceModels.add((String) model.getProperty(Constants.PROPERTY_NS_URI));
306 }
307 }
308
309 else
310 {
311 if (metaNsUri.equals(model.getProperty(Constants.PROPERTY_NS_URI)))
312 {
313
314
315 for (final Relationship relationship : model.getRelationships(EcoreRelationshipType.INSTANCE_MODEL,
316 Direction.OUTGOING))
317 {
318 instanceModels.add((String) relationship.getEndNode().getProperty(Constants.PROPERTY_NS_URI));
319 }
320 }
321 }
322 }
323 tx.success();
324
325 final String[] response = instanceModels.toArray(new String[instanceModels.size()]);
326 Arrays.sort(response);
327 return response;
328 }
329 finally
330 {
331 tx.finish();
332 }
333 }
334
335
336
337
338
339
340
341
342
343 @Override
344 public boolean modelExists(final String nsUri)
345 {
346 LOG.debug("DAO modelExists()");
347
348 final Transaction tx = neo.beginTx();
349 try
350 {
351
352 for (final Node modelNode : helper.getSubrefNodeChildren(EcoreRelationshipType.RESOURCES))
353 {
354 if (((String) modelNode.getProperty(Constants.PROPERTY_NS_URI)).equals(nsUri))
355 {
356 return true;
357 }
358
359 final Node ePackageNode = helper.determineEcoreClassifierNode(EcorePackage.Literals.EPACKAGE.getName());
360 if (null != ePackageNode)
361 {
362 for (final Node packageNode : ePackageNode.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
363 ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.INSTANCE, Direction.OUTGOING))
364 {
365 if (nsUri.equals(packageNode.getProperty(Constants.PROPERTY_NS_URI)))
366 {
367 return true;
368 }
369 }
370 }
371 }
372 }
373 finally
374 {
375 tx.finish();
376 }
377 return false;
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 @Override
394 public void save(final Resource resource) throws MRException
395 {
396 LOG.debug("DAO save()");
397
398 final Transaction tx = neo.beginTx();
399 try
400 {
401
402 final Map<EObject, Object> registry = new HashMap<EObject, Object>();
403
404
405
406
407
408 saveProcessorPhaseOne.process(resource, registry);
409
410
411
412
413
414 saveProcessorPhaseTwo.process(resource, registry);
415
416 tx.success();
417 }
418 catch (final IllegalStateException e)
419 {
420 throw new MRException("Could not save model:" + e.getMessage(), e);
421 }
422 finally
423 {
424 tx.finish();
425 }
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439 @Override
440 public EObject load(final String nsUri, final Map<Object, EObject> registry)
441 {
442 LOG.debug("DAO load(String)");
443 final ResourceSet rset = new ResourceSetImpl();
444 rset.getResourceFactoryRegistry().getContentTypeToFactoryMap().put(DEFAULT_CONTENT_TYPE, RESOURCE_FACTORY);
445
446 final Transaction tx = neo.beginTx();
447 try
448 {
449 final Node modelNode = helper.getModelNode(nsUri);
450 if (null == modelNode)
451 {
452 return findTopLevelPackage(nsUri, registry);
453 }
454 else
455 {
456 for (final Node referenced : modelNode.traverse(Order.BREADTH_FIRST, StopEvaluator.END_OF_GRAPH,
457 ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.DEPENDS, Direction.OUTGOING,
458 EcoreRelationshipType.INSTANCE_MODEL, Direction.INCOMING))
459 {
460 final String uri = (String) referenced.getProperty(Constants.PROPERTY_NS_URI);
461 final XMIResource resource = (XMIResource) rset.createResource(URI.createURI(uri));
462 resource.getContents().add(load(uri, registry));
463 }
464 return loadProcessor.process(modelNode, registry);
465 }
466 }
467 finally
468 {
469 tx.finish();
470 }
471 }
472
473
474
475
476
477
478
479
480
481
482
483 private EPackage findTopLevelPackage(final String nsUri, final Map<Object, EObject> registry)
484 {
485 final Node ePackageNode = helper.determineEcoreClassifierNode(EcorePackage.Literals.EPACKAGE.getName());
486 for (final Node pkgNode : ePackageNode.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
487 ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.INSTANCE, Direction.OUTGOING))
488 {
489 if (nsUri.equals(pkgNode.getProperty(Constants.PROPERTY_NS_URI)))
490 {
491 Node container = pkgNode;
492 while (container.hasRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING))
493 {
494 container = container.getSingleRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING).getStartNode();
495 }
496 return (EPackage) load((String) container.getProperty(Constants.PROPERTY_NS_URI), registry);
497 }
498 }
499 return null;
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513
514 @Override
515 public void delete(final String nsUri, final boolean cascading) throws MRException
516 {
517 LOG.debug("DAO delete()");
518
519 final Transaction tx = neo.beginTx();
520 try
521 {
522 for (final Node modelNode : helper.getSubrefNodeChildren(EcoreRelationshipType.RESOURCES))
523 {
524 if (nsUri.equals(modelNode.getProperty(Constants.PROPERTY_NS_URI)))
525 {
526 deleteContent(modelNode, cascading);
527 tx.success();
528 return;
529 }
530 }
531
532 throw new MRException("Could not find model with nsUri:" + nsUri);
533 }
534 finally
535 {
536 tx.finish();
537 }
538 }
539
540
541
542
543
544
545
546
547
548
549
550 private void deleteContent(final Node modelNode, final boolean cascading) throws MRException
551 {
552
553 final Iterable<Node> contents =
554 modelNode.traverse(Order.DEPTH_FIRST, StopEvaluator.END_OF_GRAPH, ReturnableEvaluator.ALL,
555 EcoreRelationshipType.CONTAINS, Direction.OUTGOING);
556
557 if (modelNode.hasRelationship(EcoreRelationshipType.DEPENDS, Direction.INCOMING))
558 {
559 final StringBuilder message = new StringBuilder("Could not delete model. Please first delete models that depend on it: ");
560 final List<Node> dependentModels = new ArrayList<Node>(modelNode.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
561 ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.DEPENDS, Direction.INCOMING).getAllNodes());
562 for (int i = 0; i < dependentModels.size(); i++)
563 {
564 message.append((String) dependentModels.get(i).getProperty(Constants.PROPERTY_NS_URI))
565 .append(
566 i < dependentModels.size() - 1 ? ", " : ".");
567 }
568 throw new MRException(message.toString());
569 }
570 if (modelNode.hasRelationship(EcoreRelationshipType.INSTANCE_MODEL, Direction.OUTGOING))
571 {
572 if (cascading)
573 {
574 for (final Relationship relationship : modelNode.getRelationships(EcoreRelationshipType.INSTANCE_MODEL,
575 Direction.OUTGOING))
576 {
577 deleteContent(relationship.getEndNode(), cascading);
578 }
579
580
581 }
582 else
583 {
584 throw new MRException("You have to delete instance models of this model first!");
585 }
586 }
587
588
589 for (final Node node : contents)
590 {
591 if (node.hasRelationship())
592 {
593 for (final Relationship relationship : node.getRelationships())
594 {
595 relationship.delete();
596 }
597 }
598 node.delete();
599 }
600 }
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 @Override
618 public Match[] find(final String expression, final String[] classifiers, final boolean isRegEx, final boolean isCaseSensitive)
619 {
620 LOG.debug("DAO find()");
621
622 Arrays.sort(classifiers);
623
624 final int eObjectPos = Arrays.binarySearch(classifiers, EcorePackage.Literals.EOBJECT.getName());
625 final boolean containsEObject = eObjectPos >= 0;
626 final Transaction tx = neo.beginTx();
627 try
628 {
629 if (containsEObject)
630 {
631 return searchProcessor.processCompleteSearch(expression, classifiers, isCaseSensitive, isRegEx);
632 }
633 return searchProcessor.processPartialSearch(expression, classifiers, isCaseSensitive, isRegEx);
634 }
635 finally
636 {
637 tx.finish();
638 }
639 }
640 }