View Javadoc
1   package org.andromda.repositories.emf;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.net.URL;
6   import java.util.ArrayList;
7   import java.util.Arrays;
8   import java.util.HashMap;
9   import java.util.Iterator;
10  import java.util.List;
11  import java.util.Map;
12  import org.andromda.core.common.ResourceFinder;
13  import org.andromda.core.engine.ModelProcessor;
14  import org.andromda.core.metafacade.ModelAccessFacade;
15  import org.andromda.core.repository.RepositoryFacade;
16  import org.andromda.core.repository.RepositoryFacadeException;
17  import org.apache.log4j.Logger;
18  import org.eclipse.emf.common.util.EList;
19  import org.eclipse.emf.common.util.URI;
20  import org.eclipse.emf.ecore.EObject;
21  import org.eclipse.emf.ecore.resource.Resource;
22  import org.eclipse.emf.ecore.resource.ResourceSet;
23  import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
24  
25  /**
26   * An abstract EMF {@link RepositoryFacade} instance that should be extended by any repository wishing to load EMF models.
27   *
28   * @author Steve Jerman
29   * @author Chad Brandon
30   * @author Bob Fields (Multiple model support)
31   */
32  public abstract class EMFRepositoryFacade
33      implements RepositoryFacade
34  {
35      /**
36       * The logger instance.
37       */
38      private static final Logger logger = Logger.getLogger(EMFRepositoryFacade.class);
39  
40      /**
41       * Stores the resources (i.e. models) loaded into EMF.
42       */
43      protected ResourceSet resourceSet;
44  
45      /**
46       *
47       */
48      protected ModelAccessFacade modelFacade;
49  
50      /**
51       * Stores the actual loaded model.
52       */
53      // Modification required for multi-model support - fix compile errors after change
54      // and implement multiple model processing by iterating through models in the list.
55      protected List<Resource> model;
56  
57      /**
58       * The options for loading the model.
59       */
60      private Map<String, Object> loadOptions = new HashMap<String, Object>();
61  
62      /**
63       * Gets the current load options.
64       *
65       * @return the load options.
66       */
67      protected Map<String, Object> getLoadOptions()
68      {
69          return this.loadOptions;
70      }
71  
72      /**
73       * Reads the model with the given <code>uri</code>.
74       *
75       * @param uri the URI to the model
76       */
77      public void readModel(final String uri)
78      {
79          try
80          {
81              if (this.model==null)
82              {
83                  this.model = new ArrayList<Resource>();
84              }
85              Resource modelResource = this.resourceSet.createResource(EMFRepositoryFacadeUtils.createUri(uri));
86              if (modelResource == null)
87              {
88                  throw new RepositoryFacadeException('\'' + uri + "' is an invalid model");
89              }
90              modelResource.load(this.getLoadOptions());
91              // Show errors and warnings, if any....
92              EList<Diagnostic> errors = modelResource.getErrors();
93              if (errors!=null && !errors.isEmpty())
94              {
95                  logger.info(errors);
96              }
97              EList<Diagnostic> warnings = modelResource.getWarnings();
98              if (warnings!=null && !warnings.isEmpty())
99              {
100                 logger.info(warnings);
101             }
102             // Don't validate that model resources can be loaded, if not necessary. Speeds up processing.
103             if (ModelProcessor.getModelValidation())
104             {
105                 try {
106                     //logger.debug("EMFRepositoryFacade.readModel.resolve: " + modelResource.getURI());
107                     // Duplicate call to EcoreUtil.resolveAll(modelResource);
108                     //long now = System.currentTimeMillis();
109                     //for (EObject eObject : modelResource.getAllContents())
110                     for (Iterator<EObject> i = modelResource.getAllContents();  i.hasNext(); )
111                     {
112                         //long now1 = System.currentTimeMillis();
113                         EObject eObject = i.next();
114                         //logger.debug("EMFRepositoryFacade.resolveAll.crossRef: " + EcoreUtil.getURI(eObject) + " " + (System.currentTimeMillis()-now1) + " ms");
115                         for (Iterator<EObject> crossRefIterator =  eObject.eCrossReferences().iterator();  crossRefIterator.hasNext(); )
116                         {
117                             try
118                             {
119                                 //long now2 = System.currentTimeMillis();
120                                 //EObject crossRef =
121                                     crossRefIterator.next();
122                                 //EObject resolved = EcoreUtil.resolve(crossRef, this.resourceSet);
123                                 //logger.debug("EMFRepositoryFacade.resolveAll.crossRef: " + crossRef.toString() + " = " + EcoreUtil.getURI(crossRef) + " " + (System.currentTimeMillis()-now2) + " ms");
124                             }
125                             catch (Exception ex)
126                             {
127                                 logger.error("EMFRepositoryFacade.readModel.resolveAll on " + eObject + ": " + ex);
128                             }
129                         }
130                     }
131                 } catch (RuntimeException e) {
132                     logger.error("EMFRepositoryFacade.readModel.resolveAll :" + e);
133                 }
134             }
135             this.model.add(modelResource);
136         }
137         catch (final Exception exception)
138         {
139             throw new RepositoryFacadeException(exception);
140         }
141     }
142 
143     /**
144      * @see org.andromda.core.repository.RepositoryFacade#open()
145      */
146     public void open()
147     {
148         this.resourceSet = this.createNewResourceSet();
149     }
150 
151     /**
152      * Creates and returns a new resource suitable for loading models into EMF.
153      * This callback is used when (re-)initializing this repository so that it can be reused between different
154      * AndroMDA runs, once a resource set is used for a model it becomes 'polluted' so that subsequent models
155      * will see things from the previous runs, which might mess up the processing.
156      *
157      * @return a new resource set to be used by this repository
158      */
159     public abstract ResourceSet createNewResourceSet();
160 
161     /**
162      * Ignore. Avoid compiler warning.
163      * @see org.andromda.core.repository.RepositoryFacade#close()
164      */
165     public abstract void close();
166 
167     /**
168      * The path to any modules found on the classpath.
169      */
170     private static final String MODULES_PATH = "META-INF/emf/modules";
171 
172     /**
173      * @see org.andromda.core.repository.RepositoryFacade#readModel(String[], String[])
174      */
175     public void readModel(
176         String[] modelUris,
177         String[] moduleSearchPaths)
178     {
179         if (modelUris == null || modelUris.length == 0)
180         {
181             throw new RepositoryFacadeException("No model specified.");
182         }
183         final List<String> moduleSearchPathList = new ArrayList<String>();
184         if (moduleSearchPaths != null)
185         {
186             moduleSearchPathList.addAll(Arrays.asList(moduleSearchPaths));
187         }
188 
189         // - first add the default module search paths maps that are found on the classpath
190         URL[] classpathSearchPaths = ResourceFinder.findResources(MODULES_PATH);
191         if (classpathSearchPaths != null)
192         {
193             classpathSearchPaths = ResourceFinder.findResources("profiles");
194         }
195         if (classpathSearchPaths != null)
196         {
197             final int numberOfClasspathSearchPaths = classpathSearchPaths.length;
198             for (int ctr = 0; ctr < numberOfClasspathSearchPaths; ctr++)
199             {
200                 final URL classpathSearchPath = classpathSearchPaths[ctr];
201                 if (classpathSearchPath != null)
202                 {
203                     moduleSearchPathList.add(classpathSearchPath.toString());
204                 }
205             }
206         }
207         logger.debug("ModuleSearchPaths: " + moduleSearchPathList);
208         // Add the new URI map to the existing URI map
209 
210         this.resourceSet.setURIConverter(new EMFURIConverter(moduleSearchPathList,
211             this.resourceSet.getURIConverter().getURIMap()));
212         if (modelUris.length > 0)
213         {
214             final int numberOfModelUris = modelUris.length;
215             for (int ctr = 0; ctr < numberOfModelUris; ctr++)
216             {
217                 this.readModel(modelUris[ctr]);
218             }
219         }
220     }
221 
222     /**
223      * @see org.andromda.core.repository.RepositoryFacade#readModel(java.io.InputStream[], String[], String[])
224      */
225     public void readModel(
226         InputStream[] stream,
227         String[] modelUri,
228         String[] moduleSearchPaths)
229     {
230         this.readModel(
231             modelUri,
232             moduleSearchPaths);
233     }
234 
235     /**
236      * @see org.andromda.core.repository.RepositoryFacade#writeModel(Object, String, String, String)
237      */
238     public void writeModel(
239         Object modelIn,
240         String location,
241         String version,
242         String encoding)
243     {
244         this.writeModel(
245             modelIn,
246             location,
247             "");
248     }
249 
250     /**
251      * @see org.andromda.core.repository.RepositoryFacade#writeModel(Object, String, String)
252      */
253     public void writeModel(
254         Object modelIn,
255         String location,
256         String version)
257     {
258         final org.eclipse.emf.ecore.EModelElement element = (org.eclipse.emf.ecore.EModelElement)modelIn;
259         final Resource resource = element.eResource();
260         final URI uri = URI.createURI(location);
261         resource.setURI(uri);
262         try
263         {
264             resource.save(null);
265         }
266         catch (IOException exception)
267         {
268             throw new RepositoryFacadeException("Could not save model", exception);
269         }
270     }
271 
272     /**
273      * @see org.andromda.core.repository.RepositoryFacade#clear()
274      */
275     public void clear()
276     {
277         this.model = null;
278         this.resourceSet = this.createNewResourceSet();
279     }
280 }