EMFRepositoryFacade.java
package org.andromda.repositories.emf;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.andromda.core.common.ResourceFinder;
import org.andromda.core.engine.ModelProcessor;
import org.andromda.core.metafacade.ModelAccessFacade;
import org.andromda.core.repository.RepositoryFacade;
import org.andromda.core.repository.RepositoryFacadeException;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
/**
* An abstract EMF {@link RepositoryFacade} instance that should be extended by any repository wishing to load EMF models.
*
* @author Steve Jerman
* @author Chad Brandon
* @author Bob Fields (Multiple model support)
*/
public abstract class EMFRepositoryFacade
implements RepositoryFacade
{
/**
* The logger instance.
*/
private static final Logger logger = Logger.getLogger(EMFRepositoryFacade.class);
/**
* Stores the resources (i.e. models) loaded into EMF.
*/
protected ResourceSet resourceSet;
/**
*
*/
protected ModelAccessFacade modelFacade;
/**
* Stores the actual loaded model.
*/
// Modification required for multi-model support - fix compile errors after change
// and implement multiple model processing by iterating through models in the list.
protected List<Resource> model;
/**
* The options for loading the model.
*/
private Map<String, Object> loadOptions = new HashMap<String, Object>();
/**
* Gets the current load options.
*
* @return the load options.
*/
protected Map<String, Object> getLoadOptions()
{
return this.loadOptions;
}
/**
* Reads the model with the given <code>uri</code>.
*
* @param uri the URI to the model
*/
public void readModel(final String uri)
{
try
{
if (this.model==null)
{
this.model = new ArrayList<Resource>();
}
Resource modelResource = this.resourceSet.createResource(EMFRepositoryFacadeUtils.createUri(uri));
if (modelResource == null)
{
throw new RepositoryFacadeException('\'' + uri + "' is an invalid model");
}
modelResource.load(this.getLoadOptions());
// Show errors and warnings, if any....
EList<Diagnostic> errors = modelResource.getErrors();
if (errors!=null && !errors.isEmpty())
{
logger.info(errors);
}
EList<Diagnostic> warnings = modelResource.getWarnings();
if (warnings!=null && !warnings.isEmpty())
{
logger.info(warnings);
}
// Don't validate that model resources can be loaded, if not necessary. Speeds up processing.
if (ModelProcessor.getModelValidation())
{
try {
//logger.debug("EMFRepositoryFacade.readModel.resolve: " + modelResource.getURI());
// Duplicate call to EcoreUtil.resolveAll(modelResource);
//long now = System.currentTimeMillis();
//for (EObject eObject : modelResource.getAllContents())
for (Iterator<EObject> i = modelResource.getAllContents(); i.hasNext(); )
{
//long now1 = System.currentTimeMillis();
EObject eObject = i.next();
//logger.debug("EMFRepositoryFacade.resolveAll.crossRef: " + EcoreUtil.getURI(eObject) + " " + (System.currentTimeMillis()-now1) + " ms");
for (Iterator<EObject> crossRefIterator = eObject.eCrossReferences().iterator(); crossRefIterator.hasNext(); )
{
try
{
//long now2 = System.currentTimeMillis();
//EObject crossRef =
crossRefIterator.next();
//EObject resolved = EcoreUtil.resolve(crossRef, this.resourceSet);
//logger.debug("EMFRepositoryFacade.resolveAll.crossRef: " + crossRef.toString() + " = " + EcoreUtil.getURI(crossRef) + " " + (System.currentTimeMillis()-now2) + " ms");
}
catch (Exception ex)
{
logger.error("EMFRepositoryFacade.readModel.resolveAll on " + eObject + ": " + ex);
}
}
}
} catch (RuntimeException e) {
logger.error("EMFRepositoryFacade.readModel.resolveAll :" + e);
}
}
this.model.add(modelResource);
}
catch (final Exception exception)
{
throw new RepositoryFacadeException(exception);
}
}
/**
* @see org.andromda.core.repository.RepositoryFacade#open()
*/
public void open()
{
this.resourceSet = this.createNewResourceSet();
}
/**
* Creates and returns a new resource suitable for loading models into EMF.
* This callback is used when (re-)initializing this repository so that it can be reused between different
* AndroMDA runs, once a resource set is used for a model it becomes 'polluted' so that subsequent models
* will see things from the previous runs, which might mess up the processing.
*
* @return a new resource set to be used by this repository
*/
public abstract ResourceSet createNewResourceSet();
/**
* Ignore. Avoid compiler warning.
* @see org.andromda.core.repository.RepositoryFacade#close()
*/
public abstract void close();
/**
* The path to any modules found on the classpath.
*/
private static final String MODULES_PATH = "META-INF/emf/modules";
/**
* @see org.andromda.core.repository.RepositoryFacade#readModel(String[], String[])
*/
public void readModel(
String[] modelUris,
String[] moduleSearchPaths)
{
if (modelUris == null || modelUris.length == 0)
{
throw new RepositoryFacadeException("No model specified.");
}
final List<String> moduleSearchPathList = new ArrayList<String>();
if (moduleSearchPaths != null)
{
moduleSearchPathList.addAll(Arrays.asList(moduleSearchPaths));
}
// - first add the default module search paths maps that are found on the classpath
URL[] classpathSearchPaths = ResourceFinder.findResources(MODULES_PATH);
if (classpathSearchPaths != null)
{
classpathSearchPaths = ResourceFinder.findResources("profiles");
}
if (classpathSearchPaths != null)
{
final int numberOfClasspathSearchPaths = classpathSearchPaths.length;
for (int ctr = 0; ctr < numberOfClasspathSearchPaths; ctr++)
{
final URL classpathSearchPath = classpathSearchPaths[ctr];
if (classpathSearchPath != null)
{
moduleSearchPathList.add(classpathSearchPath.toString());
}
}
}
logger.debug("ModuleSearchPaths: " + moduleSearchPathList);
// Add the new URI map to the existing URI map
this.resourceSet.setURIConverter(new EMFURIConverter(moduleSearchPathList,
this.resourceSet.getURIConverter().getURIMap()));
if (modelUris.length > 0)
{
final int numberOfModelUris = modelUris.length;
for (int ctr = 0; ctr < numberOfModelUris; ctr++)
{
this.readModel(modelUris[ctr]);
}
}
}
/**
* @see org.andromda.core.repository.RepositoryFacade#readModel(java.io.InputStream[], String[], String[])
*/
public void readModel(
InputStream[] stream,
String[] modelUri,
String[] moduleSearchPaths)
{
this.readModel(
modelUri,
moduleSearchPaths);
}
/**
* @see org.andromda.core.repository.RepositoryFacade#writeModel(Object, String, String, String)
*/
public void writeModel(
Object modelIn,
String location,
String version,
String encoding)
{
this.writeModel(
modelIn,
location,
"");
}
/**
* @see org.andromda.core.repository.RepositoryFacade#writeModel(Object, String, String)
*/
public void writeModel(
Object modelIn,
String location,
String version)
{
final org.eclipse.emf.ecore.EModelElement element = (org.eclipse.emf.ecore.EModelElement)modelIn;
final Resource resource = element.eResource();
final URI uri = URI.createURI(location);
resource.setURI(uri);
try
{
resource.save(null);
}
catch (IOException exception)
{
throw new RepositoryFacadeException("Could not save model", exception);
}
}
/**
* @see org.andromda.core.repository.RepositoryFacade#clear()
*/
public void clear()
{
this.model = null;
this.resourceSet = this.createNewResourceSet();
}
}