001: package org.andromda.core.metafacade;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.List;
006: import java.util.ListIterator;
007:
008: import org.apache.commons.lang.StringUtils;
009: import org.apache.log4j.Logger;
010:
011: /**
012: * Base class for all metafacades.
013: *
014: * @author <a href="http://www.mbohlen.de">Matthias Bohlen </a>
015: * @author Chad Brandon
016: * @author Wouter Zoons
017: */
018: public class MetafacadeBase {
019: /**
020: * The meta object which this metafacade wraps.
021: */
022: private Object metaObject;
023:
024: /**
025: * Constructs a new instance of this class with the given <code>metaObject</code>
026: * and <code>context</code>. The metaObject is the meta model element which
027: * this metafacade insulates. The <code>context</code> is the name of the
028: * context for this metafacade instance.
029: *
030: * @param metaObject the meta object.
031: * @param context the context of this meta object.
032: */
033: public MetafacadeBase(final Object metaObject, final String context) {
034: this .metaObject = metaObject;
035: this .context = context;
036: }
037:
038: /**
039: * Retrieves the <code>owner</code> of this metafacade (for example: an operation owns its parameters, a class owns
040: * its attributes).
041: * <p/>
042: * By default <code>null</code> is returned, however this method is overridden by subclasses which have a
043: * <code>parent</code> or <code>owner</code>. This is used to give the model validation messages more context as to
044: * where the validation error occurred. </p>
045: *
046: * @return the owner of this metafacade.
047: */
048: public Object getValidationOwner() {
049: return null;
050: }
051:
052: /**
053: * Retrieves the <code>name</code> of this metafacade used within the validation messages.
054: * <p/>
055: * By default <code>null</code> is returned, however this method is overridden by subclasses model elements that do
056: * have a name. </p>
057: *
058: * @return the owner of this metafacade.
059: */
060: public String getValidationName() {
061: return null;
062: }
063:
064: /**
065: * Stores whether or not this metafacade has
066: * been initialized.
067: */
068: private boolean initialized = false;
069:
070: /**
071: * Sets the flag indicating this metafacade has been initialized.
072: */
073: final void setInitialized() {
074: this .initialized = true;
075: }
076:
077: /**
078: * Indicates if this metafacade has been initialized.
079: *
080: * @return true/false
081: */
082: final boolean isInitialized() {
083: return this .initialized;
084: }
085:
086: /**
087: * Validates that this facade's meta object is in a valid state.
088: * <p/>
089: * Validate is called during metafacade creation by the factory. In the lifecycle of a metafacade it is validated
090: * only once, this is enforced by the caching within the metafacade factory.
091: *
092: * @param validationMessages any messages generated during validation.
093: * @see MetafacadeFactory#createMetafacade(Object, String, Class)
094: */
095: public final void validate(final Collection validationMessages) {
096: this .validateInvariants(validationMessages);
097: }
098:
099: /**
100: * <p/>
101: * The logic of modeled OCL invariants from derived metafacades will be generated into this method and validation
102: * messages created and collected into the <code>messages</code> collection. This method is called by {@link #validate(Collection)}
103: * <p/>
104: * By default this method is empty. </p>
105: */
106: public void validateInvariants(final Collection messages) {
107: // By default this does nothing
108: }
109:
110: /**
111: * A lifecycle method, providing the ability for sub classes to take any action after the factory has completely
112: * initialized a metafacade, but before it has been validated for completeness.
113: */
114: public void initialize() {
115: // By default this does nothing
116: }
117:
118: /**
119: * Returns one facade for a particular metaObject. Contacts the MetafacadeFactory to manufacture the proper
120: * metafacade. In certain cases <code>metaObject</code> can also be a metafacade instance; in that case the actual
121: * meta model element is retrieved from the metafacade and a metafacade is constructed from that.
122: *
123: * @param metaObject the underlying meta model element. A metafacade is created for each.
124: * @return MetafacadeBase the facade
125: * @see MetafacadeFactory
126: */
127: protected MetafacadeBase shieldedElement(final Object metaObject) {
128: MetafacadeBase metafacade = null;
129: if (metaObject != null) {
130: final String context = this .getContext();
131: metafacade = MetafacadeFactory.getInstance()
132: .createMetafacade(metaObject, context);
133:
134: // - The metafacade we've just got may have been found in the cache.
135: // If so, it can have an arbitrary context (because it's cached).
136: // We now need to set the context once again, so that all
137: // other metafacade mappings based on the context work as expected.
138: if (metafacade != null) {
139: metafacade.resetMetafacadeContext(context);
140: }
141: }
142: return metafacade;
143: }
144:
145: /**
146: * Returns a collection of facades for a collection of metaobjects. Contacts the MetafacadeFactory to manufacture
147: * the proper facades.
148: *
149: * @param metaobjects the objects to decorate
150: * @return Collection of MetafacadeBase-derived objects
151: * @see MetafacadeFactory
152: */
153: protected Collection shieldedElements(final Collection metaobjects) {
154: final List metafacades = new ArrayList();
155: if (metaobjects != null) {
156: metafacades.addAll(metaobjects);
157: for (final ListIterator iterator = metafacades
158: .listIterator(); iterator.hasNext();) {
159: iterator.set(this .shieldedElement(iterator.next()));
160: }
161: }
162: return metafacades;
163: }
164:
165: /**
166: * Stores the context for this metafacade
167: */
168: private String context = null;
169:
170: /**
171: * Gets the context for this metafacade.
172: *
173: * @return the context name.
174: */
175: final String getContext() {
176: String context = this .context;
177: if (StringUtils.isBlank(context)) {
178: context = this .getName();
179: }
180: return context;
181: }
182:
183: /**
184: * Sets the context for this metafacade. This is used to pass the context along from a metafacade specializing this
185: * metafacade (since we use delegate inheritance between shared and non-shared metafacades), as well as to pass the
186: * context to a metafacade being created within another.
187: *
188: * @param context the metafacade interface name representing the context.
189: * @see MetafacadeMapping#isContextRoot()
190: * @see MetafacadeFactory#createMetafacade(Object, String, Class)
191: */
192: public void setMetafacadeContext(final String context) {
193: this .context = context;
194: }
195:
196: /**
197: * Resets the metafacade context after the metafacade was retrieved from the metafacade cache.
198: * DO NOT CALL THIS METHOD BY HAND, it is reserved for use in the MetafacadeFactory.
199: * @see org.andromda.core.metafacade.MetafacadeFactory
200: * @param context the context defined by MetafacadeFactory
201: */
202: public void resetMetafacadeContext(String context) {
203: throw new IllegalStateException(
204: "Method resetMetafacadeContext() must be overridden by concrete metafacade class ("
205: + this .getClass().getName()
206: + ")! Please re-generate your metafacades using the new andromda-meta cartridge.");
207: }
208:
209: /**
210: * Stores the namespace for this metafacade
211: */
212: private String namespace = null;
213:
214: /**
215: * Gets the current namespace for this metafacade
216: *
217: * @return String
218: */
219: final String getNamespace() {
220: return this .namespace;
221: }
222:
223: /**
224: * Sets the namespace for this metafacade.
225: *
226: * @param namespace
227: */
228: final void setNamespace(final String namespace) {
229: this .namespace = namespace;
230: }
231:
232: /**
233: * Returns true or false depending on whether the <code>property</code> is registered or not.
234: *
235: * @param property the name of the property to check.
236: * @return true/false on whether or not its regisgterd.
237: */
238: protected boolean isConfiguredProperty(final String property) {
239: return MetafacadeFactory.getInstance().isPropertyRegistered(
240: this , property);
241: }
242:
243: /**
244: * Gets a configured property from the container. Note that the configured property must be registered first.
245: *
246: * @param property the property name
247: * @return Object the configured property instance (mappings, etc)
248: */
249: protected Object getConfiguredProperty(final String property) {
250: return MetafacadeFactory.getInstance().getRegisteredProperty(
251: this , property);
252: }
253:
254: /**
255: * Attempts to set the property with <code>name</code> having the specified <code>value</code> on this metafacade.
256: */
257: protected void setProperty(final String name, final Object value) {
258: MetafacadeFactory.getInstance().registerProperty(
259: this .getName(), name, value);
260: }
261:
262: /**
263: * Gets the current meta model object for this metafacade. This is used from {@link MetafacadeFactory} when
264: * attempting to construct a metafacade from a metafacade. This allows us to get the meta object for this metafacade
265: * so that the meta object can be used instead.
266: *
267: * @return the underlying model's meta object instance.
268: */
269: public final Object getMetaObject() {
270: return this .metaObject;
271: }
272:
273: /**
274: * The metafacade logger instance.
275: */
276: protected Logger logger;
277:
278: /**
279: * Package-local setter, called by facade factory. Sets the logger to use inside the facade's code.
280: *
281: * @param logger the logger to set
282: */
283: final void setLogger(final Logger logger) {
284: this .logger = logger;
285: }
286:
287: /**
288: * The flag indicating whether or not this metafacade is a context root.
289: */
290: protected boolean contextRoot = false;
291:
292: /**
293: * Sets whether or not this metafacade represents a contextRoot. If it does represent a context root, then {@link
294: * #getMetafacadeContext()}returns the metafacade interface for this metafacade, otherwise the regular
295: * <code>context</code> is returned.
296: *
297: * @param contextRoot
298: */
299: final void setContextRoot(final boolean contextRoot) {
300: this .contextRoot = contextRoot;
301: }
302:
303: /**
304: * Gets the <code>context</code> for this metafacade. This is either the <code>contextRoot</code> (if one exists),
305: * or the regular <code>context</code>.
306: *
307: * @return the metafacade's context.
308: * @see #setContextRoot(boolean)
309: */
310: public String getMetafacadeContext() {
311: String metafacadeContext = this .getContext();
312: if (this .contextRoot) {
313: metafacadeContext = this .getName();
314: }
315: return metafacadeContext;
316: }
317:
318: /**
319: * Stores the name of the interface for this metafacade
320: */
321: private String name = null;
322:
323: /**
324: * Gets the name for this metafacade.
325: *
326: * @return the metafacade's name.
327: */
328: final String getName() {
329: if (this .name == null) {
330: this .name = MetafacadeImpls.instance().getMetafacadeClass(
331: this .getClass().getName()).getName();
332: }
333: return this .name;
334: }
335:
336: /**
337: * @see java.lang.Object#equals(java.lang.Object)
338: */
339: public boolean equals(Object object) {
340: boolean equals = false;
341: if (object instanceof MetafacadeBase) {
342: MetafacadeBase that = (MetafacadeBase) object;
343: equals = this .metaObject.equals(that.metaObject);
344: }
345: return equals;
346: }
347:
348: /**
349: * @see java.lang.Object#hashCode()
350: */
351: public int hashCode() {
352: return metaObject.hashCode();
353: }
354:
355: /**
356: * In order to speed up the check for this property (which will happen many times), we cache it :-)
357: */
358: private Boolean metafacadePropertyCachingEnabled = null;
359:
360: /**
361: * A check to verify whether or not to make use of metafacade property caching. This method check if the {@link
362: * MetafacadeProperties#ENABLE_METAFACADE_PROPERTY_CACHING} namespace property has been set, if this is not the case
363: * then the caching will be enabled by default.
364: */
365: public final boolean isMetafacadePropertyCachingEnabled() {
366: if (this .metafacadePropertyCachingEnabled == null) {
367: final String enableCache = (String) this
368: .getConfiguredProperty(MetafacadeProperties.ENABLE_METAFACADE_PROPERTY_CACHING);
369: this .metafacadePropertyCachingEnabled = Boolean
370: .valueOf(enableCache);
371: }
372: return this .metafacadePropertyCachingEnabled.booleanValue();
373: }
374:
375: /**
376: * The instance of this class as the appropriate metafacade instance.
377: */
378: private MetafacadeBase THIS = null;
379:
380: /**
381: * The metafacade instance of <code>this</code>. This should be used when
382: * you'd need to check if <code>this</code> was an instance of a given metafacade.
383: * For example: <code>THIS() instanceof SomeMetafacade</code>.
384: *
385: * This <strong>MUST</strong> be used instead of <em>this<em> in order to access the correct
386: * metafacade instance in the hierarchy (since we use delegate inheritance).
387: */
388: protected final MetafacadeBase THIS() {
389: return this.THIS == null ? this.THIS = this
390: .shieldedElement(this.metaObject) : this.THIS;
391: }
392: }
|