View Javadoc
1   package org.andromda.core.metafacade;
2   
3   import java.io.Serializable;
4   import java.util.ArrayList;
5   import java.util.Collection;
6   import java.util.LinkedHashMap;
7   import java.util.LinkedHashSet;
8   import java.util.List;
9   import java.util.Map;
10  import org.andromda.core.common.AndroMDALogger;
11  import org.andromda.core.common.ExceptionUtils;
12  import org.andromda.core.profile.Profile;
13  import org.apache.commons.collections.keyvalue.MultiKey;
14  import org.apache.commons.lang.StringUtils;
15  import org.apache.log4j.Logger;
16  
17  /**
18   * The factory in charge of constructing Metafacade instances. In order for a
19   * metafacade (i.e. a facade around a meta model element) to be constructed, it
20   * must be constructed through this factory.
21   *
22   * @author <a href="http://www.mbohlen.de">Matthias Bohlen </a>
23   * @author Chad Brandon
24   * @author Peter Friese
25   * @author Bob Fields
26   */
27  public final class MetafacadeFactory
28      implements Serializable
29  {
30      private static final long serialVersionUID = 34L;
31  
32      /**
33       * Caches the registered properties used within metafacades.
34       */
35      private final Map<String, Map<String, Map<String, Object>>> metafacadeNamespaces = new LinkedHashMap<String, Map<String, Map<String, Object>>>();
36  
37      /**
38       * The shared instance of this factory.
39       */
40      private static MetafacadeFactory instance = null;
41  
42      private MetafacadeFactory()
43      {
44          // make sure that nobody instantiates it
45      }
46  
47      /**
48       * Returns the facade factory singleton.
49       *
50       * @return the only instance
51       */
52      public static MetafacadeFactory getInstance()
53      {
54          if (instance == null)
55          {
56              instance = new MetafacadeFactory();
57          }
58          return instance;
59      }
60  
61      /**
62       * The metafacade cache for this factory.
63       */
64      private final MetafacadeCache cache = MetafacadeCache.newInstance();
65  
66      /**
67       * The metafacade mappings instance for this factory.
68       */
69      private final MetafacadeMappings mappings = MetafacadeMappings.newInstance();
70  
71      /**
72       * Performs any initialization required by the factory (i.e. discovering all
73       * <code>metafacade</code> mappings, etc).
74       */
75      public void initialize()
76      {
77          this.mappings.initialize();
78      }
79  
80      /**
81       * The shared profile instance.
82       */
83      private final Profile profile = Profile.instance();
84  
85      /**
86       * The namespace that is currently active (i.e. being used) within the factory
87       */
88      private String namespace;
89  
90      /**
91       * Sets the active namespace. The AndroMDA core and each cartridge have their own namespace for metafacade
92       * registration.
93       *
94       * @param namespace the name of the active namespace.
95       */
96      public void setNamespace(final String namespace)
97      {
98          this.namespace = namespace;
99          this.profile.setNamespace(namespace);
100         this.cache.setNamespace(this.namespace);
101     }
102 
103     /**
104      * Returns the name of the active namespace.
105      *
106      * @return String the namespace name
107      */
108     public String getNamespace()
109     {
110         if (this.namespace == null)
111         {
112             throw new MetafacadeFactoryException("This metafacade factory's namespace must be populated before " +
113                 "metafacade construction can occur");
114         }
115         return this.namespace;
116     }
117 
118     /**
119      * Returns a metafacade for a mappingObject, depending on its
120      * <code>mappingClass</code> and (optionally) its <code>stereotypes</code>
121      * and <code>context</code>.
122      *
123      * @param mappingObject the object used to map the metafacade (a meta model
124      *        object or a metafacade itself).
125      * @param context the name of the context the meta model element is
126      *        registered under.
127      * @return the new metafacade
128      */
129     public MetafacadeBase createMetafacade(
130         final Object mappingObject,
131         final String context)
132     {
133         return this.createMetafacade(
134             mappingObject,
135             context,
136             null);
137     }
138 
139     /**
140      * Creates a metafacade given the <code>mappingObject</code>,
141      * <code>contextName</code> and <code>metafacadeClass</code>.
142      *
143      * @param mappingObject the object used to map the metafacade (a meta model
144      *        object or a metafacade itself).
145      * @param context the name of the context the meta model element (if the
146      *        mappObject is a meta model element) is registered under.
147      * @param metafacadeClass if not null, it contains the name of the
148      *        metafacade class to be used. This is used ONLY when instantiating
149      *        super metafacades in an inheritance chain. The final metafacade
150      *        will NEVER have a metafacadeClass specified (it will ALWAYS be
151      *        null).
152      * @return the new metafacade
153      */
154     private MetafacadeBase createMetafacade(
155         final Object mappingObject,
156         final String context,
157         Class metafacadeClass)
158     {
159         final String methodName = "MetafacadeFactory.createMetafacade";
160         ExceptionUtils.checkNull(
161             "mappingObject",
162             mappingObject);
163 
164         // - register the namespace properties (if they haven't been)
165         this.registerNamespaceProperties();
166 
167         // if the mappingObject is REALLY a metafacade, just return it
168         if (mappingObject instanceof MetafacadeBase)
169         {
170             return (MetafacadeBase)mappingObject;
171         }
172         try
173         {
174             final Collection<String> stereotypes = this.getModel().getStereotypeNames(mappingObject);
175             if (this.getLogger().isDebugEnabled())
176             {
177                 this.getLogger().debug("mappingObject stereotypes --> '" + stereotypes + '\'');
178             }
179 
180             MetafacadeMapping mapping = null;
181             if (metafacadeClass == null)
182             {
183                 final MetafacadeMappings modelMetafacadeMappings = this.getModelMetafacadeMappings();
184                 mapping = modelMetafacadeMappings.getMetafacadeMapping(
185                     mappingObject,
186                     this.getNamespace(),
187                     context,
188                     stereotypes);
189                 if (this.getLogger().isDebugEnabled())
190                 {
191                     this.getLogger().debug("mappingObject getModelMetafacadeMappings for " + mappingObject + " namespace " + this.getNamespace() + " context " + context);
192                 }
193                 if (mapping != null)
194                 {
195                     metafacadeClass = mapping.getMetafacadeClass();
196                 }
197                 else
198                 {
199                     // get the default since no mapping was found.
200                     metafacadeClass = modelMetafacadeMappings.getDefaultMetafacadeClass(this.getNamespace());
201                     if (this.getLogger().isDebugEnabled())
202                     {
203                         this.getLogger().warn(
204                             "Meta object model class '" + mappingObject.getClass() +
205                             "' has no corresponding meta facade class, default is being used --> '" + metafacadeClass +
206                                     '\'');
207                     }
208                 }
209             }
210 
211             if (metafacadeClass == null)
212             {
213                 throw new MetafacadeMappingsException(methodName + " metafacadeClass was not retrieved from mappings" +
214                     " or specified as an argument in this method for mappingObject --> '" + mappingObject + '\'');
215             }
216             final MetafacadeBase metafacade = this.getMetafacade(
217                     metafacadeClass,
218                     mappingObject,
219                     context,
220                     mapping);
221 
222             // IMPORTANT: initialize each metafacade ONLY once (otherwise we
223             // get stack overflow errors)
224             if (metafacade != null && !metafacade.isInitialized())
225             {
226                 metafacade.setInitialized();
227                 metafacade.initialize();
228             }
229             return metafacade;
230         }
231         catch (final Throwable throwable)
232         {
233             final String message =
234                 "Failed to construct a meta facade of type '" + metafacadeClass + "' with mappingObject of type --> '" +
235                 mappingObject.getClass() + '\'';
236             this.getLogger().error(message);
237             throw new MetafacadeFactoryException(message, throwable);
238         }
239     }
240 
241     /**
242      * Gets the model metafacade mappings (the mappings that correspond
243      * to the current metafacade model namespace).
244      *
245      * @return the model metafacade mappings.
246      */
247     private MetafacadeMappings getModelMetafacadeMappings()
248     {
249         return this.mappings.getModelMetafacadeMappings(this.metafacadeModelNamespace);
250     }
251 
252     /**
253      * Validates all metafacades for the current namespace
254      * and collects the messages in the internal validation messages
255      * collection.
256      *
257      * @see #getValidationMessages()
258      */
259     public void validateAllMetafacades()
260     {
261         for (final MetafacadeBase metafacadeBase : this.getAllMetafacades())
262         {
263             metafacadeBase.validate(this.validationMessages);
264         }
265     }
266 
267     /**
268      * Creates a metafacade from the passed in <code>mappingObject</code>, and
269      * <code>mapping</code> instance.
270      *
271      * @param mappingObject the mapping object for which to create the
272      *        metafacade.
273      * @param mapping the mapping from which to create the metafacade
274      * @return the metafacade, or null if it can't be created.
275      */
276     protected MetafacadeBase createMetafacade(
277         final Object mappingObject,
278         final MetafacadeMapping mapping)
279     {
280         try
281         {
282             return this.getMetafacade(
283                 mapping.getMetafacadeClass(),
284                 mappingObject,
285                 mapping.getContext(),
286                 mapping);
287         }
288         catch (final Throwable throwable)
289         {
290             final String message =
291                 "Failed to construct a meta facade of type '" + mapping.getMetafacadeClass() +
292                 "' with mappingObject of type --> '" + mapping.getMappingClassNames() + '\'';
293             this.getLogger().error(message);
294             throw new MetafacadeFactoryException(message, throwable);
295         }
296     }
297 
298     /**
299      * Retrieves (if one has already been constructed) or constructs a new
300      * <code>metafacade</code> from the given <code>metafacadeClass</code>
301      * and <code>mappingObject</code>.
302      *
303      * @param metafacadeClass the metafacade class.
304      * @param mappingObject the object to which the metafacade is mapped.
305      * @param context the context to which the metafacade applies
306      * @param mapping the optional MetafacadeMapping instance from which the
307      *        metafacade is mapped.
308      * @return the new (or cached) metafacade.
309      * @throws Exception if any error occurs during metafacade creation
310      */
311     private MetafacadeBase getMetafacade(
312         final Class metafacadeClass,
313         final Object mappingObject,
314         final String context,
315         final MetafacadeMapping mapping)
316         throws Exception
317     {
318         MetafacadeBase metafacade = this.cache.get(
319                 mappingObject,
320                 metafacadeClass);
321         if (metafacade == null)
322         {
323             final MultiKey key = new MultiKey(mappingObject, metafacadeClass);
324             if (!this.metafacadesInCreation.contains(key))
325             {
326                 this.metafacadesInCreation.add(
327                     key);
328                 if (mapping != null && mapping.isContextRoot())
329                 {
330                     metafacade = MetafacadeUtils.constructMetafacade(
331                             metafacadeClass,
332                             mappingObject,
333                             null);
334                     // set whether or not this metafacade is a context root
335                     metafacade.setContextRoot(mapping.isContextRoot());
336                 }
337                 else
338                 {
339                     metafacade = MetafacadeUtils.constructMetafacade(
340                             metafacadeClass,
341                             mappingObject,
342                             context);
343                 }
344                 this.metafacadesInCreation.remove(key);
345 
346                 this.cache.add(
347                     mappingObject,
348                     metafacade);
349             }
350         }
351 
352         if (metafacade != null)
353         {
354             // if the requested metafacadeClass is different from the one in the mapping, contextRoot should be reset
355             if (mapping != null && !mapping.getMetafacadeClass().equals(metafacadeClass))
356             {
357                 metafacade.setContextRoot(false);
358                 metafacade.resetMetafacadeContext(context);
359             }
360             // we need to set some things each time
361             // we change a metafacade's namespace
362             final String metafacadeNamespace = metafacade.getMetafacadeNamespace();
363             if (metafacadeNamespace == null || !metafacadeNamespace.equals(this.getNamespace()))
364             {
365                 // assign the logger and active namespace
366                 metafacade.setNamespace(this.getNamespace());
367                 metafacade.setLogger(this.getLogger());
368             }
369         }
370         return metafacade;
371     }
372 
373     /**
374      * Stores the metafacades being created, so that we don't get stuck in
375      * endless recursion during creation.
376      */
377     private final Collection<MultiKey> metafacadesInCreation = new ArrayList<MultiKey>();
378 
379     /**
380      * Returns a metafacade for a mappingObject, depending on its <code>mappingClass</code>.
381      *
382      * @param mappingObject the object which is used to map to the metafacade
383      * @return MetafacadeBase the facade object (not yet attached to mappingClass object)
384      */
385     public MetafacadeBase createMetafacade(final Object mappingObject)
386     {
387         return this.createMetafacade(
388             mappingObject,
389             null,
390             null);
391     }
392 
393     /**
394      * Create a facade implementation object for a mappingObject. The facade
395      * implementation object must be found in a way that it implements the
396      * interface <code>interfaceName</code>.
397      *
398      * @param interfaceName the name of the interface that the implementation
399      *        object has to implement
400      * @param mappingObject the mappingObject for which a facade shall be
401      *        created
402      * @param context the context in which this metafacade will be created.
403      * @return MetafacadeBase the metafacade
404      */
405     public MetafacadeBase createFacadeImpl(
406         final String interfaceName,
407         final Object mappingObject,
408         final String context)
409     {
410         ExceptionUtils.checkEmpty(
411             "interfaceName",
412             interfaceName);
413         ExceptionUtils.checkNull(
414             "mappingObject",
415             mappingObject);
416 
417         Class metafacadeClass = null;
418         try
419         {
420             metafacadeClass = this.metafacadeImpls.getMetafacadeImplClass(interfaceName);
421             return this.createMetafacade(
422                 mappingObject,
423                 context,
424                 metafacadeClass);
425         }
426         catch (final Throwable throwable)
427         {
428             final String message =
429                 "Failed to construct a meta facade of type '" + metafacadeClass + "' with mappingObject of type --> '" +
430                 mappingObject.getClass().getName() + '\'';
431             this.getLogger().error(message);
432             throw new MetafacadeFactoryException(message, throwable);
433         }
434     }
435 
436     /**
437      * Returns a metafacade for each mappingObject, contained within the
438      * <code>mappingObjects</code> collection depending on its
439      * <code>mappingClass</code> and (optionally) its <code>stereotypes</code>,
440      * and <code>contextName</code>.
441      *
442      * @param mappingObjects the meta model element.
443      * @param contextName the name of the context the meta model element is
444      *        registered under.
445      * @return the Collection of newly created Metafacades.
446      */
447     protected Collection<MetafacadeBase> createMetafacades(
448         final Collection mappingObjects,
449         final String contextName)
450     {
451         final Collection<MetafacadeBase> metafacades = new ArrayList<MetafacadeBase>();
452         if (mappingObjects != null && !mappingObjects.isEmpty())
453         {
454             for (final Object mappingObject : mappingObjects)
455             {
456                 if (this.getLogger().isDebugEnabled())
457                 {
458                     this.getLogger().debug("MetafacadeFactory createMetafacade for namespace " + this.getNamespace() + " model " + this.getModel() + " contextName " + contextName + " mappingObject " + mappingObject);
459                 }
460                 metafacades.add(this.createMetafacade(
461                         mappingObject,
462                         contextName,
463                         null));
464             }
465         }
466         return metafacades;
467     }
468 
469     /**
470      * Returns a metafacade for each mappingObject, contained within the
471      * <code>mappingObjects</code> collection depending on its
472      * <code>mappingClass</code>.
473      *
474      * @param mappingObjects the objects used to map the metafacades (can be a
475      *        meta model element or an actual metafacade itself).
476      * @return Collection of metafacades
477      */
478     public Collection<MetafacadeBase> createMetafacades(final Collection mappingObjects)
479     {
480         return this.createMetafacades(
481             mappingObjects,
482             null);
483     }
484 
485     /**
486      * The model facade which provides access to the underlying meta model.
487      */
488     private ModelAccessFacade model;
489 
490     /**
491      * Gets the model which provides access to the underlying model and is used
492      * to construct metafacades.
493      *
494      * @return the model access facade.
495      */
496     public ModelAccessFacade getModel()
497     {
498         if (this.model == null)
499         {
500             throw new MetafacadeFactoryException("This metafacade factory's model must be populated before " +
501                 "metafacade construction can occur");
502         }
503         return this.model;
504     }
505 
506     /**
507      * The shared metafacade impls instance.
508      */
509     private MetafacadeImpls metafacadeImpls = MetafacadeImpls.instance();
510 
511     /**
512      * Stores the namespace that contains the metafacade model implementation.
513      */
514     private String metafacadeModelNamespace;
515 
516     /**
517      * The model access facade instance (provides access to the meta model).
518      *
519      * @param model the model
520      * @param metafacadeModelNamespace the namespace that contains the metafacade facade implementation.
521      */
522     public void setModel(
523         final ModelAccessFacade model,
524         final String metafacadeModelNamespace)
525     {
526         this.metafacadeModelNamespace = metafacadeModelNamespace;
527 
528         // - set the model type as the namespace for the metafacade impls so we have
529         //   access to the correct metafacade classes
530         this.metafacadeImpls.setMetafacadeModelNamespace(metafacadeModelNamespace);
531         this.model = model;
532     }
533 
534     /**
535      * Gets the correct logger based on whether or not an namespace logger should be used
536      *
537      * @return the logger
538      */
539     final Logger getLogger()
540     {
541         return AndroMDALogger.getNamespaceLogger(this.getNamespace());
542     }
543 
544     /**
545      * Registers a property with the specified <code>name</code> in the given
546      * <code>namespace</code>.
547      *
548      * @param namespace the namespace in which the property is stored.
549      * @param metafacadeName the name of the metafacade under which the property is registered
550      * @param name the name of the property
551      * @param value to give the property
552      */
553     final void registerProperty(
554         final String namespace,
555         final String metafacadeName,
556         final String name,
557         final Object value)
558     {
559         ExceptionUtils.checkEmpty(
560             "name",
561             name);
562         Map<String, Map<String, Object>> metafacadeNamespace = this.metafacadeNamespaces.get(namespace);
563         if (metafacadeNamespace == null)
564         {
565             metafacadeNamespace = new LinkedHashMap<String, Map<String, Object>>();
566             this.metafacadeNamespaces.put(
567                 namespace,
568                 metafacadeNamespace);
569         }
570         Map<String, Object> propertyNamespace = metafacadeNamespace.get(metafacadeName);
571         if (propertyNamespace == null)
572         {
573             propertyNamespace = new LinkedHashMap<String, Object>();
574             metafacadeNamespace.put(
575                 metafacadeName,
576                 propertyNamespace);
577         }
578         propertyNamespace.put(
579             name,
580             value);
581     }
582 
583     /**
584      * Registers a property with the specified <code>name</code> in the namespace
585      * that is currently set within the factory.
586      *
587      * @param metafacadeName the name of the metafacade under which the property is registered
588      * @param name the name of the property
589      * @param value to give the property
590      */
591     final void registerProperty(
592         final String metafacadeName,
593         final String name,
594         final Object value)
595     {
596         this.registerProperty(
597             this.getNamespace(),
598             metafacadeName,
599             name,
600             value);
601     }
602 
603     /**
604      * Gets the metafacade's property namespace (or returns null if hasn't be registered).
605      *
606      * @param metafacade the metafacade
607      * @return the metafacade's namespace
608      */
609     private Map<String, Object> getMetafacadePropertyNamespace(final MetafacadeBase metafacade)
610     {
611         Map<String, Object> metafacadeNamespace = null;
612         if (metafacade != null)
613         {
614             Map<String, Map<String, Object>> namespace = this.metafacadeNamespaces.get(this.getNamespace());
615             if (namespace != null)
616             {
617                 metafacadeNamespace = namespace.get(metafacade.getMetafacadeName());
618             }
619         }
620         return metafacadeNamespace;
621     }
622 
623     /**
624      * Returns true if this property is registered under the given
625      * <code>namespace</code>, false otherwise.
626      *
627      * @param metafacade the metafacade to search.
628      * @param name the name of the property.
629      * @return true if the property is registered, false otherwise.
630      */
631     final boolean isPropertyRegistered(
632         final MetafacadeBase metafacade,
633         final String name)
634     {
635         final Map<String, Object> propertyNamespace = this.getMetafacadePropertyNamespace(metafacade);
636         return propertyNamespace != null && propertyNamespace.containsKey(name);
637     }
638 
639     /**
640      * Finds the first property having the given <code>namespaces</code>, or
641      * <code>null</code> if the property can <strong>NOT </strong> be found.
642      *
643      * @param metafacade the metafacade to search.
644      * @param name the name of the property to find.
645      * @return the property or null if it can't be found.
646      */
647     private Object findProperty(
648         final MetafacadeBase metafacade,
649         final String name)
650     {
651         final Map<String, Object> propertyNamespace = this.getMetafacadePropertyNamespace(metafacade); //final Map<String, Map>
652         return propertyNamespace != null ? propertyNamespace.get(name) : null;
653     }
654 
655     /**
656      * Gets the registered property registered under the <code>namespace</code>
657      * with the <code>name</code>
658      *
659      * @param metafacade the metafacade to search
660      * @param name the name of the property to check.
661      * @return the registered property
662      */
663     final Object getRegisteredProperty(
664         final MetafacadeBase metafacade,
665         final String name)
666     {
667         final String methodName = "MetafacadeFactory.getRegisteredProperty";
668         final Object registeredProperty = this.findProperty(
669                 metafacade,
670                 name);
671         if (registeredProperty == null && !this.isPropertyRegistered(
672                 metafacade,
673                 name))
674         {
675             throw new MetafacadeFactoryException(methodName + " - no property '" + name +
676                 "' registered under metafacade '" + metafacade.getMetafacadeName() + "' for namespace '" + this.getNamespace() +
677                     '\'');
678         }
679         return registeredProperty;
680     }
681 
682     /**
683      * The validation messages that have been collected during the
684      * execution of this factory.
685      */
686     private final Collection<ModelValidationMessage> validationMessages = new LinkedHashSet<ModelValidationMessage>();
687 
688     /**
689      * Gets the list of all validation messages collection during model processing.
690      *
691      * @return Returns the validationMessages.
692      * @see #validateAllMetafacades()
693      */
694     public List<ModelValidationMessage> getValidationMessages()
695     {
696         return new ArrayList<ModelValidationMessage>(this.validationMessages);
697     }
698 
699     /**
700      * Stores the collection of all metafacades for
701      * each namespace.
702      */
703     private final Map<String, Collection<MetafacadeBase>> allMetafacades = new LinkedHashMap<String, Collection<MetafacadeBase>>();
704 
705     /**
706      * <p>
707      * Gets all metafacades for the entire model for the
708      * current namespace set within the factory.
709      * </p>
710      * <p>
711      * <strong>NOTE:</strong> The model package filter is applied
712      * before returning the results (if defined within the factory).
713      * </p>
714      *
715      * @return all metafacades
716      */
717     public Collection<MetafacadeBase> getAllMetafacades()
718     {
719         final String namespace = this.getNamespace();
720         Collection<MetafacadeBase> metafacades = null;
721         if (this.getModel() != null)
722         {
723             metafacades = allMetafacades.get(namespace);
724             if (metafacades == null)
725             {
726                 metafacades = this.createMetafacades(this.getModel().getModelElements());
727                 allMetafacades.put(
728                     namespace,
729                     metafacades);
730             }
731             if (metafacades != null)
732             {
733                 metafacades = new ArrayList<MetafacadeBase>(metafacades);
734             }
735         }
736         return metafacades;
737     }
738 
739     /**
740      * Caches the metafacades by stereotype.
741      */
742     private final Map<String, Map<String, Collection<MetafacadeBase>>> metafacadesByStereotype
743     = new LinkedHashMap<String, Map<String, Collection<MetafacadeBase>>>();
744 
745     /**
746      * <p>
747      * Gets all metafacades for the entire model having the given
748      * stereotype.
749      * </p>
750      * <p>
751      * <strong>NOTE:</strong> The model package filter is applied
752      * before returning the results (if defined within the factory).
753      * </p>
754      *
755      * @param stereotype the stereotype by which to perform the search.
756      * @return the metafacades having the given <code>stereotype</code>.
757      */
758     public Collection<MetafacadeBase> getMetafacadesByStereotype(final String stereotype)
759     {
760         final String namespace = this.getNamespace();
761         Collection<MetafacadeBase> metafacades = null;
762         if (this.getModel() != null)
763         {
764             Map<String, Collection<MetafacadeBase>> stereotypeMetafacades = this.metafacadesByStereotype.get(namespace);
765             if (stereotypeMetafacades == null)
766             {
767                 stereotypeMetafacades = new LinkedHashMap<String, Collection<MetafacadeBase>>();
768             }
769             metafacades = stereotypeMetafacades.get(stereotype);
770             if (metafacades == null)
771             {
772                 metafacades = this.createMetafacades(this.getModel().findByStereotype(stereotype));
773                 stereotypeMetafacades.put(
774                     stereotype,
775                     metafacades);
776                 this.metafacadesByStereotype.put(
777                     namespace,
778                     stereotypeMetafacades);
779             }
780             if (metafacades != null)
781             {
782                 metafacades = new ArrayList<MetafacadeBase>(metafacades);
783             }
784         }
785         return metafacades;
786     }
787 
788     /**
789      * Performs shutdown procedures for the factory. This should be called <strong>ONLY</strong> when model processing has
790      * completed.
791      */
792     public void shutdown()
793     {
794         this.clearCaches();
795         this.metafacadeNamespaces.clear();
796         this.mappings.shutdown();
797         this.model = null;
798         MetafacadeFactory.instance = null;
799 
800         // - shutdown the profile instance
801         this.profile.shutdown();
802     }
803 
804     /**
805      * Registers all namespace properties (if required).
806      */
807     private void registerNamespaceProperties()
808     {
809         // - only register them if they already aren't registered
810         if (this.metafacadeNamespaces.isEmpty())
811         {
812             if (StringUtils.isNotBlank(this.metafacadeModelNamespace))
813             {
814                 final MetafacadeMappings modelMappings = this.getModelMetafacadeMappings();
815                 if (modelMappings != null)
816                 {
817                     modelMappings.registerAllProperties();
818                 }
819             }
820         }
821     }
822 
823     /**
824      * Entirely resets all the internal resources within this factory instance (such
825      * as the caches, etc).
826      */
827     public void reset()
828     {
829         // - refresh the profile
830         this.profile.refresh();
831 
832         // - clear out the namespace properties so we can re-register them next run
833         this.metafacadeNamespaces.clear();
834 
835         // - re-register the namespace properties (if we're running again)
836         this.registerNamespaceProperties();
837 
838         // - clear out the rest of the factory's caches
839         this.clearCaches();
840     }
841 
842     /**
843      * Clears out the factory's internal caches (other
844      * than namespace properties, which can be cleared by
845      * calling {@link org.andromda.core.configuration.Namespaces#clear()}.
846      */
847     public void clearCaches()
848     {
849         this.validationMessages.clear();
850         this.allMetafacades.clear();
851         this.metafacadesByStereotype.clear();
852         this.cache.clear();
853         this.metafacadesInCreation.clear();
854     }
855 }