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   
7   import org.andromda.core.common.ClassUtils;
8   import org.andromda.core.common.ExceptionUtils;
9   import org.andromda.core.common.Introspector;
10  import org.andromda.core.profile.Profile;
11  import org.apache.commons.lang.StringUtils;
12  
13  
14  /***
15   * Represents a single template <modelElement/> nested within the <modelElements/> element. It stores the
16   * actual metafacade instances which match the model element criteria (i.e. stereotype, type, etc) defined by this
17   * instance.
18   *
19   * @author Chad Brandon
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 types = new ArrayList();
51  
52      /***
53       * Gets all types associated with this model element.
54       *
55       * @return the collection of types.
56       */
57      public Collection 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 metafacades = new ArrayList();
125 
126     /***
127      * Sets the current metafacades that belong to this ModelElement instance.
128      *
129      * @param metafacades the collection of metafacdes
130      */
131     public void setMetafacades(final Collection 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 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 (final Iterator iterator = this.types.iterator(); iterator.hasNext() && accept;)
177         {
178             final Type type = (Type)iterator.next();
179             if (StringUtils.isNotBlank(type.getName()))
180             {
181                 try
182                 {
183                     accept = ClassUtils.loadClass(type.getName()).isAssignableFrom(metafacade.getClass());
184 
185                     // if the type matches the name, continue
186                     if (accept)
187                     {
188                         for (final Iterator properties = type.getProperties().iterator(); properties.hasNext();)
189                         {
190                             final Type.Property property = (Type.Property)properties.next();
191                             accept =
192                                 Introspector.instance().containsValidProperty(
193                                     metafacade,
194                                     property.getName(),
195                                     property.getValue());
196                             if (!accept)
197                             {
198                                 // break out of the loop on the first invalid
199                                 // property since all propertie should be valid.
200                                 break;
201                             }
202                         }
203                     }
204                 }
205                 catch (final Throwable throwable)
206                 {
207                     accept = false;
208                 }
209             }
210         }
211         return accept;
212     }
213 }