001: package org.andromda.core.configuration;
002:
003: import java.io.Serializable;
004: import java.net.URL;
005: import java.util.Collection;
006: import java.util.LinkedHashMap;
007: import java.util.Map;
008:
009: import org.andromda.core.common.ExceptionUtils;
010: import org.andromda.core.namespace.NamespaceComponent;
011: import org.andromda.core.namespace.NamespaceRegistry;
012: import org.andromda.core.namespace.PropertyDefinition;
013: import org.apache.log4j.Logger;
014:
015: /**
016: * Directory of configurable Namespace objects. Namespace objects are used for configuring AndroMDA
017: * namespaces.
018: *
019: * @author Chad Brandon
020: * @see org.andromda.core.configuration.Namespace
021: */
022: public class Namespaces implements Serializable {
023: /**
024: * The logger instance.
025: */
026: private static final Logger logger = Logger
027: .getLogger(Namespaces.class);
028:
029: /**
030: * This is passed as the cartridge name for the {@link #getProperty} method if we wish to use a 'default' Namespace
031: * for Plugins. This is so we don't need to define a specific mapping for each Plugin if we don't want. If a
032: * namespaceName exists with a specific Plugin name, then that will be used instead of the 'default'
033: */
034: public static final String DEFAULT = "default";
035:
036: /**
037: * Stores all namespaces.
038: */
039: private final Map namespaces = new LinkedHashMap();
040:
041: /**
042: * The shared instance.
043: */
044: private static Namespaces instance = null;
045:
046: /**
047: * Returns the singleton instance of this Namespaces
048: *
049: * @return instance.
050: */
051: public static Namespaces instance() {
052: if (instance == null) {
053: instance = new Namespaces();
054: }
055: return instance;
056: }
057:
058: /**
059: * Gets the namespaces registered in this namespaces instance.
060: *
061: * @return all namespaces.
062: */
063: public Collection getNamespaces() {
064: return this .namespaces.values();
065: }
066:
067: /**
068: * Adds a namespace to this collection of namespaces.
069: *
070: * @param namespace the Namespace to add to this instance.
071: */
072: public void addNamespace(final Namespace namespace) {
073: this .namespaces.put(namespace.getName(), namespace);
074: }
075:
076: /**
077: * Adds all <code>namespaces</code> to this instance.
078: *
079: * @param namespaces the array of namespaces to add.
080: */
081: public void addNamespaces(final Namespace[] namespaces) {
082: if (namespaces != null && namespaces.length > 0) {
083: final int namespaceNumber = namespaces.length;
084: for (int ctr = 0; ctr < namespaceNumber; ctr++) {
085: this .addNamespace(namespaces[ctr]);
086: }
087: }
088: }
089:
090: /**
091: * Gets the Namespace with the corresponding <code>namespaceName</code>.
092: *
093: * @param namespaceName
094: * @return the found Namespace
095: */
096: public Namespace getNamespace(final String namespaceName) {
097: return (Namespace) namespaces.get(namespaceName);
098: }
099:
100: /**
101: * Indicates if the namespace is present within this instance.
102: *
103: * @param namespaceName the name of the namespace.
104: * @return true/false
105: */
106: public boolean namespacePresent(final String namespaceName) {
107: return this .getNamespace(namespaceName) != null;
108: }
109:
110: /**
111: * Retrieves a property from the Namespace with the namespaceName. If the <code>ignore</code> attribute of the
112: * Property instance is set to <code>true</code> then lookup of the property will not be attempted and null will
113: * just be returned instead. If the propety is not found and <code>ignore<code> is not <code>true</code> a warning
114: * message is logged.
115: *
116: * @param namespaceName name of the Plugin to which the namespace applies
117: * @param propertyName name of the namespace property to find.
118: * @return String the namespace property value.
119: */
120: public Property getProperty(final String namespaceName,
121: final String propertyName) {
122: return this .getProperty(namespaceName, propertyName, true);
123: }
124:
125: /**
126: * Retrieves a property from the Namespace with the namespaceName. If the <code>ignore</code> attribute of the
127: * Property instance is set to <code>true</code> then lookup of the property will not be attempted and null will
128: * just be returned instead.
129: *
130: * @param namespaceName name of the Plugin to which the namespace applies
131: * @param propertyName name of the namespace property to find.
132: * @param showWarning true/false if we'd like to display a warning if the property/namespace can not be found.
133: * @return String the namespace property value.
134: */
135: public Property getProperty(final String namespaceName,
136: final String propertyName, final boolean showWarning) {
137: ExceptionUtils.checkEmpty("namespaceName", namespaceName);
138: ExceptionUtils.checkEmpty("propertyName", propertyName);
139:
140: Property property = null;
141: final Namespace namespace = (Namespace) namespaces
142: .get(namespaceName);
143: if (namespace != null) {
144: property = namespace.getProperty(propertyName);
145: }
146:
147: // - since we couldn't find a Namespace for the specified cartridge,
148: // try to lookup the default
149: Namespace defaultNamespace = null;
150: if (property == null) {
151: if (logger.isDebugEnabled()) {
152: logger.debug("no namespace with name '" + namespaceName
153: + "' found, looking for '" + Namespaces.DEFAULT
154: + "'");
155: }
156: defaultNamespace = (Namespace) namespaces
157: .get(Namespaces.DEFAULT);
158: if (defaultNamespace != null) {
159: property = defaultNamespace.getProperty(propertyName);
160: }
161: }
162:
163: if (namespace == null && defaultNamespace == null
164: && showWarning) {
165: logger
166: .warn("WARNING! No '"
167: + DEFAULT
168: + "' or '"
169: + namespaceName
170: + "' namespace found, "
171: + "--> please define a namespace with at least one of these names, if you would like "
172: + "to ignore this message, define the namespace with "
173: + "ignore set to 'true'");
174: } else if (property == null && showWarning) {
175: logger
176: .warn("WARNING! Namespaces '"
177: + DEFAULT
178: + "' and '"
179: + namespaceName
180: + "' have no property '"
181: + propertyName
182: + "' defined --> please define this property in AT LEAST ONE of these two namespaces. "
183: + " If you want to 'ignore' this message, add the property to the namespace with ignore set to 'true'");
184: }
185: return property;
186: }
187:
188: /**
189: * Retrieves all property definitions for the given namespace.
190: *
191: * @param namespaceName the name of the namespace.
192: * @return the list of properties contained in the namespace.
193: */
194: public PropertyDefinition[] getPropertyDefinitions(
195: final String namespaceName) {
196: final NamespaceRegistry registry = this
197: .getRegistry(namespaceName);
198: return registry == null ? new PropertyDefinition[0] : registry
199: .getPropertyDefinitions();
200: }
201:
202: /**
203: * Stores the namespace registries
204: */
205: private final Map registries = new LinkedHashMap();
206:
207: /**
208: * Gets all available namespace registries (these are namespaces
209: * which have been discovered but are not necessarily configured).
210: *
211: * @return the collection of namespace registries
212: */
213: public Collection getNamespaceRegistries() {
214: return this .registries.values();
215: }
216:
217: /**
218: * Adds a namespace registry to this instance. Namespace registries contain
219: * property definitions that are defined within a {@link NamespaceRegistry}
220: * descriptor (used to describe {@link NamespaceComponent}) instances.
221: *
222: * @param registry the {@link NamespaceRegistry} instance to add.
223: */
224: public void addRegistry(final NamespaceRegistry registry) {
225: if (registry != null) {
226: // - first add the registry directly under its own name
227: this .registries.put(registry.getName(), registry);
228:
229: // - if the registry is shared, we add the registry to the default namespace as well
230: if (registry.isShared()) {
231: NamespaceRegistry defaultRegistry = this
232: .getRegistry(Namespaces.DEFAULT);
233: if (defaultRegistry == null) {
234: defaultRegistry = registry;
235: } else {
236: defaultRegistry.addPropertyDefinitions(registry
237: .getPropertyDefinitions());
238: }
239: this .registries
240: .put(Namespaces.DEFAULT, defaultRegistry);
241: }
242: }
243: }
244:
245: /**
246: * Indicates if the given <code>namespace</code> is
247: * shared or not.
248: *
249: * @param namespace the namespace to check.
250: * @return true/false.
251: */
252: public boolean isShared(final String namespace) {
253: final NamespaceRegistry registry = this .getRegistry(namespace);
254: return registry != null && registry.isShared();
255: }
256:
257: /**
258: * Attempts to get the value of a property from the given
259: * <code>namespace</code> with the given <code>name</code> by first attempting
260: * to retrieve it from the namespace and if no property is defined
261: * in the namespace we retrieve the default value (if one is defined).
262: *
263: * @param namespace the namespace for which to retreive the value.
264: * @param name the name of the value to retrieve.
265: * @return the value (or null if one couldn't be retrieved).
266: */
267: public String getPropertyValue(final String namespace,
268: final String name) {
269: final PropertyDefinition definition = this
270: .getPropertyDefinition(namespace, name);
271: if (definition == null) {
272: throw new NamespacesException("Property '" + name
273: + "' is not registered in either the '" + namespace
274: + "' or '" + Namespaces.DEFAULT + "' namespaces");
275: }
276: final String defaultValue = definition.getDefaultValue();
277: boolean warning = defaultValue == null
278: && definition.isRequired();
279: final Property property = this .getProperty(namespace, name,
280: warning);
281: return property != null && !property.isIgnore() ? property
282: .getValue() : defaultValue;
283: }
284:
285: /**
286: * Attempts to retrieve the resource root of the namespace. The resource root is the directory
287: * or archive root which contains all namespace resources.
288: *
289: * @param namespace the namespace of which to retrieve the resource.
290: * @return the resource or null if it could not be found.
291: */
292: public URL[] getResourceRoots(final String namespace) {
293: final NamespaceRegistry registry = this .getRegistry(namespace);
294: if (registry == null) {
295: throw new NamespacesException("'" + namespace
296: + "' is not a registered namespace");
297: }
298:
299: final URL[] resourceRoots = registry.getResourceRoots();
300: if (resourceRoots == null || resourceRoots.length == 0) {
301: throw new NamespacesException(
302: "No resource root(s) could be retrieved for namespace '"
303: + namespace + "'");
304: }
305: return resourceRoots;
306: }
307:
308: /**
309: * Indicates whether or not the <code>component</code> is present within the given
310: * <code>namespace</code>
311: * @param namespace the name of the namespace.
312: * @param component the name of the component type.
313: * @return true/false
314: */
315: public boolean isComponentPresent(final String namespace,
316: final String component) {
317: boolean present = false;
318: final NamespaceRegistry registry = this .getRegistry(namespace);
319: if (namespace != null && component != null && registry != null) {
320: final String[] components = registry
321: .getRegisteredComponents();
322: final int numberOfComponents = components.length;
323: for (int ctr = 0; ctr < numberOfComponents; ctr++) {
324: if (component.equals(components[ctr])) {
325: present = true;
326: break;
327: }
328: }
329: }
330: return present;
331: }
332:
333: /**
334: * Attempts to get the value of a property from the given
335: * <code>namespace</code> with the given <code>name</code> by first attempting
336: * to retreive it from the namespace and if no property is defined
337: * in the namespace we retrieve the default value (if one is defined).
338: *
339: * @param namespace the namespace for which to retreive the value.
340: * @param name the name of the value to retrieve.
341: * @return the value (or null if one couldn't be retrieved).
342: */
343: private PropertyDefinition getPropertyDefinition(
344: final String namespace, final String name) {
345: final NamespaceRegistry registry = this .getRegistry(namespace);
346: PropertyDefinition definition = null;
347: if (registry != null) {
348: definition = registry.getPropertyDefinition(name);
349: }
350: if (definition == null) {
351: final NamespaceRegistry defaultRegistry = this
352: .getRegistry(Namespaces.DEFAULT);
353: if (defaultRegistry != null) {
354: definition = defaultRegistry
355: .getPropertyDefinition(name);
356: }
357: }
358: return definition;
359: }
360:
361: /**
362: * Retrieves the namespace registry for the given namespace, or returns null
363: * if it doesn't exist.
364: *
365: * @param namespace the namespace name.
366: * @return the registry, or null if not found.
367: */
368: public NamespaceRegistry getRegistry(final String namespace) {
369: return (NamespaceRegistry) this .registries.get(namespace);
370: }
371:
372: /**
373: * Clears out the current namespaces.
374: */
375: public void clear() {
376: this.namespaces.clear();
377: }
378: }
|