001: package org.andromda.core.cartridge.template;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Iterator;
006:
007: import org.andromda.core.common.ClassUtils;
008: import org.andromda.core.common.ExceptionUtils;
009: import org.andromda.core.common.Introspector;
010: import org.andromda.core.profile.Profile;
011: import org.apache.commons.lang.StringUtils;
012:
013: /**
014: * Represents a single template <modelElement/> nested within the <modelElements/> element. It stores the
015: * actual metafacade instances which match the model element criteria (i.e. stereotype, type, etc) defined by this
016: * instance.
017: *
018: * @author Chad Brandon
019: * @see ModelElements
020: */
021: public class ModelElement {
022: private String stereotype;
023:
024: /**
025: * Gets the stereotype of this modelElement.
026: *
027: * @return Returns the stereotype.
028: */
029: public String getStereotype() {
030: return Profile.instance().get(this .stereotype);
031: }
032:
033: /**
034: * Returns <code>true</code> or <code>false</code> depending on whether or not this model element has a stereotype
035: * defined.
036: *
037: * @return true/false
038: */
039: public boolean hasStereotype() {
040: return this .stereotype != null;
041: }
042:
043: /**
044: * Stores the types defined for this model element.
045: */
046: private final Collection types = new ArrayList();
047:
048: /**
049: * Gets all types associated with this model element.
050: *
051: * @return the collection of types.
052: */
053: public Collection getTypes() {
054: return this .types;
055: }
056:
057: /**
058: * Returns <code>true</code> or <code>false</code> depending on whether or not this model element has any type
059: * elements defined.
060: *
061: * @return true/false
062: */
063: public boolean hasTypes() {
064: return !this .getTypes().isEmpty();
065: }
066:
067: /**
068: * Sets the stereotype of the ModelElement.
069: *
070: * @param stereotype The stereotype to set.
071: */
072: public void setStereotype(final String stereotype) {
073: this .stereotype = stereotype;
074: ExceptionUtils.checkEmpty("stereotype", this .stereotype);
075: }
076:
077: /**
078: * Adds the <code>type</code> to the collection of types belonging to this model element.
079: *
080: * @param type the {@link Type}instance.
081: */
082: public void addType(final Type type) {
083: ExceptionUtils.checkNull("type", type);
084: this .types.add(type);
085: }
086:
087: /**
088: * Stores the name of the variable for this model element.
089: */
090: private String variable;
091:
092: /**
093: * Gets the variable stereotype of this modelElement (this is what is made available to a template during
094: * processing).
095: *
096: * @return Returns the variable.
097: */
098: public String getVariable() {
099: return this .variable;
100: }
101:
102: /**
103: * Sets the variable name.
104: *
105: * @param variable The variable to set.
106: */
107: public void setVariable(final String variable) {
108: this .variable = StringUtils.trimToEmpty(variable);
109: }
110:
111: /**
112: * The metafacades for this model element.
113: */
114: private Collection metafacades = new ArrayList();
115:
116: /**
117: * Sets the current metafacades that belong to this ModelElement instance.
118: *
119: * @param metafacades the collection of metafacdes
120: */
121: public void setMetafacades(final Collection metafacades) {
122: ExceptionUtils.checkNull("metafacades", metafacades);
123: this .metafacades = metafacades;
124: this .applyTypeFiltering();
125: }
126:
127: /**
128: * Gets the metafacades that belong to this ModelElement instance. These are the actual elements from the model.
129: *
130: * @return the collection of metafacades.
131: */
132: public Collection getMetafacades() {
133: return this .metafacades;
134: }
135:
136: /**
137: * Applies any filtering by any types specified within this model element.
138: */
139: private void applyTypeFiltering() {
140: if (this .hasTypes()) {
141: for (final Iterator iterator = this .metafacades.iterator(); iterator
142: .hasNext();) {
143: if (!accept(iterator.next())) {
144: iterator.remove();
145: }
146: }
147: }
148: }
149:
150: /**
151: * Checks the <code>object</code> to see whether or not its acceptable. It matches on the types and each type's
152: * properties. <strong>NOTE:</strong> protected visibility to improve performance from within {@link
153: * #applyTypeFiltering()}
154: *
155: * @param metafacade the metafacade to check
156: * @return true/false
157: */
158: private boolean accept(final Object metafacade) {
159: boolean accept = true;
160: for (final Iterator iterator = this .types.iterator(); iterator
161: .hasNext()
162: && accept;) {
163: final Type type = (Type) iterator.next();
164: if (StringUtils.isNotBlank(type.getName())) {
165: try {
166: accept = ClassUtils.loadClass(type.getName())
167: .isAssignableFrom(metafacade.getClass());
168:
169: // if the type matches the name, continue
170: if (accept) {
171: for (final Iterator properties = type
172: .getProperties().iterator(); properties
173: .hasNext();) {
174: final Type.Property property = (Type.Property) properties
175: .next();
176: accept = Introspector.instance()
177: .containsValidProperty(metafacade,
178: property.getName(),
179: property.getValue());
180: if (!accept) {
181: // break out of the loop on the first invalid
182: // property since all propertie should be valid.
183: break;
184: }
185: }
186: }
187: } catch (final Throwable throwable) {
188: accept = false;
189: }
190: }
191: }
192: return accept;
193: }
194: }
|