/*
* Copyright (c) 2004- michael lawley and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation
* which accompanies this distribution, and is available by writing to
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Contributors:
* michael lawley
*
*
*
*/
package tefkat.plugin;
import org.eclipse.swt.graphics.Color;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.xsd.util.XSDResourceFactoryImpl;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
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.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.GenericXMLResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
import org.osgi.framework.BundleContext;
import tefkat.config.TefkatConfig.ExecutionMode;
import tefkat.config.TefkatConfig.Model;
import tefkat.config.TefkatConfig.TefkatConfigFactory;
import tefkat.config.TefkatConfig.TransformationTask;
import tefkat.engine.Binding;
import tefkat.engine.Function;
import tefkat.engine.Tefkat;
import tefkat.engine.TefkatListener;
import tefkat.engine.TefkatListenerAdapter;
import tefkat.model.Extent;
import tefkat.model.TRule;
import tefkat.model.Transformation;
import tefkat.plugin.TefkatPreferencePage.URIMap;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
/**
* The main plugin class to be used in the desktop.
*/
public class TefkatPlugin extends AbstractUIPlugin {
public static final String PLUGIN_ID = "tefkat.plugin";
public static final String TEFKAT_NATURE = PLUGIN_ID + ".TefkatNature";
public static final String TEFKAT_BUILDER = PLUGIN_ID + ".TefkatBuilder";
public static final String TEFKAT_PARTITIONING = PLUGIN_ID + ".TefkatPartitioning";
public static final String PLUGIN_FUNCTION_SET = PLUGIN_ID + ".functionSet";
public static final String CONFIGURATION_FILE = "tefkat.xmi";
public static final String URIMAP_PREFERENCE = "URIMap";
// public static final TefkatResourceFactory TEFKAT_RESOURCE_FACTORY = Tefkat
private static final Resource.Factory ECORE_RESOURCE_FACTORY = new EcoreResourceFactoryImpl();
private static final Resource.Factory XMI_RESOURCE_FACTORY = new XMIResourceFactoryImpl();
private static final Resource.Factory XML_RESOURCE_FACTORY = new GenericXMLResourceFactoryImpl();
private static final Resource.Factory XSD_RESOURCE_FACTORY = new XSDResourceFactoryImpl();
final static String TEFKAT_CONSOLE_NAME = "Tefkat";
final static Color INFO_COLOR = new Color(null, 0, 0, 255);
final static Color WARN_COLOR = new Color(null, 255, 0, 0);
private static Map SERIALIZATION_OPTIONS;
static {
SERIALIZATION_OPTIONS = new HashMap();
SERIALIZATION_OPTIONS.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE);
SERIALIZATION_OPTIONS.put(XMLResource.OPTION_EXTENDED_META_DATA, new BasicExtendedMetaData());
SERIALIZATION_OPTIONS.put(XMLResource.OPTION_USE_LEXICAL_HANDLER, Boolean.TRUE);
}
// The shared instance.
private static TefkatPlugin plugin;
// Resource bundle.
private ResourceBundle resourceBundle;
// The QVT parser wrapped as a resource factory
// static {
// Map map = Registry.INSTANCE.getExtensionToFactoryMap();
// map.put("qvt", TEFKAT_RESOURCE_FACTORY);
// }
// The Tefkat Transformation Engine
private Tefkat theEngine;
private MessageConsole console;
private MessageConsoleStream infoStream;
private MessageConsoleStream warnStream;
private TefkatListener consoleAdapter = new TefkatListenerAdapter() {
public void info(String message) {
infoStream.println("INFO: " + message);
}
public void warning(String message) {
warnStream.println("WARN: " + message);
}
public void error(String message, Throwable cause) {
warnStream.println("ERROR: " + message);
StringWriter s = new StringWriter();
cause.printStackTrace(new PrintWriter(s));
warnStream.println(s.toString());
}
public void transformationStarted(Transformation transformation, Extent[] srcs, Extent[] tgts, Extent trace, Binding context) {
info("Transformation started: " + transformation.getName());
}
public void transformationFinished() {
info("Transformation finished");
}
public void resourceLoaded(Resource res) {
info("Loaded (" + res.hashCode() + ") " + res.getURI());
}
public void evaluateRule(TRule rule, Binding context, boolean cached) {
info("Evaluating " + rule.getName());
}
// public void enterTerm(Node node) {
// info("Enter: " + node);
// }
//
// public void exitTerm(Node node) {
// info("Exit: " + node);
// }
//
// public void delayTerm(Node node) {
// info("Delay: " + node);
// }
};
private RuleBasedPartitionScanner scanner;
/**
* The constructor.
*/
public TefkatPlugin() {
plugin = this;
try {
resourceBundle = ResourceBundle.getBundle("tefkat.plugin.TefkatPluginResources");
} catch (MissingResourceException x) {
resourceBundle = null;
}
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
List list = convertFromString(getPreferenceStore().getString(URIMAP_PREFERENCE));
for (final Iterator itr = list.iterator(); itr.hasNext(); ) {
URIMap map = (URIMap) itr.next();
if (map.enabled) {
URI sourceUri = URI.createURI(map.source);
URI targetUri = URI.createURI(map.target);
URIConverter.URI_MAP.put(sourceUri, targetUri);
}
}
}
/**
* Returns the shared instance.
*/
public static TefkatPlugin getPlugin() {
return plugin;
}
/**
* Returns the workspace instance.
*/
public static IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* Returns the string from the plugin's resource bundle, or 'key' if not
* found.
*/
public static String getResourceString(String key) {
ResourceBundle bundle = TefkatPlugin.getPlugin().getResourceBundle();
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
return key;
}
}
static List convertFromString(String preferenceValue) {
List list = new ArrayList();
String[] values = preferenceValue.split("[\t\n]");
for (int i = 2; i < values.length; i += 3) {
URIMap map = new URIMap();
map.enabled = Boolean.valueOf(values[i - 2]).booleanValue();
map.source = values[i - 1];
map.target = values[i];
list.add(map);
}
return list;
}
static String convertToString(List list) {
StringBuffer sb = new StringBuffer();
for (final Iterator itr = list.iterator(); itr.hasNext(); ) {
URIMap map = (URIMap) itr.next();
sb.append(map.enabled);
sb.append("\t");
sb.append(map.source);
sb.append("\t");
sb.append(map.target);
sb.append("\n");
}
return sb.toString();
}
/**
* Returns the plugin's resource bundle,
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
public void addTefkatListener(TefkatListener listener) {
getTefkat().addTefkatListener(listener);
}
public void removeTefkatListener(TefkatListener listener) {
getTefkat().removeTefkatListener(listener);
}
public Tefkat getTefkat() {
if (null == theEngine) {
theEngine = new Tefkat();
// theEngine.registerFactory("qvt", TEFKAT_RESOURCE_FACTORY);
ConsolePlugin plugin = ConsolePlugin.getDefault();
IConsoleManager manager = plugin.getConsoleManager();
IConsole[] existing = manager.getConsoles();
// remove any old consoles
for (int i = 0; i < existing.length; i++) {
if (TEFKAT_CONSOLE_NAME.startsWith(existing[i].getName())) {
manager.removeConsoles(new IConsole[]{ existing[i] });
}
}
console = new MessageConsole(TEFKAT_CONSOLE_NAME, null);
manager.addConsoles(new IConsole[]{ console });
manager.showConsoleView(console);
infoStream = console.newMessageStream();
warnStream = console.newMessageStream();
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
infoStream.setColor(INFO_COLOR);
warnStream.setColor(WARN_COLOR);
}
});
theEngine.addTefkatListener(consoleAdapter);
initFunctionSets();
}
return theEngine;
}
private void initFunctionSets() {
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(TefkatPlugin.PLUGIN_FUNCTION_SET);
IConfigurationElement[] funcSetElements = extensionPoint.getConfigurationElements();
for (int j = 0; j < funcSetElements.length; j++) {
IConfigurationElement funcSet = funcSetElements[j];
IConfigurationElement[] functionElements = funcSet.getChildren("function");
for (int i = 0; i < functionElements.length; i++) {
IConfigurationElement function = functionElements[i];
String name = function.getAttribute("name");
if (name != null && function.getAttribute("class") != null) {
try {
Object instance = function.createExecutableExtension("class");
if (instance instanceof Function) {
getTefkat().addFunction(name, (Function) instance);
} else {
String namespace = functionElements[i].getDeclaringExtension().getNamespace();
getLog().log(new Status(IStatus.ERROR, TefkatPlugin.PLUGIN_FUNCTION_SET, IStatus.OK, "Wrong type for function from " + namespace + ": " + name, null));
}
} catch (CoreException e) {
String namespace = functionElements[i].getDeclaringExtension().getNamespace();
getLog().log(new Status(IStatus.ERROR, TefkatPlugin.PLUGIN_FUNCTION_SET, IStatus.OK, "Error loading function from " + namespace + ": " + name, e));
}
} else {
String namespace = functionElements[i].getDeclaringExtension().getNamespace();
getLog().log(new Status(IStatus.ERROR, TefkatPlugin.PLUGIN_FUNCTION_SET, IStatus.OK, "Invalid function from " + namespace + ": " + name, null));
}
}
}
}
public void addAutoBuildNature(IProject project) throws CoreException {
if (project.findMember(CONFIGURATION_FILE) == null) {
URI uri = URI.createPlatformResourceURI(project.getName())
.appendSegment(CONFIGURATION_FILE);
Resource res = getResourceSet().createResource(uri);
res.getContents().add(
TefkatConfigFactory.eINSTANCE.createConfiguration());
try {
res.save(null);
} catch (IOException e) {
IStatus status = new Status(IStatus.ERROR,
TefkatPlugin.PLUGIN_ID, IStatus.OK,
"Failed to create Tefkat configuration", e);
this.getLog().log(status);
throw new CoreException(status);
}
project.refreshLocal(IResource.DEPTH_ONE, null);
}
if (project.hasNature(TEFKAT_NATURE)) {
return;
}
IProjectDescription description = project.getDescription();
String[] ids = description.getNatureIds();
String[] newIds = new String[ids.length + 1];
System.arraycopy(ids, 0, newIds, 0, ids.length);
newIds[ids.length] = TEFKAT_NATURE;
description.setNatureIds(newIds);
project.setDescription(description, null);
}
public void removeAutoBuildNature(IProject project) throws CoreException {
IProjectDescription description = project.getDescription();
String[] ids = description.getNatureIds();
for (int i = 0; i < ids.length; i++) {
if (ids[i].equals(TEFKAT_NATURE)) {
String[] newIds = new String[ids.length - 1];
System.arraycopy(ids, 0, newIds, 0, i);
System.arraycopy(ids, i + 1, newIds, i, ids.length - i - 1);
description.setNatureIds(newIds);
project.setDescription(description, null);
return;
}
}
}
public boolean getInterrupted() {
return getTefkat().getInterrupted();
}
public void setInterrupted(boolean state) {
getTefkat().setInterrupted(state);
}
public void pause() {
getTefkat().pause();
}
public void step() {
getTefkat().step();
}
public void resume() {
getTefkat().resume();
}
public void run(TransformationTask task, IProgressMonitor monitor)
throws CoreException {
String transformation = task.getTransformation().getLocationUri();
String trace = null;
if (null != task.getTrace()) {
trace = task.getTrace().getLocationUri();
}
List sourceModels = task.getSourceModels();
List targetModels = task.getTargetModels();
String[] sources = new String[sourceModels.size()];
String[] targets = new String[targetModels.size()];
for (int i = 0; i < sources.length; i++) {
sources[i] = ((Model) sourceModels.get(i)).getLocationUri();
}
for (int i = 0; i < targets.length; i++) {
targets[i] = ((Model) targetModels.get(i)).getLocationUri();
}
List props = task.getUriMap();
execute(transformation, sources, targets, trace, task.getMode(),
props, monitor);
}
public void execute(String transformation, String[] sourceModels,
String[] targetModels, String trace, ExecutionMode mode,
Collection props, final IProgressMonitor monitor) throws CoreException {
Resource transformationR = null;
Resource[] sourcesR = null;
Resource[] targetsR = null;
Resource traceR = null;
try {
monitor.subTask("Loading models " + transformation);
URIConverter converter = getResourceSet().getURIConverter();
Map URIMap = converter.getURIMap();
for (Iterator itr = props.iterator(); itr.hasNext(); ) {
Map.Entry entry = (Map.Entry) itr.next();
URI uri1 = URI.createURI((String) entry.getKey());
URI uri2 = URI.createURI((String) entry.getValue());
URIMap.put(uri1, uri2);
}
transformationR = getResource(transformation, monitor);
sourcesR = getResources(sourceModels, monitor);
if (mode.equals(ExecutionMode.REPLACE_LITERAL)) {
targetsR = createResources(targetModels);
if (null != trace) {
traceR = createResource(trace);
}
} else {
targetsR = getResources(targetModels, monitor);
if (null != trace) {
traceR = getResource(trace, monitor);
}
}
monitor.worked(1);
if (monitor.isCanceled()) {
throw new InterruptedException("Tefkat Build cancelled by user.");
}
monitor.subTask("Running " + transformation);
Tefkat engine = getTefkat();
TefkatListener monitorListener = new TefkatListenerAdapter() {
public void info(String message) {
if (message.equalsIgnoreCase("stratification")) {
monitor.subTask(message);
}
}
public void evaluateRule(TRule rule, Binding context, boolean cached) {
monitor.subTask("Evaluating rule: " + rule.getName());
}
public void transformationStarted(Transformation transformation, Extent[] srcs, Extent[] tgts, Extent trace, Binding context) {
monitor.worked(2);
}
public void transformationFinished() {
monitor.worked(2);
}
};
engine.addTefkatListener(monitorListener);
EngineThread thread = new EngineThread(engine, transformationR, sourcesR, targetsR, traceR);
thread.start();
while (thread.isAlive()) {
if (monitor.isCanceled()) {
getTefkat().setInterrupted(true);
thread.join(1000);
break;
}
try {
Thread.sleep(1000);
} catch (RuntimeException e1) {
}
}
engine.removeTefkatListener(monitorListener);
if (null != thread.getException()) {
throw thread.getException();
}
monitor.subTask("Storing results " + transformation);
for (int i = 0; i < targetsR.length; i++) {
setObjectIds(targetsR[i]);
targetsR[i].save(SERIALIZATION_OPTIONS);
}
if (null != traceR) {
setObjectIds(traceR);
traceR.save(SERIALIZATION_OPTIONS);
}
monitor.worked(1);
} catch (Exception e) {
String message = e.getMessage();
if (null == message) {
message = e.toString();
e.printStackTrace();
}
IStatus status = new Status(IStatus.ERROR, TefkatPlugin.PLUGIN_ID,
IStatus.OK, "Tefkat failed: " + message, e);
getLog().log(status);
throw new CoreException(status);
} finally {
removeTefkatListener(consoleAdapter);
theEngine = null;
// clear out loaded resources so that a reload is forced
// next time through - things may have changed so we don't
// want any cached state.
//
if (true) {
clearResourceSet();
// getTefkat().registerFactory("qvt", new TefkatResourceFactory(getTefkat().getResourceSet()));
} else {
// unloadResource(traceE.getResource());
// unloadResource(transformationE.getResource());
// for (int i = 0; i < sourcesE.length; i++) {
// unloadResource(sourcesE[i].getResource());
// }
// for (int i = 0; i < targetsE.length; i++) {
// unloadResource(targetsE[i].getResource());
// }
unloadResources();
}
}
}
private void setObjectIds(Resource res) {
if (res instanceof XMIResource) {
XMIResource xres = (XMIResource) res;
for (Iterator itr = xres.getAllContents(); itr.hasNext(); ) {
EObject obj = (EObject) itr.next();
if (null == xres.getID(obj)) {
xres.setID(obj, String.valueOf(obj.hashCode()));
}
}
}
}
public Resource[] createResources(String[] modelURIs) {
Resource[] resource = new Resource[modelURIs.length];
for (int i = 0; i < modelURIs.length; i++) {
resource[i] = createResource(modelURIs[i]);
}
return resource;
}
public Resource createResource(String modelURI) {
try {
URI uri = URI.createURI(modelURI);
return getResourceSet().createResource(uri);
} catch (Throwable t) {
throw new RuntimeException("Could not create '" + modelURI + "': "
+ t.getMessage(), t);
}
}
private Resource getResource(String modelURI, IProgressMonitor monitor) throws IOException {
Resource resource;
try {
monitor.subTask("Loading " + modelURI);
URI uri = URI.createURI(modelURI);
resource = getResourceSet().getResource(uri, true);
} catch (Throwable t) {
t.printStackTrace();
IOException e = new IOException("Could not load '" + modelURI + "': " + t.getMessage());
e.initCause(t);
throw e;
}
List errors = resource.getErrors();
if (errors.size() > 0) {
String message = "";
for (int i = 0; i < errors.size(); i++) {
Resource.Diagnostic diag = (Resource.Diagnostic) errors.get(i);
message += diag.getMessage() + ": " + diag.getLine() + ", " + diag.getColumn() + " of " + diag.getLocation() + "\n";
}
throw new IOException(message);
}
return resource;
}
private Resource[] getResources(String[] modelURIs, IProgressMonitor monitor) throws IOException {
Resource[] resources = new Resource[modelURIs.length];
for (int i = 0; i < modelURIs.length; i++) {
resources[i] = getResource(modelURIs[i], monitor);
}
return resources;
}
// private void unloadResource(Resource res) {
//// System.out.println("unloading " + res.getURI());
// res.getContents().clear();
// res.unload();
// }
// This causes meta-models to also be unloaded so that we can deal
// with changes to meta-models as well as their instances
//
private void unloadResources() {
System.out.println("Unloading all resources...");
List resources = getResourceSet().getResources();
for (Iterator itr = resources.iterator(); itr.hasNext();) {
Resource res = (Resource) itr.next();
System.out.println("clearing " + res.getURI());
res.getContents().clear();
// }
// for (Iterator itr = resources.iterator(); itr.hasNext();) {
// Resource res = (Resource) itr.next();
System.out.println("unloading " + res.getURI());
res.unload();
}
// System.out.println("Cleaned up " + resources.size() + " resources.");
// resources.clear();
System.out.println("...resources unloaded.");
}
private ResourceSet _resourceSet = null;
public ResourceSet getResourceSet() {
if (null == _resourceSet) {
_resourceSet = new ResourceSetImpl();
_resourceSet.getLoadOptions().putAll(SERIALIZATION_OPTIONS);
Map map = _resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap();
map.put("ecore", ECORE_RESOURCE_FACTORY);
map.put("xmi", XMI_RESOURCE_FACTORY);
map.put("tefkat", XMI_RESOURCE_FACTORY);
// map.put("qvt", TEFKAT_RESOURCE_FACTORY);
map.put("xsd", XSD_RESOURCE_FACTORY);
map.put("wsdl", XSD_RESOURCE_FACTORY);
map.put("xml", XML_RESOURCE_FACTORY);
}
return _resourceSet;
}
public void clearResourceSet() {
if (null != _resourceSet) {
_resourceSet = null;
}
if (null != theEngine) {
theEngine.clearResourceSet();
}
}
private static class EngineThread extends Thread {
private Tefkat engine;
private Resource transformation;
private Resource[] sources;
private Resource[] targets;
private Resource trace;
private Exception exception;
public EngineThread(final Tefkat engine, final Resource transformation, final Resource[] sources, final Resource[] targets, final Resource trace) {
this.engine = engine;
this.transformation = transformation;
this.sources = sources;
this.targets = targets;
this.trace = trace;
final IWorkbench workbench = PlatformUI.getWorkbench();
workbench.getDisplay().syncExec(new Runnable() {
public void run() {
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
IViewPart view = page.findView("tefkat.plugin.TefkatView");
if (null != view && page.isPartVisible(view)) {
TefkatListener listener = (TefkatListener) view.getAdapter(TefkatListener.class);
if (null != listener) {
engine.addTefkatListener(listener);
}
}
view = page.findView("tefkat.plugin.TefkatTransformationView");
if (null != view && page.isPartVisible(view)) {
TefkatListener listener = (TefkatListener) view.getAdapter(TefkatListener.class);
if (null != listener) {
engine.addTefkatListener(listener);
}
}
}
});
}
public Exception getException() {
return exception;
}
public void run() {
try {
engine.transform(transformation, sources, targets, trace);
} catch (Exception e) {
exception = e;
} finally {
final IWorkbench workbench = PlatformUI.getWorkbench();
workbench.getDisplay().syncExec(new Runnable() {
public void run() {
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
IViewPart view = page.findView("tefkat.plugin.TefkatView");
if (null != view) {
TefkatListener listener = (TefkatListener) view.getAdapter(TefkatListener.class);
if (null != listener) {
engine.removeTefkatListener(listener);
}
}
view = page.findView("tefkat.plugin.TefkatTransformationView");
if (null != view) {
TefkatListener listener = (TefkatListener) view.getAdapter(TefkatListener.class);
if (null != listener) {
engine.removeTefkatListener(listener);
}
}
}
});
}
}
}
public RuleBasedPartitionScanner getTefkatPartitionScanner() {
if (scanner == null) {
scanner = new TefkatPartitionScanner();
}
return scanner;
}
}