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/LoadProcessor.java
7   // $
8   //
9   
10  package de.uni_leipzig.wifa.iwi.mr3.dao.neo4j.impl;
11  
12  import java.util.Comparator;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Set;
17  import java.util.TreeSet;
18  
19  import org.eclipse.emf.common.util.EMap;
20  import org.eclipse.emf.ecore.EAnnotation;
21  import org.eclipse.emf.ecore.EAttribute;
22  import org.eclipse.emf.ecore.EClass;
23  import org.eclipse.emf.ecore.EClassifier;
24  import org.eclipse.emf.ecore.EDataType;
25  import org.eclipse.emf.ecore.EEnum;
26  import org.eclipse.emf.ecore.EEnumLiteral;
27  import org.eclipse.emf.ecore.EFactory;
28  import org.eclipse.emf.ecore.EGenericType;
29  import org.eclipse.emf.ecore.EObject;
30  import org.eclipse.emf.ecore.EOperation;
31  import org.eclipse.emf.ecore.EPackage;
32  import org.eclipse.emf.ecore.EParameter;
33  import org.eclipse.emf.ecore.EReference;
34  import org.eclipse.emf.ecore.ETypeParameter;
35  import org.eclipse.emf.ecore.EcoreFactory;
36  import org.neo4j.api.core.Direction;
37  import org.neo4j.api.core.Node;
38  import org.neo4j.api.core.Relationship;
39  import org.neo4j.api.core.RelationshipType;
40  import org.neo4j.api.core.ReturnableEvaluator;
41  import org.neo4j.api.core.StopEvaluator;
42  import org.neo4j.api.core.Traverser.Order;
43  
44  import de.uni_leipzig.wifa.iwi.mr3.dao.Constants;
45  import de.uni_leipzig.wifa.iwi.mr3.dao.LoadProcessor;
46  import de.uni_leipzig.wifa.iwi.mr3.dao.neo4j.EcoreRelationshipType;
47  
48  /**
49   * Load processor for loading a model from nodespace.
50   */
51  public class LoadProcessorImpl implements LoadProcessor
52  {
53    /** Node {@link Comparator comparator}. */
54    private static final Comparator<Node> NODE_POSITION_COMPARATOR = new Comparator<Node>()
55    {
56      /**
57       * Compare method.
58       * <p>
59       * Code from <code>org.neo4j.api.core.NodeImpl.compare(..)</code> because
60       * {@link Node} isn't {@link Comparable}.
61       *
62       * @param first
63       *          First node
64       * @param second
65       *          Second node
66       * @return Comparison result
67       */
68      @Override
69      public int compare(final Node first, final Node second)
70      {
71        final long firstId = first.getId(), secondId = second.getId();
72  
73        if (firstId < secondId)
74        {
75          return -1;
76        }
77        else if (firstId > secondId)
78        {
79          return 1;
80        }
81        return 0;
82      }
83    };
84  
85    /**
86     * Iterable with node ordering.
87     * <p>
88     * Nodes are ordered acsending by their ID.
89     */
90    static class OrderedNodeIterable implements Iterable<Node>
91    {
92      private final Node node;
93      private final RelationshipType relType;
94      private final Direction direction;
95  
96      /**
97       * Constructor.
98       *
99       * @param node
100      *          Node
101      * @param direction
102      *          Direction
103      * @param relType
104      *          RelationshipType
105      */
106     public OrderedNodeIterable(final Node node, final RelationshipType relType, final Direction direction)
107     {
108       this.node = node;
109       this.relType = relType;
110       this.direction = direction;
111     }
112 
113     /**
114      * Create the {@link Iterator} over the internal collection nodes.
115      *
116      * @return Iterator
117      * @see java.lang.Iterable#iterator()
118      */
119     @Override
120     public Iterator<Node> iterator()
121     {
122       final Set<Node> nodes = new TreeSet<Node>(NODE_POSITION_COMPARATOR);
123       nodes.addAll(node.traverse(Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE, ReturnableEvaluator.ALL_BUT_START_NODE, relType,
124           direction).getAllNodes());
125       return nodes.iterator();
126     }
127   }
128 
129   /**
130    * Determine all the nodes with given {@link RelationshipType} and
131    * {@link Direction} and return an ordered {@link Iterable}.
132    * <p>
133    * Because of undefined ordering of traverser results, we order the nodes by
134    * its nodeId. So the Nodes comes back as they are created.
135    *
136    * @param node
137    *          Node
138    * @param relType
139    *          RelationshipTpe
140    * @param direction
141    *          Direction
142    * @return Sorted Iterable
143    */
144   private Iterable<Node> getOrderedNodes(final Node node, final RelationshipType relType, final Direction direction)
145   {
146     return new OrderedNodeIterable(node, relType, direction);
147   }
148 
149   /**
150    * Process.
151    * 
152    * @param node
153    *          Node to process
154    * @param registry
155    *          the registry for loaded objects
156    * @return EMF EObject
157    * @see de.uni_leipzig.wifa.iwi.mr3.dao.LoadProcessor#process(java.lang.Object)
158    */
159   public EObject process(final Object node, final Map<Object, EObject> registry)
160   {
161     if (null == node)
162     {
163       return null;
164     }
165 
166     if (((Node) node).hasRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING))
167     {
168       // load m2 (and m3) model
169       return getEPackage((Node) node, registry);
170     }
171     else
172     {
173       // load m1 model
174       return loadObject((Node) node, registry);
175     }
176   }
177 
178   /**
179    * Start node space traversing and build up model.
180    *
181    * @param node
182    *          the model node
183    * @param registry
184    *          Node cache
185    * @return the (EPackage) model
186    */
187   private EPackage getEPackage(final Node node, final Map<Object, EObject> registry)
188   {
189     final EPackage aPackage = EcoreFactory.eINSTANCE.createEPackage();
190 
191     // properties
192     aPackage.setName((String) node.getProperty(Constants.PROPERTY_NAME));
193     aPackage.setNsURI((String) node.getProperty(Constants.PROPERTY_NS_URI));
194     aPackage.setNsPrefix((String) node.getProperty(Constants.PROPERTY_NS_PREFIX));
195 
196     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
197     {
198       // omit EClass
199       if (aNode.hasProperty(Constants.PROPERTY_NAME)
200           && EClass.class.getSimpleName().equals(aNode.getProperty(Constants.PROPERTY_NAME)))
201       {
202         aPackage.getEClassifiers().add(getEClass(aNode, registry));
203         continue;
204       }
205 
206       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
207       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
208       {
209         aPackage.getEAnnotations().add(getEAnnotation(aNode));
210       }
211       else if (EClass.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
212       {
213         aPackage.getEClassifiers().add(getEClass(aNode, registry));
214       }
215       else if (EDataType.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
216       {
217         aPackage.getEClassifiers().add(getEDataType(aNode, registry));
218       }
219       else if (EEnum.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
220       {
221         aPackage.getEClassifiers().add(getEEnum(aNode, registry));
222       }
223       else if (EPackage.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
224       {
225         aPackage.getESubpackages().add(getEPackage(aNode, registry));
226       }
227     }
228     return aPackage;
229   }
230 
231   /**
232    * Determines a classifier from a node in the nodespace. If not found in
233    * registry, dispatches it to the concrete methods.
234    *
235    * @param node
236    *          the node
237    * @param registry
238    *          Node cache
239    * @return the classifier
240    */
241   private EClassifier getEClassifier(final Node node, final Map<Object, EObject> registry)
242   {
243     final EClassifier classifier = (EClassifier) registry.get(node);
244     if (null != classifier)
245     {
246       return classifier;
247     }
248 
249     // omit EClass: it has no incoming INSTANCE relationship
250     if (!node.hasRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING)
251         && EClass.class.getSimpleName().equals(node.getProperty(Constants.PROPERTY_NAME)))
252     {
253       return getEClass(node, registry);
254     }
255 
256     final Node metaNode = node.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
257     if (EClass.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
258     {
259       return getEClass(node, registry);
260     }
261     else if (EEnum.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
262     {
263       return getEEnum(node, registry);
264     }
265     else if (EDataType.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
266     {
267       return getEDataType(node, registry);
268     }
269     return null;
270   }
271 
272   /**
273    * Loads an EOperation from the given node.
274    *
275    * @param node
276    *          the node to load
277    * @param registry
278    *          Node cache
279    * @return the EOperation
280    */
281   private EOperation getEOperation(final Node node, final Map<Object, EObject> registry)
282   {
283     final EOperation operation = EcoreFactory.eINSTANCE.createEOperation();
284 
285     // properties
286     operation.setName((String) node.getProperty(Constants.PROPERTY_NAME));
287     operation.setOrdered((Boolean) node.getProperty(Constants.PROPERTY_ORDERED));
288     operation.setUnique((Boolean) node.getProperty(Constants.PROPERTY_UNIQUE));
289     operation.setLowerBound((Integer) node.getProperty(Constants.PROPERTY_LOWER_BOUND));
290     operation.setUpperBound((Integer) node.getProperty(Constants.PROPERTY_UPPER_BOUND));
291 
292     // relationships
293 
294     // exceptions
295     for (final Node eNode : getOrderedNodes(node, EcoreRelationshipType.EXCEPTION, Direction.OUTGOING))
296     {
297       operation.getEExceptions().add(getEClassifier(eNode, registry));
298     }
299 
300     // type
301     if (node.hasRelationship(EcoreRelationshipType.GENERIC_TYPE, Direction.OUTGOING))
302     {
303       final Node genericTypeNode =
304           node.getSingleRelationship(EcoreRelationshipType.GENERIC_TYPE, Direction.OUTGOING).getEndNode();
305       operation.setEGenericType(getEGenericType(genericTypeNode, registry));
306     }
307 
308     // CONTAINS relationships
309     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
310     {
311       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
312 
313       if (metaNode.getProperty(Constants.PROPERTY_NAME).equals(EAnnotation.class.getSimpleName()))
314       {
315         operation.getEAnnotations().add(getEAnnotation(aNode));
316       }
317       if (metaNode.getProperty(Constants.PROPERTY_NAME).equals(EParameter.class.getSimpleName()))
318       {
319         operation.getEParameters().add(getEParameter(aNode, registry));
320       }
321       if (metaNode.getProperty(Constants.PROPERTY_NAME).equals(ETypeParameter.class.getSimpleName()))
322       {
323         final ETypeParameter typeParameter = getETypeParameter(aNode, registry);
324         if (!operation.getETypeParameters().contains(typeParameter))
325         {
326           operation.getETypeParameters().add(typeParameter);
327         }
328       }
329 
330     }
331     return operation;
332   }
333 
334   /**
335    * Loads an EParameter from the given node.
336    *
337    * @param node
338    *          the node to load
339    * @param registry
340    *          Node cache
341    * @return the parameter
342    */
343   private EParameter getEParameter(final Node node, final Map<Object, EObject> registry)
344   {
345     final EParameter parameter = EcoreFactory.eINSTANCE.createEParameter();
346 
347     // properties
348     parameter.setName((String) node.getProperty(Constants.PROPERTY_NAME));
349     parameter.setOrdered((Boolean) node.getProperty(Constants.PROPERTY_ORDERED));
350     // many and required can not be set
351     parameter.setUnique((Boolean) node.getProperty(Constants.PROPERTY_UNIQUE));
352     parameter.setLowerBound((Integer) node.getProperty(Constants.PROPERTY_LOWER_BOUND));
353     parameter.setUpperBound((Integer) node.getProperty(Constants.PROPERTY_UPPER_BOUND));
354 
355     // relationships
356     // type
357     final Node genericTypeNode =
358         node.getSingleRelationship(EcoreRelationshipType.GENERIC_TYPE, Direction.OUTGOING).getEndNode();
359     parameter.setEGenericType(getEGenericType(genericTypeNode, registry));
360 
361     // CONTAINS relationship
362     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
363     {
364       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
365 
366       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
367       {
368         parameter.getEAnnotations().add(getEAnnotation(aNode));
369       }
370     }
371 
372     return parameter;
373   }
374 
375   /**
376    * Loads an EEnumLiteral from the given node.
377    *
378    * @param node
379    *          the node to load
380    * @return the EEnumLiteral
381    */
382   private EEnumLiteral getEEnumLiteral(final Node node)
383   {
384     final EEnumLiteral enumLiteral = EcoreFactory.eINSTANCE.createEEnumLiteral();
385 
386     // properties
387     enumLiteral.setName((String) node.getProperty(Constants.PROPERTY_NAME));
388     enumLiteral.setLiteral((String) node.getProperty(Constants.PROPERTY_LITERAL));
389     enumLiteral.setValue((Integer) node.getProperty(Constants.PROPERTY_VALUE));
390 
391     // CONTAINS relationship
392     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
393     {
394       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
395 
396       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
397       {
398         enumLiteral.getEAnnotations().add(getEAnnotation(aNode));
399       }
400     }
401 
402     return enumLiteral;
403   }
404 
405   /**
406    * Loads an EAnnotation from the given node.
407    *
408    * @param node
409    *          the node to load
410    * @return the EAnnotation
411    */
412   private EAnnotation getEAnnotation(final Node node)
413   {
414     final EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
415 
416     // properties
417     annotation.setSource((String) node.getProperty(Constants.PROPERTY_SOURCE));
418 
419     // relationships: entries
420     final EMap<String, String> entries = annotation.getDetails();
421     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
422     {
423       final String key =
424           aNode.hasProperty(Constants.PROPERTY_KEY_IS_NULL) ? null : (String) aNode.getProperty(Constants.PROPERTY_KEY);
425       final String val =
426           aNode.hasProperty(Constants.PROPERTY_VALUE_IS_NULL) ? null : (String) aNode.getProperty(Constants.PROPERTY_VALUE);
427 
428       entries.put(key, val);
429     }
430     return annotation;
431   }
432 
433   /**
434    * Determines an EGenericType from a node in nodespace.
435    *
436    * @param node
437    *          the node
438    * @param registry
439    *          Node cache
440    * @return the EGenericType
441    */
442   private EGenericType getEGenericType(final Node node, final Map<Object, EObject> registry)
443   {
444     if (null != registry.get(node))
445     {
446       return (EGenericType) registry.get(node);
447     }
448 
449     final EGenericType genericType = EcoreFactory.eINSTANCE.createEGenericType();
450 
451     if (node.hasRelationship(EcoreRelationshipType.TYPE, Direction.OUTGOING))
452     {
453       // determine top level package node of the classifier
454       final Node classifierNode = node.getSingleRelationship(EcoreRelationshipType.TYPE, Direction.OUTGOING).getEndNode();
455       final EClassifier classifier = getEClassifier(classifierNode, registry);
456       genericType.setEClassifier(classifier);
457     }
458     // get all available type arguments
459     for (final Node typeArgumentNode : getOrderedNodes(node, EcoreRelationshipType.GENERIC_TYPE_ARGUMENT, Direction.OUTGOING))
460     {
461       genericType.getETypeArguments().add(getEGenericType(typeArgumentNode, registry));
462     }
463 
464     registry.put(node, genericType);
465 
466     return genericType;
467   }
468 
469   /**
470    * Determines an ETypeParameter from a node in nodespace.
471    *
472    * @param node
473    *          the node
474    * @param registry
475    *          Node cache
476    * @return the ETypeParameter
477    */
478   private ETypeParameter getETypeParameter(final Node node, final Map<Object, EObject> registry)
479   {
480     final ETypeParameter typeParameter = EcoreFactory.eINSTANCE.createETypeParameter();
481 
482     // properties
483     typeParameter.setName((String) node.getProperty(Constants.PROPERTY_NAME));
484 
485     // CONTAINS relationship
486     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
487     {
488       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
489 
490       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
491       {
492         typeParameter.getEAnnotations().add(getEAnnotation(aNode));
493       }
494     }
495 
496     registry.put(node, typeParameter);
497 
498     return typeParameter;
499   }
500 
501   /**
502    * Determines an EDatatype from a node in the nodespace.
503    *
504    * @param node
505    *          the node
506    * @param registry
507    *          Node cache
508    * @return the EDataType
509    */
510   private EDataType getEDataType(final Node node, final Map<Object, EObject> registry)
511   {
512     if (null != registry.get(node))
513     {
514       return (EDataType) registry.get(node);
515     }
516 
517     final EDataType newDatatype = EcoreFactory.eINSTANCE.createEDataType();
518 
519     // properties
520     newDatatype.setName((String) node.getProperty(Constants.PROPERTY_NAME));
521 
522     if (node.hasProperty(Constants.PROPERTY_SERIALIZABLE))
523     {
524       newDatatype.setSerializable((Boolean) node.getProperty(Constants.PROPERTY_SERIALIZABLE));
525     }
526     if (node.hasProperty(Constants.PROPERTY_INSTANCE_TYPE_NAME))
527     {
528       newDatatype.setInstanceTypeName((String) node.getProperty(Constants.PROPERTY_INSTANCE_TYPE_NAME));
529     }
530 
531     // relationships
532     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
533     {
534       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
535 
536       if (ETypeParameter.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
537       {
538         final ETypeParameter typeParameter = getETypeParameter(aNode, registry);
539         if (!newDatatype.getETypeParameters().contains(typeParameter))
540         {
541           newDatatype.getETypeParameters().add(typeParameter);
542         }
543       }
544       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
545       {
546         newDatatype.getEAnnotations().add(getEAnnotation(aNode));
547       }
548     }
549 
550     registry.put(node, newDatatype);
551     return newDatatype;
552   }
553 
554   /**
555    * Determines an EEnum from a node in the nodespace.
556    *
557    * @param node
558    *          the node
559    * @param registry
560    *          Node cache
561    * @return the EEnum
562    */
563   private EEnum getEEnum(final Node node, final Map<Object, EObject> registry)
564   {
565     if (null != registry.get(node))
566     {
567       return (EEnum) registry.get(node);
568     }
569 
570     final EEnum anEnum = EcoreFactory.eINSTANCE.createEEnum();
571 
572     registry.put(node, anEnum);
573 
574     // properties
575     anEnum.setName((String) node.getProperty(Constants.PROPERTY_NAME));
576 
577     if (node.hasProperty(Constants.PROPERTY_SERIALIZABLE))
578     {
579       anEnum.setSerializable((Boolean) node.getProperty(Constants.PROPERTY_SERIALIZABLE));
580     }
581 
582     if (node.hasProperty(Constants.PROPERTY_INSTANCE_TYPE_NAME))
583     {
584       anEnum.setInstanceTypeName((String) node.getProperty(Constants.PROPERTY_INSTANCE_TYPE_NAME));
585     }
586 
587     // relationships
588     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
589     {
590       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
591 
592       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
593       {
594         anEnum.getEAnnotations().add(getEAnnotation(aNode));
595       }
596       if (EEnumLiteral.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
597       {
598         anEnum.getELiterals().add(getEEnumLiteral(aNode));
599       }
600     }
601 
602     return anEnum;
603   }
604 
605   /**
606    * Determines an EClass from a node in the nodespace.
607    *
608    * @param node
609    *          the node
610    * @param registry
611    *          Node cache
612    * @return the EClass
613    */
614   private EClass getEClass(final Node node, final Map<Object, EObject> registry)
615   {
616     if (null != registry.get(node))
617     {
618       return (EClass) registry.get(node);
619     }
620 
621     final EClass aClass = EcoreFactory.eINSTANCE.createEClass();
622 
623     registry.put(node, aClass);
624 
625     // properties
626     aClass.setName((String) node.getProperty(Constants.PROPERTY_NAME));
627 
628     if (node.hasProperty(Constants.PROPERTY_INSTANCE_TYPE_NAME))
629     {
630       aClass.setInstanceTypeName((String) node.getProperty(Constants.PROPERTY_INSTANCE_TYPE_NAME));
631     }
632 
633     aClass.setAbstract((Boolean) node.getProperty(Constants.PROPERTY_INTERFACE));
634     aClass.setAbstract((Boolean) node.getProperty(Constants.PROPERTY_ABSTRACT));
635 
636     // relationships
637     // supertypes
638     if (node.hasRelationship(EcoreRelationshipType.SUPER, Direction.OUTGOING))
639     {
640       for (final Node superNode : getOrderedNodes(node, EcoreRelationshipType.SUPER, Direction.OUTGOING))
641       {
642         final EClass superType = (EClass) getEClassifier(superNode, registry);
643         if (superType != null)
644         {
645           aClass.getESuperTypes().add(superType);
646         }
647       }
648     }
649 
650     // CONTAINS relationship
651     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
652     {
653       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
654 
655       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
656       {
657         aClass.getEAnnotations().add(getEAnnotation(aNode));
658       }
659       if (EAttribute.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
660       {
661         aClass.getEStructuralFeatures().add(getEAttribute(aNode, registry));
662       }
663       if (EReference.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
664       {
665         aClass.getEStructuralFeatures().add(getEReference(aNode, registry));
666       }
667       if (EOperation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
668       {
669         aClass.getEOperations().add(getEOperation(aNode, registry));
670       }
671       if (ETypeParameter.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
672       {
673         final ETypeParameter typeParameter = getETypeParameter(aNode, registry);
674         if (!aClass.getETypeParameters().contains(typeParameter))
675         {
676           aClass.getETypeParameters().add(typeParameter);
677         }
678       }
679     }
680 
681     return aClass;
682   }
683 
684   /**
685    * Determines an EReference from a node in the nodespace.
686    *
687    * @param node
688    *          the node
689    * @param registry
690    *          Node cache
691    * @return the EReference
692    */
693   private EReference getEReference(final Node node, final Map<Object, EObject> registry)
694   {
695     if (null != registry.get(node))
696     {
697       return (EReference) registry.get(node);
698     }
699 
700     final EReference reference = EcoreFactory.eINSTANCE.createEReference();
701 
702     registry.put(node, reference);
703 
704     // properties
705     reference.setChangeable((Boolean) node.getProperty(Constants.PROPERTY_CHANGEABLE));
706     // container is set automatically
707     reference.setContainment((Boolean) node.getProperty(Constants.PROPERTY_CONTAINMENT));
708     reference.setDerived((Boolean) node.getProperty(Constants.PROPERTY_DERIVED));
709     reference.setLowerBound((Integer) node.getProperty(Constants.PROPERTY_LOWER_BOUND));
710     reference.setName((String) node.getProperty(Constants.PROPERTY_NAME));
711     reference.setOrdered((Boolean) node.getProperty(Constants.PROPERTY_ORDERED));
712     reference.setResolveProxies((Boolean) node.getProperty(Constants.PROPERTY_RESOLVE_PROXIES));
713     reference.setTransient((Boolean) node.getProperty(Constants.PROPERTY_TRANSIENT));
714     reference.setUnique((Boolean) node.getProperty(Constants.PROPERTY_UNIQUE));
715     reference.setUnsettable((Boolean) node.getProperty(Constants.PROPERTY_UNSETTABLE));
716     reference.setUpperBound((Integer) node.getProperty(Constants.PROPERTY_UPPER_BOUND));
717     reference.setVolatile((Boolean) node.getProperty(Constants.PROPERTY_VOLATILE));
718 
719     if (node.hasProperty(Constants.PROPERTY_DEFAULT_VALUE_LITERAL))
720     {
721       reference.setDefaultValueLiteral((String) node.getProperty(Constants.PROPERTY_DEFAULT_VALUE_LITERAL));
722     }
723     // relationships
724     // type
725     final Node genericTypeNode =
726         node.getSingleRelationship(EcoreRelationshipType.GENERIC_TYPE, Direction.OUTGOING).getEndNode();
727     reference.setEGenericType(getEGenericType(genericTypeNode, registry));
728 
729     // keys
730     for (final Node keyNode : getOrderedNodes(node, EcoreRelationshipType.E_KEY, Direction.OUTGOING))
731     {
732       reference.getEKeys().add(getEAttribute(keyNode, registry));
733     }
734 
735     // opposite
736     final Relationship oppositeRelationship = node.getSingleRelationship(EcoreRelationshipType.OPPOSITE, Direction.OUTGOING);
737     if (null != oppositeRelationship)
738     {
739       reference.setEOpposite(getEReference(oppositeRelationship.getEndNode(), registry));
740       getEReference(oppositeRelationship.getEndNode(), registry).setEOpposite(reference);
741     }
742 
743     // CONTAINS relationship
744     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
745     {
746       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
747 
748       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
749       {
750         reference.getEAnnotations().add(getEAnnotation(aNode));
751       }
752     }
753 
754     return reference;
755   }
756 
757   /**
758    * Determines an EAttribute from a node in the nodespace.
759    *
760    * @param node
761    *          the node
762    * @param registry
763    *          Node cache
764    * @return the EAttribute
765    */
766   private EAttribute getEAttribute(final Node node, final Map<Object, EObject> registry)
767   {
768     if (null != registry.get(node))
769     {
770       return (EAttribute) registry.get(node);
771     }
772 
773     final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute();
774 
775     registry.put(node, attribute);
776 
777     // properties
778     attribute.setChangeable((Boolean) node.getProperty(Constants.PROPERTY_CHANGEABLE));
779     // container is set automatically
780     attribute.setDerived((Boolean) node.getProperty(Constants.PROPERTY_DERIVED));
781     attribute.setID((Boolean) node.getProperty(Constants.PROPERTY_ID));
782     attribute.setLowerBound((Integer) node.getProperty(Constants.PROPERTY_LOWER_BOUND));
783     attribute.setName((String) node.getProperty(Constants.PROPERTY_NAME));
784     attribute.setOrdered((Boolean) node.getProperty(Constants.PROPERTY_ORDERED));
785     attribute.setTransient((Boolean) node.getProperty(Constants.PROPERTY_TRANSIENT));
786     attribute.setUnique((Boolean) node.getProperty(Constants.PROPERTY_UNIQUE));
787     attribute.setUnsettable((Boolean) node.getProperty(Constants.PROPERTY_UNSETTABLE));
788     attribute.setUpperBound((Integer) node.getProperty(Constants.PROPERTY_UPPER_BOUND));
789     attribute.setVolatile((Boolean) node.getProperty(Constants.PROPERTY_VOLATILE));
790 
791     if (node.hasProperty(Constants.PROPERTY_DEFAULT_VALUE_LITERAL))
792     {
793       attribute.setDefaultValueLiteral((String) node.getProperty(Constants.PROPERTY_DEFAULT_VALUE_LITERAL));
794     }
795     // relationships
796     // type
797     final Node genericTypeNode =
798         node.getSingleRelationship(EcoreRelationshipType.GENERIC_TYPE, Direction.OUTGOING).getEndNode();
799     attribute.setEGenericType(getEGenericType(genericTypeNode, registry));
800 
801     // attribute type is set automatically
802 
803     // CONTAINS relationship
804     for (final Node aNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
805     {
806       final Node metaNode = aNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
807 
808       if (EAnnotation.class.getSimpleName().equals(metaNode.getProperty(Constants.PROPERTY_NAME)))
809       {
810         attribute.getEAnnotations().add(getEAnnotation(aNode));
811       }
812     }
813 
814     return attribute;
815   }
816 
817   /**
818    * Loads an EObject (m1 model) from the given node in nodespace.
819    * 
820    * @param modelNode
821    *          the model node
822    * @param registry
823    *          Node cache
824    * @return the model to load
825    */
826   private EObject loadObject(final Node modelNode, final Map<Object, EObject> registry)
827   {
828     final Node objectNode = modelNode.getSingleRelationship(EcoreRelationshipType.CONTAINS, Direction.OUTGOING).getEndNode();
829 
830     // determine an EObject
831     return getEObject(objectNode, registry);
832   }
833 
834   /**
835    * Determines an EObject from a node in nodespace.
836    *
837    * @param node
838    *          the node
839    * @param registry
840    *          Node cache
841    * @return the EObject
842    */
843   private EObject getEObject(final Node node, final Map<Object, EObject> registry)
844   {
845     if (null != registry.get(node))
846     {
847       return registry.get(node);
848     }
849 
850     // get the meta EClass node
851     final Node classNode = node.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
852     final String className = (String) classNode.getProperty(Constants.PROPERTY_NAME);
853 
854     // get the meta (sub-)package node
855     final Node packageNode = classNode.getSingleRelationship(EcoreRelationshipType.CONTAINS, Direction.INCOMING).getStartNode();
856 
857     // dynamically create the EObject
858     final EPackage modelPackage = getEPackage(packageNode, registry);
859     final EClass eClass = (EClass) modelPackage.getEClassifier(className);
860     final EFactory factory = modelPackage.getEFactoryInstance();
861     final EObject object = factory.create(eClass);
862 
863     registry.put(node, object);
864 
865     // set structural features
866     for (final Node featureNode : getOrderedNodes(node, EcoreRelationshipType.CONTAINS, Direction.OUTGOING))
867     {
868       // find out if the saved feature is a reference or a containment reference
869       // or an attribute
870       final boolean hasRef = featureNode.hasRelationship(EcoreRelationshipType.REFERENCES, Direction.OUTGOING);
871       final boolean hasRefCont =
872           featureNode.hasRelationship(EcoreRelationshipType.REFERENCES_AS_CONTAINMENT, Direction.OUTGOING);
873       final EcoreRelationshipType relType =
874           hasRef ? EcoreRelationshipType.REFERENCES : hasRefCont ? EcoreRelationshipType.REFERENCES_AS_CONTAINMENT : null;
875       if (null == relType)
876       {
877         // set attribute and its values
878         final Node metaNode =
879             featureNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
880         final EAttribute attribute = getEAttribute(metaNode, registry);
881         if (attribute.isMany())
882         {
883           @SuppressWarnings("unchecked")
884           final List<Object> attributes = (List<Object>) object.eGet(attribute);
885           attributes.add(featureNode.getProperty(Constants.PROPERTY_VALUE));
886         }
887         else
888         {
889           object.eSet(attribute, featureNode.getProperty(Constants.PROPERTY_VALUE));
890         }
891       }
892       else
893       {
894         // set reference
895         final Node metaNode =
896             featureNode.getSingleRelationship(EcoreRelationshipType.INSTANCE, Direction.INCOMING).getStartNode();
897         final EReference reference = getEReference(metaNode, registry);
898         if (reference.isMany())
899         {
900           @SuppressWarnings("unchecked")
901           final List<Object> references = (List<Object>) object.eGet(reference);
902           references.add(getEObject(featureNode.getSingleRelationship(relType, Direction.OUTGOING).getEndNode(), registry));
903         }
904         else
905         {
906           object.eSet(reference, getEObject(featureNode.getSingleRelationship(relType, Direction.OUTGOING).getEndNode(),
907               registry));
908         }
909       }
910     }
911     return object;
912   }
913 }