View Javadoc
1   package org.andromda.core.cartridge.template;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Iterator;
6   import org.andromda.core.common.ClassUtils;
7   import org.andromda.core.common.ExceptionUtils;
8   import org.andromda.core.common.Introspector;
9   import org.andromda.core.metafacade.MetafacadeBase;
10  import org.andromda.core.profile.Profile;
11  import org.apache.commons.lang.StringUtils;
12  
13  /**
14   * Represents a single template <modelElement/> nested within the <modelElements/> element. It stores the
15   * actual metafacade instances which match the model element criteria (i.e. stereotype, type, etc) defined by this
16   * instance.
17   *
18   * @author Chad Brandon
19   * @author Bob Fields
20   * @see ModelElements
21   */
22  public class ModelElement
23  {
24      private String stereotype;
25  
26      /**
27       * Gets the stereotype of this modelElement.
28       *
29       * @return Returns the stereotype.
30       */
31      public String getStereotype()
32      {
33          return Profile.instance().get(this.stereotype);
34      }
35  
36      /**
37       * Returns <code>true</code> or <code>false</code> depending on whether or not this model element has a stereotype
38       * defined.
39       *
40       * @return true/false
41       */
42      public boolean hasStereotype()
43      {
44          return this.stereotype != null;
45      }
46  
47      /**
48       * Stores the types defined for this model element.
49       */
50      private final Collection<Type> types = new ArrayList<Type>();
51  
52      /**
53       * Gets all types associated with this model element.
54       *
55       * @return the collection of types.
56       */
57      public Collection<Type> getTypes()
58      {
59          return this.types;
60      }
61  
62      /**
63       * Returns <code>true</code> or <code>false</code> depending on whether or not this model element has any type
64       * elements defined.
65       *
66       * @return true/false
67       */
68      public boolean hasTypes()
69      {
70          return !this.getTypes().isEmpty();
71      }
72  
73      /**
74       * Sets the stereotype of the ModelElement.
75       *
76       * @param stereotype The stereotype to set.
77       */
78      public void setStereotype(final String stereotype)
79      {
80          this.stereotype = stereotype;
81          ExceptionUtils.checkEmpty("stereotype", this.stereotype);
82      }
83  
84      /**
85       * Adds the <code>type</code> to the collection of types belonging to this model element.
86       *
87       * @param type the {@link Type}instance.
88       */
89      public void addType(final Type type)
90      {
91          ExceptionUtils.checkNull("type", type);
92          this.types.add(type);
93      }
94  
95      /**
96       * Stores the name of the variable for this model element.
97       */
98      private String variable;
99  
100     /**
101      * Gets the variable stereotype of this modelElement (this is what is made available to a template during
102      * processing).
103      *
104      * @return Returns the variable.
105      */
106     public String getVariable()
107     {
108         return this.variable;
109     }
110 
111     /**
112      * Sets the variable name.
113      *
114      * @param variable The variable to set.
115      */
116     public void setVariable(final String variable)
117     {
118         this.variable = StringUtils.trimToEmpty(variable);
119     }
120 
121     /**
122      * The metafacades for this model element.
123      */
124     private Collection<MetafacadeBase> metafacades = new ArrayList<MetafacadeBase>();
125 
126     /**
127      * Sets the current metafacades that belong to this ModelElement instance.
128      *
129      * @param metafacades the collection of metafacades
130      */
131     public void setMetafacades(final Collection<MetafacadeBase> metafacades)
132     {
133         ExceptionUtils.checkNull("metafacades", metafacades);
134         this.metafacades = metafacades;
135         this.applyTypeFiltering();
136     }
137 
138     /**
139      * Gets the metafacades that belong to this ModelElement instance. These are the actual elements from the model.
140      *
141      * @return the collection of metafacades.
142      */
143     public Collection<MetafacadeBase> getMetafacades()
144     {
145         return this.metafacades;
146     }
147 
148     /**
149      * Applies any filtering by any types specified within this model element.
150      */
151     private void applyTypeFiltering()
152     {
153         if (this.hasTypes())
154         {
155             for (final Iterator iterator = this.metafacades.iterator(); iterator.hasNext();)
156             {
157                 if (!accept(iterator.next()))
158                 {
159                     iterator.remove();
160                 }
161             }
162         }
163     }
164 
165     /**
166      * Checks the <code>object</code> to see whether or not its acceptable. It matches on the types and each type's
167      * properties. <strong>NOTE:</strong> protected visibility to improve performance from within {@link
168      * #applyTypeFiltering()}
169      *
170      * @param metafacade the metafacade to check
171      * @return true/false
172      */
173     private boolean accept(final Object metafacade)
174     {
175         boolean accept = true;
176         for (Type type : this.types)
177         {
178             if (StringUtils.isNotBlank(type.getName()))
179             {
180                 try
181                 {
182                     accept = ClassUtils.loadClass(type.getName()).isAssignableFrom(metafacade.getClass());
183 
184                     // if the type matches the name, continue
185                     if (accept)
186                     {
187                         for (Type.Property property : type.getProperties())
188                         {
189                             accept =
190                                 Introspector.instance().containsValidProperty(
191                                     metafacade,
192                                     property.getName(),
193                                     property.getValue());
194                             if (!accept)
195                             {
196                                 // break out of the loop on the first invalid
197                                 // property since all properties should be valid.
198                                 break;
199                             }
200                         }
201                     }
202                 }
203                 catch (final Throwable throwable)
204                 {
205                     accept = false;
206                 }
207             }
208         }
209         return accept;
210     }
211 }