001: package org.andromda.core.metafacade;
002:
003: import java.net.URL;
004:
005: import java.util.ArrayList;
006: import java.util.Arrays;
007: import java.util.Collection;
008: import java.util.Iterator;
009: import java.util.LinkedHashMap;
010: import java.util.List;
011: import java.util.Map;
012:
013: import org.andromda.core.common.ClassUtils;
014: import org.andromda.core.common.Constants;
015: import org.andromda.core.common.ExceptionUtils;
016: import org.andromda.core.common.ResourceUtils;
017: import org.andromda.core.configuration.Namespaces;
018: import org.andromda.core.namespace.NamespaceRegistry;
019: import org.apache.commons.lang.StringUtils;
020:
021: /**
022: * Discovers all metafacade interfaces and implementation classes in each namespace registry. This class is
023: * then used to retrieve both the appropriate metafacade interface and/or metafacade implementation class based
024: * on one or the other.
025: *
026: * @author Chad Brandon
027: */
028: public class MetafacadeImpls {
029: /**
030: * The shared instance.
031: */
032: private static final MetafacadeImpls instance = new MetafacadeImpls();
033:
034: /**
035: * Stores each metafacade classes instance keyed by namespace.
036: */
037: private final Map metafacadeClasses = new LinkedHashMap();
038:
039: /**
040: * Returns the shared instance of this class.
041: *
042: * @return MetafacadeImpls the shared instance.
043: */
044: public static MetafacadeImpls instance() {
045: return instance;
046: }
047:
048: /**
049: * The current model type to which metafacade class retrieval applies.
050: */
051: private String metafacadeModelNamespace;
052:
053: /**
054: * Sets the current model type to which this instance's metafacade class retrieval
055: * should apply.
056: *
057: * @param metafacadeModelNamespace the namespace that has the metafacade model implementation.
058: */
059: public void setMetafacadeModelNamespace(
060: final String metafacadeModelNamespace) {
061: this .metafacadeModelNamespace = metafacadeModelNamespace;
062: }
063:
064: /**
065: * The extension for the metafacade implementation files.
066: */
067: private final static String METAFACADE_IMPLEMENTATION_SUFFIX = MetafacadeConstants.METAFACADE_IMPLEMENTATION_SUFFIX
068: + ClassUtils.CLASS_EXTENSION;
069:
070: /**
071: * Discovers and loads all metafacade implementation classes and interfaces in each avaiable namespace registry into
072: * each given namespace in the <code>modelTypeNamespaces</code> list.
073: * Note that this method must be called before any metafacade implementation classes will be able to be retrieved
074: * when calling {@link #getMetafacadeClass(String)}or {@link #getMetafacadeImplClass(String)}.
075: *
076: * @param metafacadeModelNamespaces a list of each namespace containing a metafacade model facade implementation.
077: */
078: public void discover(final String[] metafacadeModelNamespaces) {
079: ExceptionUtils.checkNull("modelTypes",
080: metafacadeModelNamespaces);
081: final List modelNamespaces = new ArrayList(Arrays
082: .asList(metafacadeModelNamespaces));
083: final int numberOfModelTypes = metafacadeModelNamespaces.length;
084: for (int ctr = 0; ctr < numberOfModelTypes; ctr++) {
085: final String modelNamespace = metafacadeModelNamespaces[ctr];
086: if (modelNamespace != null) {
087: // - remove the current model type so that we don't keep out the namespace
088: // that stores the metafacade model
089: modelNamespaces.remove(modelNamespace);
090:
091: MetafacadeClasses metafacadeClasses = (MetafacadeClasses) this .metafacadeClasses
092: .get(modelNamespace);
093: if (metafacadeClasses == null) {
094: metafacadeClasses = new MetafacadeClasses();
095: this .metafacadeClasses.put(modelNamespace,
096: metafacadeClasses);
097: }
098: metafacadeClasses.clear();
099: try {
100: final Namespaces namespacesConfiguration = Namespaces
101: .instance();
102: for (final Iterator iterator = namespacesConfiguration
103: .getNamespaceRegistries().iterator(); iterator
104: .hasNext();) {
105: final NamespaceRegistry namespaceRegistry = (NamespaceRegistry) iterator
106: .next();
107: final String namespaceRegistryName = namespaceRegistry
108: .getName();
109: if (!modelNamespaces
110: .contains(namespaceRegistryName)) {
111: this .registerMetafacadeClasses(
112: metafacadeClasses,
113: namespacesConfiguration,
114: namespaceRegistry);
115: }
116: }
117: } catch (final Throwable throwable) {
118: throw new MetafacadeImplsException(throwable);
119: }
120:
121: // - add the metafacade model namespace back
122: modelNamespaces.add(modelNamespace);
123: }
124: }
125: }
126:
127: /**
128: * Registers the metafacade classes for the given <code>namespaceRegistry</code>.
129: *
130: * @param metafacadeClasses the metafacade classes instance to store the registered metafacade classes.
131: * @param namespaces the namespaces from which we retrieve the additional namespace information.
132: * @param namespaceRegistry the registry from which we retrieve the classes.
133: */
134: private void registerMetafacadeClasses(
135: final MetafacadeClasses metafacadeClasses,
136: final Namespaces namespaces,
137: final NamespaceRegistry namespaceRegistry) {
138: final String namespaceRegistryName = namespaceRegistry
139: .getName();
140: if (namespaces.isComponentPresent(namespaceRegistryName,
141: Constants.COMPONENT_METAFACADES)) {
142: final URL[] namespaceRoots = namespaceRegistry
143: .getResourceRoots();
144: if (namespaceRoots != null && namespaceRoots.length > 0) {
145: final int numberOfNamespaceRoots = namespaceRoots.length;
146: for (int ctr = 0; ctr < numberOfNamespaceRoots; ctr++) {
147: final URL namespaceRoot = namespaceRoots[ctr];
148: final Collection contents = ResourceUtils
149: .getDirectoryContents(namespaceRoot, false,
150: null);
151: for (final Iterator contentsIterator = contents
152: .iterator(); contentsIterator.hasNext();) {
153: final String path = ((String) contentsIterator
154: .next());
155: if (path
156: .endsWith(METAFACADE_IMPLEMENTATION_SUFFIX)) {
157: final String typeName = StringUtils
158: .replace(ResourceUtils
159: .normalizePath(path)
160: .replace('/', '.'),
161: ClassUtils.CLASS_EXTENSION,
162: "");
163: Class implementationClass = null;
164: try {
165: implementationClass = ClassUtils
166: .loadClass(typeName);
167: } catch (final Exception exception) {
168: // - ignore
169: }
170: if (implementationClass != null
171: && MetafacadeBase.class
172: .isAssignableFrom(implementationClass)) {
173: final List allInterfaces = ClassUtils
174: .getInterfaces(implementationClass);
175: if (!allInterfaces.isEmpty()) {
176: final Class interfaceClass = (Class) allInterfaces
177: .iterator().next();
178: final String implementationClassName = implementationClass
179: .getName();
180: final String interfaceClassName = interfaceClass
181: .getName();
182: metafacadeClasses.metafacadesByImpls
183: .put(
184: implementationClassName,
185: interfaceClassName);
186: metafacadeClasses.implsByMetafacades
187: .put(interfaceClassName,
188: implementationClassName);
189: }
190: }
191: }
192: }
193: }
194: }
195: }
196: }
197:
198: /**
199: * Attempts to retrieve the metafacade classes instance with the current active namespace
200: * and throws an exception if one can not be found.
201: *
202: * @return the metafacade classes instance.
203: */
204: private MetafacadeClasses getMetafacadeClasses() {
205: final MetafacadeClasses classes = (MetafacadeClasses) this .metafacadeClasses
206: .get(this .metafacadeModelNamespace);
207: if (classes == null) {
208: throw new MetafacadeImplsException(
209: "Namespace '"
210: + this .metafacadeModelNamespace
211: + "' is not a registered metafacade model facade namespace");
212: }
213: return classes;
214: }
215:
216: /**
217: * Retrieves the metafacade class from the passed in <code>metafacadeImplClass</code>. Will return a
218: * MetafacadeImplsException if a metafacade class can not be found for the <code>metafacadeImplClass</code>
219: *
220: * @param metafacadeImplClass the name of the metafacade implementation class.
221: * @return the metafacacade Class
222: */
223: public Class getMetafacadeClass(final String metafacadeImplClass) {
224: ExceptionUtils.checkEmpty("metafacadeImplClass",
225: metafacadeImplClass);
226: return this .getMetafacadeClasses().getMetafacadeClass(
227: metafacadeImplClass);
228: }
229:
230: /**
231: * Retrieves the metafacade implementation class from the passed in <code>metafacadeClass</code>. Will return a
232: * MetafacadeImplsException if a metafacade implementation class can not be found for the
233: * <code>metafacadeClass</code>
234: *
235: * @param metafacadeClass the name of the metafacade class.
236: * @return the metafacacade implementation Class
237: */
238: public Class getMetafacadeImplClass(final String metafacadeClass) {
239: ExceptionUtils.checkEmpty("metafacadeClass", metafacadeClass);
240: return this .getMetafacadeClasses().getMetafacadeImplClass(
241: metafacadeClass);
242: }
243:
244: /**
245: * Stores the metafacade interface and implementation classes.
246: */
247: static final class MetafacadeClasses {
248: /**
249: * Stores all <code>metafacade</code> implementation classes keyed by <code>metafacade</code> interface class.
250: */
251: Map implsByMetafacades = new LinkedHashMap();
252:
253: /**
254: * Stores all <code>metafacade</code> interface classes keyed by <code>metafacade</code> implementation class.
255: */
256: Map metafacadesByImpls = new LinkedHashMap();
257:
258: /**
259: * Retrieves the metafacade class from the passed in <code>metafacadeImplClass</code>. Will return a
260: * MetafacadeImplsException if a metafacade class can not be found for the <code>metafacadeImplClass</code>
261: *
262: * @param metafacadeImplClass the name of the metafacade implementation class.
263: * @return the metafacacade Class
264: */
265: Class getMetafacadeClass(final String metafacadeImplClass) {
266: ExceptionUtils.checkEmpty("metafacadeImplClass",
267: metafacadeImplClass);
268: Class metafacadeClass = null;
269: try {
270: final String metafacadeClassName = (String) this .metafacadesByImpls
271: .get(metafacadeImplClass);
272: if (StringUtils.isEmpty(metafacadeClassName)) {
273: throw new MetafacadeImplsException(
274: "Can not find a metafacade interface for --> '"
275: + metafacadeImplClass
276: + "', check your classpath");
277: }
278: metafacadeClass = ClassUtils
279: .loadClass(metafacadeClassName);
280: } catch (final Throwable throwable) {
281: throw new MetafacadeImplsException(throwable);
282: }
283: return metafacadeClass;
284: }
285:
286: /**
287: * Retrieves the metafacade implementation class from the passed in <code>metafacadeClass</code>. Will return a
288: * MetafacadeImplsException if a metafacade implementation class can not be found for the
289: * <code>metafacadeClass</code>
290: *
291: * @param metafacadeClass the name of the metafacade class.
292: * @return the metafacacade implementation Class
293: */
294: Class getMetafacadeImplClass(final String metafacadeClass) {
295: ExceptionUtils.checkEmpty("metafacadeClass",
296: metafacadeClass);
297: Class metafacadeImplementationClass = null;
298: try {
299: final String metafacadeImplementationClassName = (String) this .implsByMetafacades
300: .get(metafacadeClass);
301: if (StringUtils
302: .isEmpty(metafacadeImplementationClassName)) {
303: throw new MetafacadeImplsException(
304: "Can not find a metafacade implementation class for --> '"
305: + metafacadeClass
306: + "' check your classpath");
307: }
308: metafacadeImplementationClass = ClassUtils
309: .loadClass(metafacadeImplementationClassName);
310: } catch (final Throwable throwable) {
311: throw new MetafacadeImplsException(throwable);
312: }
313: return metafacadeImplementationClass;
314: }
315:
316: /**
317: * Clears each map of any classes it contains.
318: */
319: void clear() {
320: this .metafacadesByImpls.clear();
321: this .implsByMetafacades.clear();
322: }
323:
324: /**
325: * @see java.lang.Object#toString()
326: */
327: public String toString() {
328: return super .toString() + "[" + this .metafacadesByImpls
329: + "]";
330: }
331: }
332: }
|