View Javadoc
1   package org.andromda.metafacades.emf.uml22;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.Iterator;
7   import java.util.List;
8   import org.andromda.core.common.ExceptionUtils;
9   import org.andromda.core.configuration.Filters;
10  import org.andromda.core.metafacade.MetafacadeBase;
11  import org.andromda.core.metafacade.MetafacadeConstants;
12  import org.andromda.core.metafacade.MetafacadeFactory;
13  import org.andromda.core.metafacade.ModelAccessFacade;
14  import org.andromda.metafacades.uml.EntityMetafacadeUtils;
15  import org.andromda.metafacades.uml.ModelElementFacade;
16  import org.andromda.metafacades.uml.PackageFacade;
17  import org.apache.commons.collections.CollectionUtils;
18  import org.apache.commons.collections.Predicate;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.log4j.Logger;
21  import org.eclipse.emf.common.util.TreeIterator;
22  import org.eclipse.emf.ecore.EObject;
23  import org.eclipse.uml2.uml.Element;
24  import org.eclipse.uml2.uml.NamedElement;
25  import org.eclipse.uml2.uml.Package;
26  import org.eclipse.uml2.uml.resource.UMLResource;
27  
28  /**
29   * Model access facade implementation for the EMF/UML2 metafacades
30   *
31   * @author Steve Jerman
32   * @author Chad Brandon
33   * @author Bob Fields (Multiple model support)
34   */
35  public class UMLModelAccessFacade
36      implements ModelAccessFacade
37  {
38      /**
39       * The logger instance.
40       */
41      private static final Logger LOGGER = Logger.getLogger(UMLModelAccessFacade.class);
42  
43      /**
44       * Protected to improve performance.
45       */
46      protected Filters modelPackages = new Filters();
47  
48      private static final String MODEL_ELEMENT = "modelElement";
49      /**
50       * @see org.andromda.core.metafacade.ModelAccessFacade#setModel(Object)
51       */
52      public void setModel(final Object modelIn)
53      {
54          ExceptionUtils.checkNull(
55              "model",
56              modelIn);
57          ExceptionUtils.checkAssignable(
58              List.class,
59              UMLModelAccessFacade.MODEL_ELEMENT,
60              modelIn.getClass());
61          // TODO Find models that are already in the models list, don't clear, remove the rest.
62          if (this.model!=null)
63          {
64              // Always clear out models from any previous andromda run
65              this.model.clear(); // Ensure garbage collection of referenced resources
66          }
67          this.model = new ArrayList<UMLResource>();
68          for (UMLResource modelResource : (ArrayList<UMLResource>)modelIn)
69          {
70              if (!this.model.contains(modelResource))
71              {
72                  this.model.add(modelResource);
73              }
74          }
75          // TODO: - clear the meta objects cache (yes this is a performance
76          //       hack that at some point should be improved).
77          UmlUtilities.clearAllMetaObjectsCache();
78          // TODO: - clears out the foreign key cache (again probably not
79          //         the cleanest way, but the easiest at this point).
80          EntityMetafacadeUtils.clearForeignKeyConstraintNameCache();
81      }
82  
83      /**
84       * @see org.andromda.core.metafacade.ModelAccessFacade#getModel()
85       */
86      public Object getModel()
87      {
88          return this.model;
89      }
90  
91      /**
92       * @see org.andromda.core.metafacade.ModelAccessFacade#getName(Object)
93       */
94      public String getName(final Object modelElement)
95      {
96          ExceptionUtils.checkNull(
97              UMLModelAccessFacade.MODEL_ELEMENT,
98              modelElement);
99          ExceptionUtils.checkAssignable(
100             ModelElementFacade.class,
101             UMLModelAccessFacade.MODEL_ELEMENT,
102             modelElement.getClass());
103         return ((ModelElementFacade)modelElement).getName();
104     }
105 
106     /**
107      * @see org.andromda.core.metafacade.ModelAccessFacade#getPackageName(Object)
108      */
109     public String getPackageName(final Object modelElement)
110     {
111         ExceptionUtils.checkNull(
112             UMLModelAccessFacade.MODEL_ELEMENT,
113             modelElement);
114         ExceptionUtils.checkAssignable(
115             ModelElementFacade.class,
116             UMLModelAccessFacade.MODEL_ELEMENT,
117             modelElement.getClass());
118         final ModelElementFacade modelElementFacade = (ModelElementFacade)modelElement;
119         final StringBuilder packageName = new StringBuilder(modelElementFacade.getPackageName(true));
120 
121         // - if the model element is a package then the package name will be the
122         // name of the package with its package name
123         if (modelElement instanceof PackageFacade)
124         {
125             final String name = modelElementFacade.getName();
126             if (StringUtils.isNotBlank(name))
127             {
128                 packageName.append(MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
129                 packageName.append(name);
130             }
131         }
132         return packageName.toString();
133     }
134 
135     /**
136      * The actual underlying model instance.
137      */
138     private List<UMLResource> model;
139 
140     /**
141      * @see org.andromda.core.metafacade.ModelAccessFacade#setPackageFilter(org.andromda.core.configuration.Filters)
142      */
143     public void setPackageFilter(final Filters modelPackagesIn)
144     {
145         this.modelPackages = modelPackagesIn;
146     }
147 
148     /**
149      * @see org.andromda.core.metafacade.ModelAccessFacade#getStereotypeNames(Object)
150      */
151     public Collection<String> getStereotypeNames(final Object modelElement)
152     {
153         ExceptionUtils.checkNull(
154             UMLModelAccessFacade.MODEL_ELEMENT,
155             modelElement);
156 
157         Collection<String> stereotypeNames = Collections.emptyList();
158         if (modelElement instanceof Element)
159         {
160             final Element element = (Element)modelElement;
161             stereotypeNames = UmlUtilities.getStereotypeNames(element);
162         }
163         else if (modelElement instanceof ModelElementFacade)
164         {
165             stereotypeNames = ((ModelElementFacade)modelElement).getStereotypeNames();
166         }
167         return stereotypeNames;
168     }
169 
170     /**
171      * @see org.andromda.core.metafacade.ModelAccessFacade#findByStereotype(String)
172      */
173     public Collection<MetafacadeBase> findByStereotype(final String name)
174     {
175         final List<NamedElement> elements = new ArrayList<NamedElement>();
176         for (final UMLResource modelResource : this.model)
177         {
178             // TODO UmlUtilities.findModel() can return null. Check for null return value.
179             for (final TreeIterator<EObject> iterator = UmlUtilities.findModel(modelResource).eAllContents(); iterator.hasNext();)
180             {
181                 final EObject object = iterator.next();
182                 if (object instanceof NamedElement)
183                 {
184                     final NamedElement element = (NamedElement)object;
185                     if (UmlUtilities.containsStereotype(
186                             element,
187                             name))
188                     {
189                         elements.add(element);
190                     }
191                 }
192             }
193         }
194         final int elementSize = elements.size();
195         if (LOGGER.isDebugEnabled())
196         {
197             LOGGER.debug("Finding stereotype <<" + name + ">> in elements " +
198                 elements.size());
199         }
200         // - filter any elements before we turn them into metafacades (for performance reasons)
201         this.filterElements(elements);
202         if (LOGGER.isDebugEnabled() && elements.size()<elementSize)
203         {
204             LOGGER.debug("Filtered out " + (elementSize-elements.size()) + " elements");
205         }
206         return MetafacadeFactory.getInstance().createMetafacades(elements);
207     }
208 
209     /**
210      * @see org.andromda.core.metafacade.ModelAccessFacade#getModelElements()
211      */
212     public Collection<MetafacadeBase> getModelElements()
213     {
214         final List<NamedElement> elements = new ArrayList<NamedElement>();
215 
216         for (UMLResource modelResource : this.model)
217         {
218             // TODO UmlUtilities.findModel() can return null. Check for null return value.
219             for (final Iterator<EObject> iterator = UmlUtilities.findModel(modelResource).eAllContents(); iterator.hasNext();)
220             {
221                 final EObject object = iterator.next();
222                 if (object instanceof NamedElement)
223                 {
224                     elements.add((NamedElement) object);
225                 }
226             }
227         }
228 
229         // - filter any elements before we turn them into metafacades (for performance reasons)
230         this.filterElements(elements);
231 
232         // Don't forget to transform properties
233         CollectionUtils.transform(
234             elements,
235             UmlUtilities.ELEMENT_TRANSFORMER);
236 
237         final Collection<MetafacadeBase> metafacades;
238 
239         if (elements.isEmpty())
240         {
241             metafacades = new ArrayList<MetafacadeBase>();
242         }
243         else
244         {
245             metafacades = MetafacadeFactory.getInstance().createMetafacades(elements);
246         }
247 
248         return metafacades;
249     }
250 
251     /**
252      * Filters out those metafacades which <strong>should</strong> be
253      * processed.
254      *
255      * @param metafacades the Collection of metafacades.
256      */
257     private void filterElements(final Collection<NamedElement> metafacades)
258     {
259         if (this.modelPackages != null && !this.modelPackages.isEmpty())
260         {
261             CollectionUtils.filter(
262                 metafacades,
263                 new Predicate()
264                 {
265                     public boolean evaluate(final Object element)
266                     {
267                         boolean valid = false;
268                         if (element instanceof NamedElement)
269                         {
270                             final NamedElement modelElement = (NamedElement)element;
271                             final StringBuilder packageName =
272                                 new StringBuilder(
273                                     UmlUtilities.getPackageName(
274                                         modelElement,
275                                         MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR,
276                                         true));
277 
278                             // - if the model element is a package then the package name will be the name
279                             // of the package with its package name
280                             if (element instanceof Package)
281                             {
282                                 final String name = modelElement.getName();
283                                 if (StringUtils.isNotBlank(name))
284                                 {
285                                     packageName.append(MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
286                                     packageName.append(name);
287                                 }
288                             }
289                             valid = UMLModelAccessFacade.this.modelPackages.isApply(packageName.toString());
290                         }
291 
292                         return valid;
293                     }
294                 });
295         }
296     }
297 }