/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.compare;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.plugin.EcorePlugin;
import org.eclipse.emf.ecore.resource.Resource;
import org.osgi.framework.BundleContext;
import org.teiid.core.designer.PluginUtil;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.PluginUtilImpl;
import org.teiid.designer.compare.impl.ComparePackageImpl;
import org.teiid.designer.compare.processor.DifferenceProcessorImpl;
import org.teiid.designer.compare.processor.MergeProcessorImpl;
import org.teiid.designer.compare.selector.EmfResourceSelector;
import org.teiid.designer.compare.selector.InputStreamModelSelector;
import org.teiid.designer.compare.selector.ModelResourceSelector;
import org.teiid.designer.compare.selector.ModelSelector;
import org.teiid.designer.compare.selector.URIModelSelector;
import org.teiid.designer.core.MappingAdapterDescriptor;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.compare.EObjectMatcherFactory;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
/**
* ModelerComparePlugin
*
* @since 8.0
*/
public class ModelerComparePlugin extends Plugin {
private static final String MISSING_RESOURCE = "<Missing message for key"; //$NON-NLS-1$
public static final String PLUGIN_ID = "org.teiid.designer.compare"; //$NON-NLS-1$
public static final String PACKAGE_ID = ModelerComparePlugin.class.getPackage().getName();
/**
* Provides access to the plugin's log and to it's resources.
*/
private static final String I18N_NAME = PACKAGE_ID + ".i18n"; //$NON-NLS-1$
public static final PluginUtil Util = new PluginUtilImpl(PLUGIN_ID, I18N_NAME, ResourceBundle.getBundle(I18N_NAME));
private static final ResourceLocator RESOURCE_LOCATOR = new ResourceLocator() {
private ResourceLocator delegate = EcorePlugin.INSTANCE.getPluginResourceLocator();
@Override
public URL getBaseURL() {
if (INSTANCE != null) {
URL baseUrl;
try {
baseUrl = FileLocator.resolve(INSTANCE.getBundle().getEntry("/")); //$NON-NLS-1$
} catch (final IOException err) {
baseUrl = null;
}
return baseUrl;
}
try {
final URI uri = URI.createURI(getClass().getResource("plugin.properties").toString()); //$NON-NLS-1$
final URL baseUrl = new URL(uri.trimSegments(1).toString() + "/"); //$NON-NLS-1$
return baseUrl;
} catch (IOException exception) {
throw new WrappedException(exception);
}
}
@Override
public Object getImage( String key ) {
try {
final URL baseUrl = getBaseURL();
final URL url = new URL(baseUrl + "icons/" + key + ".gif"); //$NON-NLS-1$//$NON-NLS-2$
InputStream inputStream = url.openStream();
inputStream.close();
return url;
} catch (MalformedURLException exception) {
throw new WrappedException(exception);
} catch (IOException exception) {
return delegate.getImage(key);
}
}
@Override
public String getString( String key ) {
String result = Util.getString(key);
if (result.startsWith(MISSING_RESOURCE)) {
result = delegate.getString(key);
}
return result;
}
@Override
public String getString( String key,
Object[] substitutions ) {
String result = Util.getString(key);
if (result.startsWith(MISSING_RESOURCE)) {
result = delegate.getString(key, substitutions);
}
return result;
}
@Override
public String getString( final String key,
final boolean translate ) {
return getString(key);
}
@Override
public String getString( final String key,
final Object[] substitutions,
final boolean translate ) {
return getString(key, substitutions);
}
};
/**
*
* @return the EMF ResourceLocator used when run as a plugin
*/
public static ResourceLocator getPluginResourceLocator() {
return RESOURCE_LOCATOR;
}
public static boolean DEBUG = false;
static ModelerComparePlugin INSTANCE = null;
static {
ModelerCore.getMetamodelRegistry();
ComparePackageImpl.init();
}
/**
* @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext)
* @since 4.3.2
*/
@Override
public void start( final BundleContext context ) throws Exception {
super.start(context);
INSTANCE = this;
((PluginUtilImpl)Util).initializePlatformLogger(this); // This must be called to initialize the platform logger!
}
/**
* Create a difference processor that computes the differences between the current (unsaved) state of a model and it's saved
* state (on disk).
* <p>
* The differences returned by the processor describe the actions taken to change the <i>saved</i> state into the <i>unsaved
* (current)</i> state.
* </p>
*
* @param modelResource the {@link ModelResource} for which the difference between the saved and current state is to be
* performed; may not be null
* @return the difference processor; never null
* @throws ModelWorkspaceException if there is a problem with the supplied resources
*/
public static DifferenceProcessor createDifferenceProcessor( final ModelResource modelResource )
throws ModelWorkspaceException {
CoreArgCheck.isNotNull(modelResource);
final ModelSelector currentSelector = new ModelResourceSelector(modelResource);
currentSelector.setLabel(modelResource.getPath().toString());
DifferenceProcessor processor = null;
if (!modelResource.hasUnsavedChanges()) {
// There are no unsaved changes, so nothing to compute ...
processor = new DifferenceProcessorImpl(currentSelector);
} else {
// There are unsaved changes, so create a selector to open the saved model ...
final URI uri = URI.createFileURI(modelResource.getResource().getLocation().toFile().getAbsolutePath());
final ModelSelector savedSelector = new URIModelSelector(uri);
final Object[] params = new Object[] {modelResource.getPath().toString()};
savedSelector.setLabel(ModelerComparePlugin.Util.getString("ModelerComparePlugin.SavedModel", params)); //$NON-NLS-1$
currentSelector.setLabel(ModelerComparePlugin.Util.getString("ModelerComparePlugin.OpenedModel", params)); //$NON-NLS-1$
processor = new DifferenceProcessorImpl(savedSelector, currentSelector);
}
final List mappingAdapters = createEObjectMatcherFactories();
processor.addEObjectMatcherFactories(mappingAdapters);
return processor;
}
/**
* Create a difference processor that computes the differences between the supplied model resources.
* <p>
* The differences returned by the processor describe the actions taken to change the <code>startingResource</code> into the
* <code>endingResource</code>.
* </p>
*
* @param startingResource the {@link ModelResource} containing the original (starting) state; may not be null
* @param endingResource the {@link ModelResource} containing the final (ending) state; may not be null
* @return the difference processor; never null
*/
public static DifferenceProcessor createDifferenceProcessor( final ModelResource startingResource,
final ModelResource endingResource ) {
CoreArgCheck.isNotNull(startingResource);
CoreArgCheck.isNotNull(endingResource);
final ModelSelector startingSelector = new ModelResourceSelector(startingResource);
final ModelSelector endingSelector = new ModelResourceSelector(endingResource);
endingSelector.setLabel(startingResource.getPath().toString());
endingSelector.setLabel(endingResource.getPath().toString());
final DifferenceProcessor processor = new DifferenceProcessorImpl(startingSelector, endingSelector);
final List mappingAdapters = createEObjectMatcherFactories();
processor.addEObjectMatcherFactories(mappingAdapters);
return processor;
}
/**
* Create a difference processor that computes the differences between model in the supplied stream and the supplied model
* resource.
* <p>
* The differences returned by the processor describe the actions taken to change the <code>startingResource</code> into the
* <code>endingResource</code>.
* </p>
*
* @param startingResource the {@link InputStream} containing the model in it's original (starting) state; may not be null
* @param startingResourcePath the {@link IPath} to the resource in the workspace or repository.
* @param endingResource the {@link ModelResource} containing the final (ending) state; may not be null
* @return the difference processor; never null
* @throws ModelWorkspaceException if there is a problem with the supplied resources
*/
public static DifferenceProcessor createDifferenceProcessor( final InputStream startingResource,
final IPath startingResourcePath,
final ModelResource endingResource,
final String startingResourceDesc )
throws ModelWorkspaceException {
CoreArgCheck.isNotNull(startingResource);
CoreArgCheck.isNotNull(startingResourcePath);
CoreArgCheck.isNotNull(endingResource);
// assume that the starting resource and ending resource are of same type
IResource resource = endingResource.getCorrespondingResource();
URI temporayURI = null;
if (ModelUtil.isXsdFile(resource)) {
temporayURI = InputStreamModelSelector.XSD_URI;
} else if (ModelUtil.isModelFile(resource)) {
temporayURI = InputStreamModelSelector.XMI_URI;
} else if (ModelUtil.isVdbArchiveFile(resource)) {
temporayURI = InputStreamModelSelector.VDB_URI;
}
// dont process....this is not a model file
if (temporayURI == null) {
return null;
}
final ModelSelector startingSelector = new InputStreamModelSelector(startingResource, temporayURI);
final ModelSelector endingSelector = new ModelResourceSelector(endingResource);
startingSelector.setLabel(startingResourceDesc);
endingSelector.setLabel(endingResource.getPath().toString());
final DifferenceProcessor processor = new DifferenceProcessorImpl(startingSelector, endingSelector);
final List mappingAdapters = createEObjectMatcherFactories();
processor.addEObjectMatcherFactories(mappingAdapters);
return processor;
}
/**
* Create a difference processor that computes the differences between the supplied resources.
* <p>
* The differences returned by the processor describe the actions taken to change the <code>startingResource</code> into the
* <code>endingResource</code>.
* </p>
*
* @param startingResource the EMF resource containing the original (starting) state; may not be null
* @param endingResource the EMF resource containing the final (ending) state; may not be null
* @return the difference processor; never null
*/
public static DifferenceProcessor createDifferenceProcessor( final Resource startingResource,
final Resource endingResource ) {
CoreArgCheck.isNotNull(startingResource);
CoreArgCheck.isNotNull(endingResource);
final ModelSelector startingSelector = new EmfResourceSelector(startingResource);
final ModelSelector endingSelector = new EmfResourceSelector(endingResource);
startingSelector.setLabel(URI.decode(startingResource.getURI().toString()));
endingSelector.setLabel(URI.decode(endingResource.getURI().toString()));
final DifferenceProcessor processor = new DifferenceProcessorImpl(startingSelector, endingSelector);
final List mappingAdapters = createEObjectMatcherFactories();
processor.addEObjectMatcherFactories(mappingAdapters);
return processor;
}
/**
* Create a difference processor that computes the differences between the supplied resources. Sets the inputToOutput map so
* that previous model mappings may be used.
* <p>
* The differences returned by the processor describe the actions taken to change the <code>startingResource</code> into the
* <code>endingResource</code>.
* </p>
*
* @param startingResource the EMF resource containing the original (starting) state; may not be null
* @param endingResource the EMF resource containing the final (ending) state; may not be null
* @param mappings
* @return the difference processor; never null
*/
public static DifferenceProcessor createDifferenceProcessor( final Resource startingResource,
final Resource endingResource,
final HashMap mappings ) {
CoreArgCheck.isNotNull(startingResource);
CoreArgCheck.isNotNull(endingResource);
final ModelSelector startingSelector = new EmfResourceSelector(startingResource);
final ModelSelector endingSelector = new EmfResourceSelector(endingResource);
startingSelector.setLabel(URI.decode(startingResource.getURI().toString()));
endingSelector.setLabel(URI.decode(endingResource.getURI().toString()));
final DifferenceProcessor processor = new DifferenceProcessorImpl(startingSelector, endingSelector, mappings);
final List mappingAdapters = createEObjectMatcherFactories();
processor.addEObjectMatcherFactories(mappingAdapters);
return processor;
}
/**
* Create a merge processor that merges the differences computed by the supplied processor. The result of executing the merge
* processor is to convert the original (starting) state of the difference report into the final (ending) state.
*
* @param difference the difference report that specifies those differences that should be merged
* @return the processor that can be used to execute the merge
*/
public static MergeProcessor createMergeProcessor( final DifferenceProcessor difference ) {
CoreArgCheck.isInstanceOf(DifferenceProcessorImpl.class, difference);
return new MergeProcessorImpl((DifferenceProcessorImpl)difference);
}
/**
* Create a merge processor that merges the differences computed by the supplied processor. The result of executing the merge
* processor is to convert the original (starting) state of the difference report into the final (ending) state.
*
* @param difference the difference report that specifies those differences that should be merged
* @param externalReferences the array of EObjects that are referenceable by either the starting or ending resource but are
* external to both resource.
* @return the processor that can be used to execute the merge
*/
public static MergeProcessor createMergeProcessor( final DifferenceProcessor difference,
final EObject[] externalReferences ) {
CoreArgCheck.isInstanceOf(DifferenceProcessorImpl.class, difference);
return new MergeProcessorImpl((DifferenceProcessorImpl)difference, externalReferences);
}
/**
* Create a merge processor that merges the differences computed by the supplied processor. The result of executing the merge
* processor is to convert the original (starting) state of the difference report into the final (ending) state.
*
* @param difference the difference report that specifies those differences that should be merged
* @param externalReferences the array of EObjects that are referenceable by either the starting or ending resource but are
* external to both resource.
* @param moveAddsRatherThanCopy true if objects that are considered "adds" should be <i>moved</i> rather than copied (will be
* removed from the source model), or false the source model should be left unchanged and any "adds" be copied into the
* output model
* @return the processor that can be used to execute the merge
*/
public static MergeProcessor createMergeProcessor( final DifferenceProcessor difference,
final EObject[] externalReferences,
final boolean moveAddsRatherThanCopy ) {
CoreArgCheck.isInstanceOf(DifferenceProcessorImpl.class, difference);
return new MergeProcessorImpl((DifferenceProcessorImpl)difference, externalReferences, moveAddsRatherThanCopy);
}
/**
* Utility method to create {@link EObjectMatcherFactory mapping adapter} instances by using the
* {@link org.teiid.designer.core.ModelerCore.EXTENSION_POINT.EOBJECT_MATCHER_FACTORY} extensions
*
* @return a list of {@link EObjectMatcherFactory} instances defined via extensions
* @see ModelerCore#getMappingAdapterDescriptors()
*/
public static List createEObjectMatcherFactories() {
final List factories = new LinkedList();
// Look for registered mapping adapters ...
final List adapterDescriptors = ModelerCore.getMappingAdapterDescriptors();
final Iterator iter = adapterDescriptors.iterator();
while (iter.hasNext()) {
final MappingAdapterDescriptor desc = (MappingAdapterDescriptor)iter.next();
if (desc != null) {
// Instantiate the descriptor ...
final EObjectMatcherFactory factory = (EObjectMatcherFactory)desc.getExtensionClassInstance();
if (factory != null) {
factories.add(factory);
}
}
}
return factories;
}
}