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
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
199
200 break;
201 }
202 }
203 }
204 }
205 catch (final Throwable throwable)
206 {
207 accept = false;
208 }
209 }
210 }
211 return accept;
212 }
213 }