View Javadoc

1   //
2   // $Revision: 5 $
3   // $LastChangedBy: mhanns $
4   // $Date: 2010-04-01 10:10:45 +0200 (Do, 01 Apr 2010) $
5   // $HeadURL:
6   // svn://localhost/winf-ps/trunk/repository/src/main/java/de/uni_leipzig/wifa/iwi/mr3/dao/impl/neo4j/PhaseTwoSaveProcessor.java
7   // $
8   //
9   
10  package de.uni_leipzig.wifa.iwi.mr3.dao.neo4j.impl;
11  
12  import java.util.Map;
13  
14  import org.eclipse.emf.common.util.EList;
15  import org.eclipse.emf.ecore.EAnnotation;
16  import org.eclipse.emf.ecore.EAttribute;
17  import org.eclipse.emf.ecore.EClass;
18  import org.eclipse.emf.ecore.EClassifier;
19  import org.eclipse.emf.ecore.EDataType;
20  import org.eclipse.emf.ecore.EEnum;
21  import org.eclipse.emf.ecore.EEnumLiteral;
22  import org.eclipse.emf.ecore.EGenericType;
23  import org.eclipse.emf.ecore.EObject;
24  import org.eclipse.emf.ecore.EOperation;
25  import org.eclipse.emf.ecore.EPackage;
26  import org.eclipse.emf.ecore.EParameter;
27  import org.eclipse.emf.ecore.EReference;
28  import org.eclipse.emf.ecore.EStructuralFeature;
29  import org.eclipse.emf.ecore.ETypeParameter;
30  import org.eclipse.emf.ecore.EcorePackage;
31  import org.eclipse.emf.ecore.impl.EStringToStringMapEntryImpl;
32  import org.neo4j.api.core.Direction;
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.Traverser.Order;
38  
39  import de.uni_leipzig.wifa.iwi.mr3.dao.Constants;
40  import de.uni_leipzig.wifa.iwi.mr3.dao.neo4j.EcoreRelationshipType;
41  
42  /**
43   * Implements the phase two: importing element's other relationships (meta,
44   * type, super, ...) into nodepsace.
45   * <p>
46   * This phase depends on already finished phase one where all nodes get
47   * generated.
48   */
49  public class PhaseTwoSaveProcessor extends AbstractNeoSaveProcessor
50  {
51    /**
52     * Process an <code>EPackage</code>.
53     *
54     * @param element
55     *          <code>EPackage</code>
56     * @param registry
57     *          Node cache
58     * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EPackage,
59     *      java.util.Map)
60     */
61    @Override
62    public void process(final EPackage element, final Map<EObject, Object> registry)
63    {
64      // relationships
65      final EPackage container = element.getESuperPackage();
66      if (null == container && !element.getNsURI().equals(EcorePackage.eNS_URI))
67      {
68        final Node metamodelNode = getHelper().getModelNode(EcorePackage.eNS_URI);
69        if (null == metamodelNode)
70        {
71          throw new IllegalStateException("First save the meta model with nsURI: " + EcorePackage.eNS_URI);
72        }
73        metamodelNode.createRelationshipTo(getNodeFromRegistry(element, registry), EcoreRelationshipType.INSTANCE_MODEL);
74      }
75  
76      // ePackage -> EPackage
77      setMetaElement(element, EPackage.class, registry);
78    }
79  
80    /**
81     * Process an <code>EDataType</code>.
82     *
83     * @param element
84     *          <code>EDataType</code>
85     * @param registry
86     *          Node cache
87     * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EDataType,
88     *      java.util.Map)
89     */
90    @Override
91    public void process(final EDataType element, final Map<EObject, Object> registry)
92    {
93      // eDataType -> EDataType
94      setMetaElement(element, EDataType.class, registry);
95    }
96  
97    /**
98     * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor_#process(org.eclipse.emf.ecore.EClass)
99     *      Process an <code>EClass</code>.
100    * @param element
101    *          <code>EClass</code>
102    * @param registry
103    *          Node cache
104    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EClass,
105    *      java.util.Map)
106    */
107   @Override
108   public void process(final EClass element, final Map<EObject, Object> registry)
109   {
110     // set inheritance relationship.
111     setSuperElements(element, registry);
112 
113     // eClass -> EClass
114     setMetaElement(element, EClass.class, registry);
115   }
116 
117   /**
118    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor_#process(org.eclipse.emf.ecore.EEnum)
119    *      Process an <code>EEnum</code>.
120    * @param element
121    *          <code>EEnum</code>
122    * @param registry
123    *          Node cache
124    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EEnum,
125    *      java.util.Map)
126    */
127   @Override
128   public void process(final EEnum element, final Map<EObject, Object> registry)
129   {
130     // eEnum -> EEnum
131     setMetaElement(element, EEnum.class, registry);
132   }
133 
134   /**
135    * Process an <code>EAnnotation</code>.
136    *
137    * @param element
138    *          <code>EAnnotation</code>
139    * @param registry
140    *          Node cache
141    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EAnnotation,
142    *      java.util.Map)
143    */
144   @Override
145   public void process(final EAnnotation element, final Map<EObject, Object> registry)
146   {
147     // eAnnotation -> EAnnotation
148     setMetaElement(element, EAnnotation.class, registry);
149   }
150 
151   /**
152    * Process an <code>EOperation</code>.
153    *
154    * @param element
155    *          <code>EOperation</code>
156    * @param registry
157    *          Node cache
158    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EOperation,
159    *      java.util.Map)
160    */
161   @Override
162   public void process(final EOperation element, final Map<EObject, Object> registry)
163   {
164     // eOperation -> EOperation
165     setMetaElement(element, EOperation.class, registry);
166   }
167 
168   /**
169    * Process an <code>EAttribute</code>.
170    *
171    * @param element
172    *          <code>EAttribute</code>
173    * @param registry
174    *          Node cache
175    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EAttribute,
176    *      java.util.Map)
177    */
178   @Override
179   public void process(final EAttribute element, final Map<EObject, Object> registry)
180   {
181     // eAttribute -> EAttribute
182     setMetaElement(element, EAttribute.class, registry);
183   }
184 
185   /**
186    * Process an <code>EReference</code>.
187    *
188    * @param element
189    *          <code>EReference</code>
190    * @param registry
191    *          Node cache
192    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EReference,
193    *      java.util.Map)
194    */
195   @Override
196   public void process(final EReference element, final Map<EObject, Object> registry)
197   {
198     // eReference -> EReference
199     setMetaElement(element, EReference.class, registry);
200   }
201 
202   /**
203    * Process an <code>EEnumLiteral</code>.
204    *
205    * @param element
206    *          <code>EEnumLiteral</code>
207    * @param registry
208    *          Node cache
209    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EEnumLiteral,
210    *      java.util.Map)
211    */
212   @Override
213   public void process(final EEnumLiteral element, final Map<EObject, Object> registry)
214   {
215     // eEnumLiteral -> EEnumLiteral
216     setMetaElement(element, EEnumLiteral.class, registry);
217   }
218 
219   /**
220    * Process an <code>EGenericType</code>.
221    * <p>
222    *
223    * @param element
224    *          <code>EGenericType</code>
225    * @param registry
226    *          Node cache
227    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EGenericType,
228    *      java.util.Map)
229    */
230   @Override
231   public void process(final EGenericType element, final Map<EObject, Object> registry)
232   {
233     setMetaElement(element, EGenericType.class, registry);
234 
235     for (final EGenericType typeArgument : element.getETypeArguments())
236     {
237       getNodeFromRegistry(element, registry).createRelationshipTo(getNodeFromRegistry(typeArgument, registry),
238           EcoreRelationshipType.GENERIC_TYPE_ARGUMENT);
239     }
240     setTypeElement(element, registry);
241   }
242 
243   /**
244    * Process an <code>EParameter</code>.
245    * <p>
246    * {@link EParameter}s are ordered!
247    *
248    * @param element
249    *          <code>EParameter</code>
250    * @param registry
251    *          Node cache
252    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EParameter,
253    *      java.util.Map)
254    */
255   @Override
256   public void process(final EParameter element, final Map<EObject, Object> registry)
257   {
258     // eParameter -> EParameter
259     setMetaElement(element, EParameter.class, registry);
260   }
261 
262   /**
263    * Process an <code>ETypeParameter</code> (generic type parameters).
264    *
265    * @param element
266    *          <code>ETypeParameter</code>
267    * @param registry
268    *          Node cache
269    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.ETypeParameter,
270    *      java.util.Map)
271    */
272   @Override
273   public void process(final ETypeParameter element, final Map<EObject, Object> registry)
274   {
275     // eTypeParameter -> ETypeParameter
276     setMetaElement(element, ETypeParameter.class, registry);
277   }
278 
279   /**
280    * Process an <code>EStringToStringMapEntryImpl</code>.
281    *
282    * @param element
283    *          <code>EStringToStringMapEntryImpl</code>
284    * @param registry
285    *          Node cache
286    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.impl.EStringToStringMapEntryImpl,
287    *      java.util.Map)
288    */
289   @Override
290   public void process(final EStringToStringMapEntryImpl element, final Map<EObject, Object> registry)
291   {
292     setMetaElement(element, EStringToStringMapEntryImpl.class, registry);
293   }
294 
295   /**
296    * Process an general element.
297    *
298    * @param element
299    *          General element
300    * @param registry
301    *          Node cache
302    * @see de.uni_leipzig.wifa.iwi.mr3.dao.SaveProcessor#process(org.eclipse.emf.ecore.EObject,
303    *      java.util.Map)
304    */
305   @Override
306   public void process(final EObject element, final Map<EObject, Object> registry)
307   {
308     final Node node = getNodeFromRegistry(element, registry);
309 
310     // type relationship
311     final Node typeNode = determineNode(element.eClass(), registry);
312     typeNode.createRelationshipTo(node, EcoreRelationshipType.INSTANCE);
313 
314     // set attributes and their values
315     for (final EAttribute feature : element.eClass().getEAllAttributes())
316     {
317       final Object featureValue = element.eGet(feature);
318       if (featureValue != null)
319       {
320         if (featureValue instanceof EList<?>)
321         {
322           for (final Object singleFeatureValue : (EList<?>) featureValue)
323           {
324             final Node featureNode = createNodeWithRelationship(node, EcoreRelationshipType.CONTAINS, true);
325             featureNode.setProperty(Constants.PROPERTY_VALUE, singleFeatureValue);
326 
327             final Node metaNode = determineNode(feature, registry);
328             metaNode.createRelationshipTo(featureNode, EcoreRelationshipType.INSTANCE);
329           }
330         }
331         else
332         {
333           final Node featureNode = createNodeWithRelationship(node, EcoreRelationshipType.CONTAINS, true);
334           featureNode.setProperty(Constants.PROPERTY_VALUE, featureValue);
335 
336           // set meta relationship
337           final Node metaNode = determineNode(feature, registry);
338           metaNode.createRelationshipTo(featureNode, EcoreRelationshipType.INSTANCE);
339         }
340       }
341     }
342 
343     // set references
344     for (final EReference feature : element.eClass().getEAllReferences())
345     {
346       final Object featureValue = element.eGet(feature);
347       if (featureValue != null)
348       {
349         if (featureValue instanceof EObject)
350         {
351           final Node featureNode = createNodeWithRelationship(node, EcoreRelationshipType.CONTAINS, true);
352           featureNode.createRelationshipTo(getNodeFromRegistry((EObject) featureValue, registry),
353               feature.isContainment() ? EcoreRelationshipType.REFERENCES_AS_CONTAINMENT : EcoreRelationshipType.REFERENCES);
354 
355           // set meta relationship
356           final Node metaNode = determineNode(feature, registry);
357           metaNode.createRelationshipTo(featureNode, EcoreRelationshipType.INSTANCE);
358         }
359         else if (featureValue instanceof EList<?>)
360         {
361           for (final Object singleFeatureValue : (EList<?>) featureValue)
362           {
363             final Node featureNode = createNodeWithRelationship(node, EcoreRelationshipType.CONTAINS, true);
364             featureNode.createRelationshipTo(getNodeFromRegistry((EObject) singleFeatureValue, registry), feature
365                 .isContainment() ? EcoreRelationshipType.REFERENCES_AS_CONTAINMENT : EcoreRelationshipType.REFERENCES);
366 
367             // set meta relationship
368             final Node metaNode = determineNode(feature, registry);
369             metaNode.createRelationshipTo(featureNode, EcoreRelationshipType.INSTANCE);
370           }
371         }
372       }
373     }
374   }
375 
376   /**
377    * Set the super elements.
378    *
379    * @param element
380    *          Element to assign with its super elements.
381    * @param registry
382    *          Node cache
383    */
384   private void setSuperElements(final EClass element, final Map<EObject, Object> registry)
385   {
386     final Node node = getNodeFromRegistry(element, registry);
387 
388     final EList<EClass> supertypes = element.getESuperTypes();
389     for (final EClass supertype : supertypes)
390     {
391       node.createRelationshipTo(getNodeFromRegistry(supertype, registry), EcoreRelationshipType.SUPER);
392     }
393   }
394 
395   /**
396    * Set meta element.
397    *
398    * @param element
399    *          Element to assign with its meta model element
400    * @param clazz
401    *          Ecore class of meta model element
402    * @param registry
403    *          Node cache
404    */
405   private void setMetaElement(final EObject element, final Class<? extends EObject> clazz, final Map<EObject, Object> registry)
406   {
407     final String mapEntryName = EcorePackage.Literals.ESTRING_TO_STRING_MAP_ENTRY.getName();
408     final String className =
409         clazz.getSimpleName().contains(mapEntryName) ? mapEntryName : clazz.getSimpleName();
410 
411     final Node node = getHelper().determineEcoreClassifierNode(className);
412     if (null == node)
413     {
414       throw new IllegalStateException("The meta element " + clazz.getSimpleName() + " could not be found!");
415     }
416 
417     // omit reflexive relationships for self describing elements (like EClass)
418     final Node target = getNodeFromRegistry(element, registry);
419     if (node.equals(target))
420     {
421       return;
422     }
423 
424     node.createRelationshipTo(target, EcoreRelationshipType.INSTANCE);
425   }
426 
427   /**
428    * Set classifier.
429    *
430    * @param element
431    *          EGenericType to assign with its classifier
432    * @param registry
433    *          Node cache
434    */
435   private void setTypeElement(final EGenericType element, final Map<EObject, Object> registry)
436   {
437       // set EType
438       final EClassifier eType = element.getEClassifier();
439       if (eType != null)
440       {
441         final Node eTypeNode = determineNode(eType, registry);
442         if (null == eTypeNode)
443         {
444           throw new IllegalStateException("The type element " + eType + " could not be found!");
445         }
446 
447         Node container = getNodeFromRegistry(element, registry);
448         while (container.hasRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING))
449         {
450           container = container.getSingleRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING).getStartNode();
451         }
452 
453         Node typeContainer = eTypeNode;
454         while (typeContainer.hasRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING))
455         {
456           typeContainer =
457               typeContainer.getSingleRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING).getStartNode();
458         }
459 
460         if (!container.equals(typeContainer))
461         {
462           container.createRelationshipTo(typeContainer, EcoreRelationshipType.DEPENDS);
463         }
464 
465         getNodeFromRegistry(element, registry).createRelationshipTo(eTypeNode, EcoreRelationshipType.TYPE);
466       }
467   }
468 
469   /**
470    * Determines a node in nodespace for the given EPackage.
471    * <p>
472    *
473    * @param aPackage
474    *          the EPackage for which the node should be determined
475    * @return the package node
476    */
477   private Node determineNode(final EPackage aPackage)
478   {
479     final Node ePackageNode = getHelper().determineEcoreClassifierNode(EcorePackage.Literals.EPACKAGE.getName());
480     for (final Node pkgNode : ePackageNode.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
481         ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.INSTANCE, Direction.OUTGOING))
482     {
483       if (aPackage.getNsURI().equals(pkgNode.getProperty(Constants.PROPERTY_NS_URI)))
484       {
485         return pkgNode;
486       }
487     }
488     return null;
489   }
490 
491   /**
492    * Determines the node for the given EClassifier. Only to call in the second
493    * phase of the save process.
494    *
495    * @param element
496    *          the EClassifier for which the node should be determined
497    * @param registry
498    *          Node cache
499    * @return the classifier node
500    */
501   private Node determineNode(final EClassifier element, final Map<EObject, Object> registry)
502   {
503     final Node node = getNodeFromRegistry(element, registry);
504     if (node != null)
505     {
506       return node;
507     }
508 
509     // determine the direct container EPackage of this classifier
510     final Node packageNode = determineNode(element.getEPackage());
511     if (null == packageNode)
512     {
513       throw new IllegalStateException("The package with namespace uri [" + element.getEPackage().getNsURI()
514           + "] could not be found!");
515     }
516 
517     for (final Node aNode : packageNode.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
518         ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
519     {
520       if (aNode.hasProperty(Constants.PROPERTY_NAME))
521       {
522         final String classifierName = (String) aNode.getProperty(Constants.PROPERTY_NAME);
523         if (classifierName.equals(element.getName()))
524         {
525           // // meta relationship?
526           final Relationship metaRel = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING);
527           if (metaRel == null)
528           {
529             // only in ecore there are, sometimes, no meta relationships
530             registry.put(element, aNode);
531             return aNode;
532           }
533           final Node metaNode = metaRel.getStartNode();
534           if (EcorePackage.Literals.ECLASS.getName().equals(metaNode.getProperty(Constants.PROPERTY_NAME))
535               || EcorePackage.Literals.EDATA_TYPE.getName().equals(metaNode.getProperty(Constants.PROPERTY_NAME))
536               || EcorePackage.Literals.EENUM.getName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
537           {
538             // cache the element node
539             registry.put(element, aNode);
540             return aNode;
541           }
542         }
543       }
544     }
545 
546     return null;
547   }
548 
549   /**
550    * Determines the node for the given EStructuralFeature.
551    *
552    * @param element
553    *          the EStructuralFeature for which the node should be determined
554    * @param registry
555    *          Node cache
556    * @return the structural feature node
557    */
558   private Node determineNode(final EStructuralFeature element, final Map<EObject, Object> registry)
559   {
560     final Node node = getNodeFromRegistry(element, registry);
561     if (node != null)
562     {
563       return node;
564     }
565 
566     // determine the container EClassifier of this element
567     final Node classifierNode = determineNode(element.getEContainingClass(), registry);
568 
569     for (final Node aNode : classifierNode.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
570         ReturnableEvaluator.ALL_BUT_START_NODE, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
571     {
572       if (aNode.hasProperty(Constants.PROPERTY_NAME))
573       {
574         final String name = (String) aNode.getProperty(Constants.PROPERTY_NAME);
575         if (name.equals(element.getName()))
576         {
577           // meta relationship?
578           final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
579           if (!EcorePackage.Literals.EOPERATION.getName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
580           {
581             // cache the element node
582             registry.put(element, aNode);
583             return aNode;
584           }
585         }
586       }
587     }
588     return null;
589   }
590 }