View Javadoc

1   package org.andromda.core.configuration;
2   
3   import java.io.Serializable;
4   import java.net.URL;
5   import java.util.Collection;
6   import java.util.LinkedHashMap;
7   import java.util.Map;
8   
9   import org.andromda.core.common.ExceptionUtils;
10  import org.andromda.core.namespace.NamespaceComponent;
11  import org.andromda.core.namespace.NamespaceRegistry;
12  import org.andromda.core.namespace.PropertyDefinition;
13  import org.apache.log4j.Logger;
14  
15  
16  /***
17   * Directory of configurable Namespace objects. Namespace objects are used for configuring AndroMDA
18   * namespaces.
19   *
20   * @author Chad Brandon
21   * @see org.andromda.core.configuration.Namespace
22   */
23  public class Namespaces
24      implements Serializable
25  {
26      /***
27       * The logger instance.
28       */
29      private static final Logger logger = Logger.getLogger(Namespaces.class);
30  
31      /***
32       * This is passed as the cartridge name for the {@link #getProperty} method if we wish to use a 'default' Namespace
33       * for Plugins. This is so we don't need to define a specific mapping for each Plugin if we don't want. If a
34       * namespaceName exists with a specific Plugin name, then that will be used instead of the 'default'
35       */
36      public static final String DEFAULT = "default";
37  
38      /***
39       * Stores all namespaces.
40       */
41      private final Map namespaces = new LinkedHashMap();
42  
43      /***
44       * The shared instance.
45       */
46      private static Namespaces instance = null;
47  
48      /***
49       * Returns the singleton instance of this Namespaces
50       *
51       * @return instance.
52       */
53      public static Namespaces instance()
54      {
55          if (instance == null)
56          {
57              instance = new Namespaces();
58          }
59          return instance;
60      }
61  
62      /***
63       * Gets the namespaces registered in this namespaces instance.
64       *
65       * @return all namespaces.
66       */
67      public Collection getNamespaces()
68      {
69          return this.namespaces.values();
70      }
71  
72      /***
73       * Adds a namespace to this collection of namespaces.
74       *
75       * @param namespace the Namespace to add to this instance.
76       */
77      public void addNamespace(final Namespace namespace)
78      {
79          this.namespaces.put(
80              namespace.getName(),
81              namespace);
82      }
83  
84      /***
85       * Adds all <code>namespaces</code> to this instance.
86       *
87       * @param namespaces the array of namespaces to add.
88       */
89      public void addNamespaces(final Namespace[] namespaces)
90      {
91          if (namespaces != null && namespaces.length > 0)
92          {
93              final int namespaceNumber = namespaces.length;
94              for (int ctr = 0; ctr < namespaceNumber; ctr++)
95              {
96                  this.addNamespace(namespaces[ctr]);
97              }
98          }
99      }
100 
101     /***
102      * Gets the Namespace with the corresponding <code>namespaceName</code>.
103      *
104      * @param namespaceName
105      * @return the found Namespace
106      */
107     public Namespace getNamespace(final String namespaceName)
108     {
109         return (Namespace)namespaces.get(namespaceName);
110     }
111 
112     /***
113      * Indicates if the namespace is present within this instance.
114      *
115      * @param namespaceName the name of the namespace.
116      * @return true/false
117      */
118     public boolean namespacePresent(final String namespaceName)
119     {
120         return this.getNamespace(namespaceName) != null;
121     }
122 
123     /***
124      * Retrieves a property from the Namespace with the namespaceName. If the <code>ignore</code> attribute of the
125      * Property instance is set to <code>true</code> then lookup of the property will not be attempted and null will
126      * just be returned instead. If the propety is not found and <code>ignore<code> is not <code>true</code> a warning
127      * message is logged.
128      *
129      * @param namespaceName name of the Plugin to which the namespace applies
130      * @param propertyName  name of the namespace property to find.
131      * @return String the namespace property value.
132      */
133     public Property getProperty(
134         final String namespaceName,
135         final String propertyName)
136     {
137         return this.getProperty(
138             namespaceName,
139             propertyName,
140             true);
141     }
142 
143     /***
144      * Retrieves a property from the Namespace with the namespaceName. If the <code>ignore</code> attribute of the
145      * Property instance is set to <code>true</code> then lookup of the property will not be attempted and null will
146      * just be returned instead.
147      *
148      * @param namespaceName name of the Plugin to which the namespace applies
149      * @param propertyName  name of the namespace property to find.
150      * @param showWarning   true/false if we'd like to display a warning if the property/namespace can not be found.
151      * @return String the namespace property value.
152      */
153     public Property getProperty(
154         final String namespaceName,
155         final String propertyName,
156         final boolean showWarning)
157     {
158         ExceptionUtils.checkEmpty(
159             "namespaceName",
160             namespaceName);
161         ExceptionUtils.checkEmpty(
162             "propertyName",
163             propertyName);
164 
165         Property property = null;
166         final Namespace namespace = (Namespace)namespaces.get(namespaceName);
167         if (namespace != null)
168         {
169             property = namespace.getProperty(propertyName);
170         }
171 
172         // - since we couldn't find a Namespace for the specified cartridge,
173         //   try to lookup the default
174         Namespace defaultNamespace = null;
175         if (property == null)
176         {
177             if (logger.isDebugEnabled())
178             {
179                 logger.debug("no namespace with name '" + namespaceName + "' found, looking for '" + Namespaces.DEFAULT + "'");
180             }
181             defaultNamespace = (Namespace)namespaces.get(Namespaces.DEFAULT);
182             if (defaultNamespace != null)
183             {
184                 property = defaultNamespace.getProperty(propertyName);
185             }
186         }
187 
188         if (namespace == null && defaultNamespace == null && showWarning)
189         {
190             logger.warn(
191                 "WARNING! No '" + DEFAULT + "' or '" + namespaceName + "' namespace found, " +
192                 "--> please define a namespace with at least one of these names, if you would like " +
193                 "to ignore this message, define the namespace with " + "ignore set to 'true'");
194         }
195         else if (property == null && showWarning)
196         {
197             logger.warn(
198                 "WARNING! Namespaces '" + DEFAULT + "' and '" + namespaceName + "' have no property '" + propertyName +
199                 "' defined --> please define this property in AT LEAST ONE of these two namespaces. " +
200                 " If you want to 'ignore' this message, add the property to the namespace with ignore set to 'true'");
201         }
202         return property;
203     }
204     
205     /***
206      * Retrieves all property definitions for the given namespace.
207      * 
208      * @param namespaceName the name of the namespace.
209      * @return the list of properties contained in the namespace.
210      */
211     public PropertyDefinition[] getPropertyDefinitions(final String namespaceName)
212     {
213         final NamespaceRegistry registry = this.getRegistry(namespaceName);
214         return registry == null ? new PropertyDefinition[0] : registry.getPropertyDefinitions();
215     }
216 
217     /***
218      * Stores the namespace registries
219      */
220     private final Map registries = new LinkedHashMap();
221 
222     /***
223      * Gets all available namespace registries (these are namespaces
224      * which have been discovered but are not necessarily configured).
225      *
226      * @return the collection of namespace registries
227      */
228     public Collection getNamespaceRegistries()
229     {
230         return this.registries.values();
231     }
232 
233     /***
234      * Adds a namespace registry to this instance.  Namespace registries contain
235      * property definitions that are defined within a {@link NamespaceRegistry}
236      * descriptor (used to describe {@link NamespaceComponent}) instances.
237      *
238      * @param registry the {@link NamespaceRegistry} instance to add.
239      */
240     public void addRegistry(final NamespaceRegistry registry)
241     {
242         if (registry != null)
243         {
244             // - first add the registry directly under its own name
245             this.registries.put(
246                 registry.getName(),
247                 registry);
248 
249             // - if the registry is shared, we add the registry to the default namespace as well
250             if (registry.isShared())
251             {
252                 NamespaceRegistry defaultRegistry = this.getRegistry(Namespaces.DEFAULT);
253                 if (defaultRegistry == null)
254                 {
255                     defaultRegistry = registry;
256                 }
257                 else
258                 {
259                     defaultRegistry.addPropertyDefinitions(registry.getPropertyDefinitions());
260                 }
261                 this.registries.put(
262                     Namespaces.DEFAULT,
263                     defaultRegistry);
264             }
265         }
266     }
267 
268     /***
269      * Indicates if the given <code>namespace</code> is
270      * shared or not.
271      *
272      * @param namespace the namespace to check.
273      * @return true/false.
274      */
275     public boolean isShared(final String namespace)
276     {
277         final NamespaceRegistry registry = this.getRegistry(namespace);
278         return registry != null && registry.isShared();
279     }
280 
281     /***
282      * Attempts to get the value of a property from the given
283      * <code>namespace</code> with the given <code>name</code> by first attempting
284      * to retrieve it from the namespace and if no property is defined
285      * in the namespace we retrieve the default value (if one is defined).
286      *
287      * @param namespace the namespace for which to retreive the value.
288      * @param name the name of the value to retrieve.
289      * @return the value (or null if one couldn't be retrieved).
290      */
291     public String getPropertyValue(
292         final String namespace,
293         final String name)
294     {
295         final PropertyDefinition definition = this.getPropertyDefinition(
296                 namespace,
297                 name);
298         if (definition == null)
299         {
300             throw new NamespacesException("Property '" + name + "' is not registered in either the '" + namespace +
301                 "' or '" + Namespaces.DEFAULT + "' namespaces");
302         }
303         final String defaultValue = definition.getDefaultValue();
304         boolean warning = defaultValue == null && definition.isRequired();
305         final Property property = this.getProperty(
306                 namespace,
307                 name,
308                 warning);
309         return property != null && !property.isIgnore() ? property.getValue() : defaultValue;
310     }
311 
312     /***
313      * Attempts to retrieve the resource root of the namespace. The resource root is the directory
314      * or archive root which contains all namespace resources.
315      *
316      * @param namespace the namespace of which to retrieve the resource.
317      * @return the resource or null if it could not be found.
318      */
319     public URL[] getResourceRoots(final String namespace)
320     {
321         final NamespaceRegistry registry = this.getRegistry(namespace);
322         if (registry == null)
323         {
324             throw new NamespacesException("'" + namespace + "' is not a registered namespace");
325         }
326 
327         final URL[] resourceRoots = registry.getResourceRoots();
328         if (resourceRoots == null || resourceRoots.length == 0)
329         {
330             throw new NamespacesException("No resource root(s) could be retrieved for namespace '" + namespace + "'");
331         }
332         return resourceRoots;
333     }
334 
335     /***
336      * Indicates whether or not the <code>component</code> is present within the given
337      * <code>namespace</code>
338      * @param namespace the name of the namespace.
339      * @param component the name of the component type.
340      * @return true/false
341      */
342     public boolean isComponentPresent(
343         final String namespace,
344         final String component)
345     {
346         boolean present = false;
347         final NamespaceRegistry registry = this.getRegistry(namespace);
348         if (namespace != null && component != null && registry != null)
349         {
350             final String[] components = registry.getRegisteredComponents();
351             final int numberOfComponents = components.length;
352             for (int ctr = 0; ctr < numberOfComponents; ctr++)
353             {
354                 if (component.equals(components[ctr]))
355                 {
356                     present = true;
357                     break;
358                 }
359             }
360         }
361         return present;
362     }
363 
364     /***
365      * Attempts to get the value of a property from the given
366      * <code>namespace</code> with the given <code>name</code> by first attempting
367      * to retreive it from the namespace and if no property is defined
368      * in the namespace we retrieve the default value (if one is defined).
369      *
370      * @param namespace the namespace for which to retreive the value.
371      * @param name the name of the value to retrieve.
372      * @return the value (or null if one couldn't be retrieved).
373      */
374     private PropertyDefinition getPropertyDefinition(
375         final String namespace,
376         final String name)
377     {
378         final NamespaceRegistry registry = this.getRegistry(namespace);
379         PropertyDefinition definition = null;
380         if (registry != null)
381         {
382             definition = registry.getPropertyDefinition(name);
383         }
384         if (definition == null)
385         {
386             final NamespaceRegistry defaultRegistry = this.getRegistry(Namespaces.DEFAULT);
387             if (defaultRegistry != null)
388             {
389                 definition = defaultRegistry.getPropertyDefinition(name);
390             }
391         }
392         return definition;
393     }
394 
395     /***
396      * Retrieves the namespace registry for the given namespace, or returns null
397      * if it doesn't exist.
398      *
399      * @param namespace the namespace name.
400      * @return the registry, or null if not found.
401      */
402     public NamespaceRegistry getRegistry(final String namespace)
403     {
404         return (NamespaceRegistry)this.registries.get(namespace);
405     }
406 
407     /***
408      * Clears out the current namespaces.
409      */
410     public void clear()
411     {
412         this.namespaces.clear();
413     }
414 }