PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/src/groove/io/ecore2groove/InstanceGraphRep.java

https://bitbucket.org/wthys/groove
Java | 352 lines | 201 code | 46 blank | 105 comment | 43 complexity | 358d4f9038e9ada5f8bd95ff67415911 MD5 | raw file
  1. /*
  2. * GROOVE: GRaphs for Object Oriented VErification Copyright 2003--2007
  3. * University of Twente
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  6. * use this file except in compliance with the License. You may obtain a copy of
  7. * the License at http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. * License for the specific language governing permissions and limitations under
  13. * the License.
  14. *
  15. * $Id$
  16. */
  17. package groove.io.ecore2groove;
  18. import static groove.graph.GraphRole.HOST;
  19. import groove.graph.EdgeRole;
  20. import groove.graph.plain.PlainGraph;
  21. import groove.graph.plain.PlainLabel;
  22. import groove.graph.plain.PlainNode;
  23. import java.util.HashMap;
  24. import java.util.HashSet;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import java.util.Stack;
  28. import java.util.Vector;
  29. import org.eclipse.emf.common.util.EList;
  30. import org.eclipse.emf.ecore.EAttribute;
  31. import org.eclipse.emf.ecore.EDataType;
  32. import org.eclipse.emf.ecore.EObject;
  33. import org.eclipse.emf.ecore.EReference;
  34. import org.eclipse.emf.ecore.EStructuralFeature;
  35. /**
  36. * Given a ModelHandler with an Ecore metamodel and also an instance model
  37. * loaded, this class generates the graph representation of the instance
  38. * model.
  39. * @author Stefan Teijgeler
  40. */
  41. public class InstanceGraphRep {
  42. private final ModelHandler mh;
  43. private final PlainGraph ig;
  44. private Map<EObject,PlainNode> iClassToNodeMap =
  45. new HashMap<EObject,PlainNode>();
  46. private Map<Triple<EObject,EStructuralFeature,EObject>,Stack<PlainNode>> iReferenceToNodeMap =
  47. new HashMap<Triple<EObject,EStructuralFeature,EObject>,Stack<PlainNode>>();
  48. private Set<EObject> iClassReferencesDone = new HashSet<EObject>();
  49. /**
  50. * Constructor method, given a ModelHandler with an Ecore metamodel and
  51. * instance model loaded, creates an instance graph representation.
  52. * @param name name of the instance graph
  53. * @param m the ModelHandler
  54. */
  55. public InstanceGraphRep(String name, ModelHandler m) {
  56. this.mh = m;
  57. this.ig = new PlainGraph(name);
  58. this.ig.setRole(HOST);
  59. // First add instances of of classes to graph, then features
  60. addClasses(this.mh.getiClasses());
  61. addStructuralFeatures(this.mh.getiClasses());
  62. }
  63. /**
  64. * Add all representations for all EClass instances in the vector to
  65. * the instance graph.
  66. * @param iClasses the instances of EClasses
  67. */
  68. private void addClasses(Vector<EObject> iClasses) {
  69. for (EObject iClass : iClasses) {
  70. // Add new labeled node to ig
  71. String labelText = GraphLabels.getLabel(iClass.eClass());
  72. PlainNode node = this.ig.addNode();
  73. this.ig.addEdge(node, labelText, node);
  74. // If this instance EClass is the root element, add the root flag
  75. if (iClass.eContainingFeature() == null) {
  76. this.ig.addEdge(node, "flag:root", node);
  77. }
  78. // Add map of EClass to node representing it
  79. this.iClassToNodeMap.put(iClass, node);
  80. }
  81. }
  82. /**
  83. * Add representations for features to the instance graph for all the
  84. * instances of EClasses of the instance model.
  85. * @param iClasses the instances of EClasses
  86. * @require EClass instances must have been added to the graph
  87. * representation already
  88. */
  89. @SuppressWarnings("unchecked")
  90. private void addStructuralFeatures(Vector<EObject> iClasses) {
  91. for (EObject iClass : iClasses) {
  92. for (EStructuralFeature feature : iClass.eClass().getEAllStructuralFeatures()) {
  93. if (feature.eClass().getName().equals("EReference")) {
  94. if (iClass.eGet(feature) != null) {
  95. // When there are multiple values of a feature,
  96. // an EcoreEList contains them
  97. if (feature.isMany()) {
  98. EList<EObject> targets =
  99. (EList<EObject>) iClass.eGet(feature, true);
  100. boolean ordered = feature.isOrdered();
  101. PlainNode previous = null;
  102. PlainNode last = null;
  103. for (EObject target : targets) {
  104. // only add reference if target exists, not
  105. // exist at this point can happen with factory
  106. if (this.iClassToNodeMap.containsKey(target)) {
  107. // Add node representing the EReference to ig
  108. last =
  109. addReference(iClass, feature, target);
  110. addOpposite(iClass, feature, target);
  111. // Add next edge if references are ordered
  112. if (ordered && previous != null) {
  113. this.ig.addEdge(previous, "next", last);
  114. }
  115. previous = last;
  116. }
  117. }
  118. // When not an EcoreEList and also not null,
  119. // then there is a single value which is an EObject
  120. } else {
  121. EObject target =
  122. (EObject) iClass.eGet(feature, true);
  123. // only add reference if target exists, not
  124. // exist at this point can happen with factory
  125. if (this.iClassToNodeMap.containsKey(target)) {
  126. addReference(iClass, feature, target);
  127. addOpposite(iClass, feature, target);
  128. }
  129. }
  130. }
  131. } else if (feature.eClass().getName().equals("EAttribute")) {
  132. if (iClass.eGet(feature) != null) {
  133. if (feature.isMany()) {
  134. EList<Object> targets =
  135. (EList<Object>) iClass.eGet(feature, true);
  136. boolean ordered = feature.isOrdered();
  137. PlainNode previous = null;
  138. PlainNode last = null;
  139. for (Object iTarget : targets) {
  140. // Add node representing the EReference
  141. last = addAttribute(iClass, feature, iTarget);
  142. // Add next edge if references are ordered
  143. if (ordered && previous != null) {
  144. PlainLabel label =
  145. PlainLabel.createLabel("next");
  146. this.ig.addEdge(previous, label, last);
  147. }
  148. previous = last;
  149. }
  150. } else {
  151. Object iTarget = iClass.eGet(feature, true);
  152. addAttribute(iClass, feature, iTarget);
  153. }
  154. }
  155. }
  156. }
  157. this.iClassReferencesDone.add(iClass);
  158. }
  159. }
  160. /**
  161. * Check if the EReference feature from iClass to target has an opposite
  162. * EReference from target to iClass. If so, add opposite edges between
  163. * the nodes that represent these EReference instances
  164. * @param iClass the source EClass instance of feature
  165. * @param feature the EReference
  166. * @param target the target EClass instance of feature
  167. * @require feature instanceof EReference, EClass instances must be
  168. * represented in the graph representation already
  169. */
  170. @SuppressWarnings("unchecked")
  171. private void addOpposite(EObject iClass, EStructuralFeature feature,
  172. EObject target) {
  173. EReference oppositeRef = ((EReference) feature).getEOpposite();
  174. if (oppositeRef != null) {
  175. if (oppositeRef.isMany()) {
  176. EList<EObject> opposites =
  177. (EList<EObject>) target.eGet(oppositeRef);
  178. for (EObject opposite : opposites) {
  179. if (opposite.equals(iClass)
  180. && this.iReferenceToNodeMap.containsKey(Triple.create(
  181. target, oppositeRef, opposite))
  182. && !this.iReferenceToNodeMap.get(
  183. Triple.create(target, oppositeRef, opposite)).isEmpty()) {
  184. Stack<PlainNode> nodeStack1 =
  185. this.iReferenceToNodeMap.get(Triple.create(
  186. opposite, feature, target));
  187. PlainNode node1 = nodeStack1.pop();
  188. Stack<PlainNode> nodeStack2 =
  189. this.iReferenceToNodeMap.get(Triple.create(target,
  190. oppositeRef, opposite));
  191. PlainNode node2 = nodeStack2.pop();
  192. this.ig.addEdge(node1, "opposite", node2);
  193. this.ig.addEdge(node2, "opposite", node1);
  194. }
  195. }
  196. } else {
  197. EObject opposite = ((EReference) feature).getEOpposite();
  198. if (opposite.equals(iClass)
  199. && this.iReferenceToNodeMap.containsKey(Triple.create(
  200. target, oppositeRef, opposite))
  201. && !this.iReferenceToNodeMap.get(
  202. Triple.create(target, oppositeRef, opposite)).isEmpty()) {
  203. Stack<PlainNode> nodeStack1 =
  204. this.iReferenceToNodeMap.get(Triple.create(opposite,
  205. feature, target));
  206. PlainNode node1 = nodeStack1.pop();
  207. Stack<PlainNode> nodeStack2 =
  208. this.iReferenceToNodeMap.get(Triple.create(target,
  209. oppositeRef, opposite));
  210. PlainNode node2 = nodeStack2.pop();
  211. this.ig.addEdge(node1, "opposite", node2);
  212. this.ig.addEdge(node2, "opposite", node1);
  213. }
  214. }
  215. }
  216. }
  217. /**
  218. * Adds a graph representation for an instance of the EAttribute feature
  219. * with a value of target. The EAttribute is a feature of source.
  220. * @param source the EClass instance
  221. * @param feature the EAttribute
  222. * @param target the value
  223. * @return The Node that was added to the instance graph
  224. * @require feature instanceof EAttribute, EClass instances must be
  225. * represented in the instance graph already.
  226. */
  227. private PlainNode addAttribute(EObject source,
  228. EStructuralFeature feature, Object target) {
  229. String attributeLabel = GraphLabels.getLabel(feature);
  230. EDataType attributeType = ((EAttribute) feature).getEAttributeType();
  231. String datatypeLabel = GraphLabels.getLabel(attributeType, target);
  232. // Create and add a node to represent the EAttribute itself
  233. PlainNode attributeNode = this.ig.addNode();
  234. this.ig.addEdge(attributeNode, attributeLabel, attributeNode);
  235. // Create and add an edge from the container EClass to the EAttribute
  236. PlainNode sourceNode = this.iClassToNodeMap.get(source);
  237. this.ig.addEdge(sourceNode, feature.getName(), attributeNode);
  238. if (!datatypeLabel.isEmpty()) {
  239. // Create and add a node to represent that datatype value
  240. PlainNode datatypeNode = this.ig.addNode();
  241. this.ig.addEdge(datatypeNode, datatypeLabel, datatypeNode);
  242. // Create and add a val edge to the value
  243. this.ig.addEdge(attributeNode, "val", datatypeNode);
  244. // When the value is an EEnum, the flag for the value needs to be
  245. // added as well
  246. if (attributeType.eClass().getName().equals("EEnum")) {
  247. String flagLabel =
  248. EdgeRole.FLAG.getPrefix() + target.toString();
  249. this.ig.addEdge(datatypeNode, flagLabel, datatypeNode);
  250. }
  251. }
  252. return attributeNode;
  253. }
  254. /**
  255. * Adds a graph representation for an instance of an EReference from source
  256. * to target, which must both be EClass instances.
  257. * @param source the source EClass instance
  258. * @param feature the EReference
  259. * @param target the target EClas instance
  260. * @return the Node that was added to the instance graph
  261. * @require feature instanceof EReference, EClass instances must be
  262. * represented in the instance graph already, source and target must be
  263. * EClass instances.
  264. */
  265. private PlainNode addReference(EObject source,
  266. EStructuralFeature feature, EObject target) {
  267. String labelText = GraphLabels.getLabel(feature);
  268. // Create node to represent the reference and add it to ig
  269. PlainNode node = this.ig.addNode();
  270. this.ig.addEdge(node, labelText, node);
  271. // If the reference is a containment reference, add flag:containment
  272. if (((EReference) feature).isContainment()) {
  273. PlainLabel contLabel =
  274. PlainLabel.createLabel("flag:containment");
  275. this.ig.addEdge(node, contLabel, node);
  276. }
  277. // Create and add an edge from the source of the EReference to the
  278. // EReference node
  279. PlainNode sourceNode = this.iClassToNodeMap.get(source);
  280. this.ig.addEdge(sourceNode, feature.getName(), node);
  281. // Create and add an edge from the EReference node to the target of the
  282. // EReference
  283. PlainNode targetNode = this.iClassToNodeMap.get(target);
  284. this.ig.addEdge(node, "val", targetNode);
  285. // Either add the node to the set of nodes that represent the
  286. // iReference, or add a new set to the map
  287. Stack<PlainNode> nodeStack =
  288. this.iReferenceToNodeMap.get(Triple.create(source, feature, target));
  289. if (nodeStack != null) {
  290. nodeStack.push(node);
  291. } else {
  292. nodeStack = new Stack<PlainNode>();
  293. nodeStack.push(node);
  294. this.iReferenceToNodeMap.put(
  295. Triple.create(source, feature, target), nodeStack);
  296. }
  297. return node;
  298. }
  299. /**
  300. * Get method for the graph that represents the instance model
  301. * @return the instance graph
  302. */
  303. public PlainGraph getInstanceGraph() {
  304. return this.ig;
  305. }
  306. }