001: package org.andromda.cartridges.meta.metafacades;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Collections;
006: import java.util.Comparator;
007: import java.util.HashMap;
008: import java.util.Iterator;
009: import java.util.LinkedHashSet;
010: import java.util.List;
011: import java.util.Map;
012: import java.util.Set;
013:
014: import org.andromda.cartridges.meta.MetaProfile;
015: import org.andromda.core.metafacade.MetafacadeException;
016: import org.andromda.metafacades.uml.AssociationEndFacade;
017: import org.andromda.metafacades.uml.AttributeFacade;
018: import org.andromda.metafacades.uml.ClassifierFacade;
019: import org.andromda.metafacades.uml.DependencyFacade;
020: import org.andromda.metafacades.uml.GeneralizationFacade;
021: import org.andromda.metafacades.uml.ModelElementFacade;
022: import org.andromda.metafacades.uml.OperationFacade;
023: import org.apache.commons.collections.CollectionUtils;
024: import org.apache.commons.collections.Predicate;
025: import org.apache.commons.collections.Transformer;
026: import org.apache.commons.lang.ObjectUtils;
027: import org.apache.commons.lang.StringUtils;
028:
029: /**
030: * Metaclass facade implementation.
031: *
032: * @see org.andromda.cartridges.meta.metafacades.Metafacade
033: */
034: public class MetafacadeLogicImpl extends MetafacadeLogic {
035: /**
036: * This defines the metamodel version package name (i.e.
037: * org.andromda.metafacades.uml14, org.andromda.metafacades.um20, etc) used
038: * by this cartridge to create the generated impl package name, if left
039: * empty then the impl package will be the same as the metafacade package
040: * (therefore we default to an empty name)
041: */
042: private static final String METAMODEL_VERSION_PACKAGE = "metamodelVersionPackage";
043: private Map featureMap = null;
044:
045: public MetafacadeLogicImpl(java.lang.Object metaObject,
046: String context) {
047: super (metaObject, context);
048: }
049:
050: /**
051: * Returns the class tagged with <<metaclass>>> that is
052: * connected to the metaobject via a dependency. If no metaclass is directly
053: * connected, the method walks up the supertype hierarchy.
054: *
055: * @return the metaclass object
056: */
057: protected Object handleGetMetaclass() {
058: // delegate to recursive method
059: return getMetaclass(this );
060: }
061:
062: /**
063: * Returns the class tagged with <<metaclass>> that is connected
064: * to cl via a dependency.
065: *
066: * @param cl the source classifier
067: * @return the metaclass object
068: */
069: private ClassifierFacade getMetaclass(ClassifierFacade classifier) {
070: for (final Iterator iter = classifier.getSourceDependencies()
071: .iterator(); iter.hasNext();) {
072: DependencyFacade dep = (DependencyFacade) iter.next();
073: ClassifierFacade target = (ClassifierFacade) dep
074: .getTargetElement();
075: Collection stereotypes = target.getStereotypeNames();
076: if ((stereotypes != null) && (stereotypes.size() > 0)) {
077: String stereotypeName = (String) stereotypes.iterator()
078: .next();
079: if (stereotypeName
080: .equals(MetaProfile.STEREOTYPE_METACLASS)) {
081: return target;
082: }
083: }
084: }
085:
086: ClassifierFacade super class = (ClassifierFacade) classifier
087: .getGeneralization();
088: return (super class != null) ? getMetaclass(super class) : null;
089: }
090:
091: /**
092: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#isMetaclassDirectDependency()
093: */
094: protected boolean handleIsMetaclassDirectDependency() {
095: boolean isMetaClassDirectDependency = false;
096: Collection dependencies = this .getSourceDependencies();
097: if ((dependencies != null) && !dependencies.isEmpty()) {
098: // there should be only one.
099: DependencyFacade dependency = (DependencyFacade) dependencies
100: .iterator().next();
101: if (dependency != null) {
102: ModelElementFacade targetElement = dependency
103: .getTargetElement();
104: if (targetElement != null) {
105: isMetaClassDirectDependency = targetElement
106: .hasStereotype(MetaProfile.STEREOTYPE_METACLASS);
107: }
108: }
109: }
110: return isMetaClassDirectDependency;
111: }
112:
113: /**
114: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicName()
115: */
116: protected String handleGetLogicName() {
117: return this .getName() + "Logic";
118: }
119:
120: /**
121: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicImplName()
122: */
123: protected String handleGetLogicImplName() {
124: return this .getName() + "LogicImpl";
125: }
126:
127: /**
128: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getFullyQualifiedLogicImplName()
129: */
130: protected String handleGetFullyQualifiedLogicImplName() {
131: return this .getMetafacadeSupportClassName(this
132: .getLogicImplName());
133: }
134:
135: /**
136: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getFullyQualifiedLogicName()
137: */
138: protected String handleGetFullyQualifiedLogicName() {
139: return this .getMetafacadeSupportClassName(this .getLogicName());
140: }
141:
142: /**
143: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicFile(java.lang.String)
144: */
145: protected String handleGetLogicFile() {
146: return this .getFullyQualifiedLogicName().replace('.', '/')
147: + ".java";
148: }
149:
150: /**
151: * Gets the metamodel version package name (i.e.
152: * org.andromda.metafacades.uml14, org.andromda.metafacades.um20, etc) used
153: * by this cartridge to create the generated impl package name, if left
154: * empty then the impl package will be the same as the metafacade package
155: * (therefore we default to an empty name)
156: */
157: private String getMetaModelVersionPackage() {
158: return ObjectUtils.toString(this
159: .getConfiguredProperty(METAMODEL_VERSION_PACKAGE));
160: }
161:
162: /**
163: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicPackageName(java.lang.String)
164: */
165: protected String handleGetLogicPackageName() {
166: String packageName = this .getMetaModelVersionPackage();
167: if (StringUtils.isEmpty(packageName)) {
168: packageName = this .getPackageName();
169: }
170: return packageName;
171: }
172:
173: /**
174: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getLogicImplFile(java.lang.String)
175: */
176: protected String handleGetLogicImplFile() {
177: return this .getFullyQualifiedLogicImplName().replace('.', '/')
178: + ".java";
179: }
180:
181: /**
182: * Creates a metafacade support class name from the given
183: * <code>metamodelVersionPackage</code> (i.e. the package for the specific
184: * meta model version). Support classes are the 'Logic' classes.
185: *
186: * @param metamodelVersionPackage the version of the meta model
187: * @param the name of the class to append to the package.
188: * @return the new metafacade support class name.
189: */
190: private String getMetafacadeSupportClassName(String name) {
191: StringBuffer fullyQualifiedName = new StringBuffer(this
192: .getLogicPackageName());
193: if (StringUtils.isNotBlank(fullyQualifiedName.toString())) {
194: fullyQualifiedName.append(".");
195: fullyQualifiedName.append(name);
196: }
197: return fullyQualifiedName.toString();
198: }
199:
200: /**
201: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacadeLogic#handleGetMethodDataForPSM(org.andromda.metafacades.uml.ClassifierFacade)
202: */
203: protected Collection handleGetMethodDataForPSM(
204: ClassifierFacade facade) {
205: return this .getMethodDataForPSM(facade, true);
206: }
207:
208: /**
209: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getMethodDataForPSM()
210: */
211: protected Collection handleGetMethodDataForPSM() {
212: return this .getMethodDataForPSM(null, false);
213: }
214:
215: /**
216: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getMethodDataForPSM(boolean)
217: */
218: private final Collection getMethodDataForPSM(
219: final ClassifierFacade facade,
220: final boolean includeSuperclasses) {
221: try {
222: final Set declarationSet = new LinkedHashSet();
223: if (this .featureMap == null) {
224: this .featureMap = new HashMap();
225: if (includeSuperclasses
226: && this .getGeneralizations() != null) {
227: for (final Iterator iterator = this
228: .getGeneralizations().iterator(); iterator
229: .hasNext();) {
230: final Map methodDataMap = new HashMap();
231: final ClassifierFacade metafacade = (ClassifierFacade) iterator
232: .next();
233: for (ClassifierFacade classifier = metafacade; classifier instanceof Metafacade; classifier = (ClassifierFacade) classifier
234: .getGeneralization()) {
235: this .getAllFeatures(methodDataMap,
236: declarationSet,
237: (Metafacade) classifier);
238: }
239: this .featureMap.put(metafacade, methodDataMap
240: .values());
241: }
242: }
243: }
244: final List result = new ArrayList();
245: if (this .featureMap != null) {
246: Collection features = (Collection) this .featureMap
247: .get(facade);
248: if (features != null) {
249: result.addAll(features);
250: }
251: }
252: if (!includeSuperclasses) {
253: final Map methodDataMap = new HashMap();
254: this
255: .getAllFeatures(methodDataMap, declarationSet,
256: this );
257: result.addAll(methodDataMap.values());
258: }
259: Collections.sort(result);
260: return result;
261: } catch (Throwable th) {
262: throw new RuntimeException(th);
263: }
264: }
265:
266: private final void getAllFeatures(final Map methodDataMap,
267: final Set declarationSet, final Metafacade facade) {
268: try {
269: final String methodVisibility = "public";
270: final String indendation = " * ";
271: final String fullyQualifiedName = facade
272: .getFullyQualifiedName();
273:
274: // translate UML attributes and association ends to getter methods
275: for (final Iterator iterator = facade.getProperties()
276: .iterator(); iterator.hasNext();) {
277: final ModelElementFacade property = (ModelElementFacade) iterator
278: .next();
279: MethodData method = null;
280: if (property instanceof AttributeFacade) {
281: final AttributeFacade attribute = (AttributeFacade) property;
282: method = new MethodData(fullyQualifiedName,
283: methodVisibility, false, attribute
284: .getGetterSetterTypeName(),
285: attribute.getGetterName(), attribute
286: .getDocumentation(indendation));
287: } else {
288: final AssociationEndFacade association = (AssociationEndFacade) property;
289: method = new MethodData(fullyQualifiedName,
290: methodVisibility, false, association
291: .getGetterSetterTypeName(),
292: association.getGetterName(), association
293: .getDocumentation(indendation));
294: }
295: final String declaration = method
296: .buildMethodDeclaration(true);
297:
298: // don't add the new method data if we already have the
299: // declaration from a previous generalization.
300: if (!declarationSet.contains(declaration)) {
301: methodDataMap.put(method.buildCharacteristicKey(),
302: method);
303: declarationSet.add(declaration);
304: }
305: }
306:
307: // translate UML operations to methods
308: for (final Iterator iterator = facade.getOperations()
309: .iterator(); iterator.hasNext();) {
310: final OperationFacade operation = (OperationFacade) iterator
311: .next();
312: final UMLOperationData method = new UMLOperationData(
313: fullyQualifiedName, operation);
314:
315: // don't add the new method data if we already have the
316: // declaration from a previous generalization.
317: final String declaration = method
318: .buildMethodDeclaration(true);
319: if (!declarationSet.contains(declaration)) {
320: methodDataMap.put(method.buildCharacteristicKey(),
321: method);
322: declarationSet.add(declaration);
323: }
324: }
325: } catch (final Throwable throwable) {
326: logger.error(throwable);
327: throw new MetafacadeException(throwable);
328: }
329: }
330:
331: /**
332: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#isRequiresInheritanceDelegatation()
333: */
334: protected boolean handleIsRequiresInheritanceDelegatation() {
335: boolean requiresInheritanceDelegation = false;
336: final ModelElementFacade super Metafacade = this
337: .getGeneralization();
338: if (super Metafacade != null) {
339: requiresInheritanceDelegation = !super Metafacade
340: .getPackageName().equals(this .getPackageName())
341: || (this .getGeneralizations().size() > 1);
342: }
343: return requiresInheritanceDelegation;
344: }
345:
346: /**
347: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#isConstructorRequiresMetaclassCast()
348: */
349: protected boolean handleIsConstructorRequiresMetaclassCast() {
350: boolean requiresCast = false;
351: final Metafacade super Metafacade = (Metafacade) this
352: .getGeneralization();
353: if (super Metafacade != null) {
354: requiresCast = super Metafacade
355: .isMetaclassDirectDependency()
356: && !this .isRequiresInheritanceDelegatation();
357: }
358: return requiresCast;
359: }
360:
361: /**
362: * @see org.andromda.metafacades.uml.GeneralizableElementFacade#getGeneralizations()
363: */
364: public Collection getGeneralizations() {
365: final List generalizations = new ArrayList(super
366: .getGeneralizationLinks());
367: Collections.sort(generalizations,
368: new GeneralizationPrecedenceComparator());
369: CollectionUtils.transform(generalizations, new Transformer() {
370: public Object transform(final Object object) {
371: return ((GeneralizationFacade) object).getParent();
372: }
373: });
374: CollectionUtils.filter(generalizations, new Predicate() {
375: public boolean evaluate(final Object object) {
376: return object instanceof Metafacade;
377: }
378: });
379: return generalizations;
380: }
381:
382: /**
383: * @see org.andromda.cartridges.meta.metafacades.MetafacadeFacade#getGeneralizationCount()
384: */
385: protected int handleGetGeneralizationCount() {
386: int count = 0;
387: final Collection generalizations = this .getGeneralizations();
388: if (generalizations != null) {
389: count = generalizations.size();
390: }
391: return count;
392: }
393:
394: /**
395: * Used to sort metafacade generalizations by precedence.
396: */
397: static final class GeneralizationPrecedenceComparator implements
398: Comparator {
399: public int compare(Object objectA, Object objectB) {
400: MetafacadeGeneralization a = (MetafacadeGeneralization) objectA;
401: MetafacadeGeneralization b = (MetafacadeGeneralization) objectB;
402: return a.getPrecedence().compareTo(b.getPrecedence());
403: }
404: }
405:
406: /**
407: * @see org.andromda.cartridges.meta.metafacades.MetafacadeLogic#getAllParents()
408: */
409: protected Collection handleGetAllParents() {
410: Set allParents = new LinkedHashSet();
411: final Collection parents = this .getGeneralizations();
412: allParents.addAll(parents);
413: for (final Iterator iterator = parents.iterator(); iterator
414: .hasNext();) {
415: final Object object = iterator.next();
416: if (object instanceof Metafacade) {
417: final Metafacade metafacade = (Metafacade) object;
418: allParents.addAll(metafacade.getAllParents());
419: }
420: }
421: return allParents;
422: }
423: }
|