/* * 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.engine; import java.awt.Dimension; import java.awt.EventQueue; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.ToolTipManager; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage.Registry; 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.Resource.Diagnostic; import org.eclipse.emf.ecore.util.ExtendedMetaData; import org.eclipse.emf.ecore.xmi.XMIResource; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.eclipse.xsd.util.XSDResourceFactoryImpl; import org.jgraph.event.GraphModelEvent; import org.jgraph.event.GraphModelListener; import tefkat.config.TefkatConfig.Configuration; import tefkat.config.TefkatConfig.Model; import tefkat.config.TefkatConfig.TransformationTask; import tefkat.config.TefkatConfig.impl.TefkatConfigPackageImpl; import tefkat.engine.trace.impl.TracePackageImpl; import tefkat.engine.view.RadialTreeLayoutAlgorithm; import tefkat.engine.view.ResourceSetModel; import tefkat.engine.view.ResourceView; import tefkat.engine.view.Visualiser; import tefkat.model.ContainerExtent; import tefkat.model.Extent; import tefkat.model.PatternUse; import tefkat.model.Query; import tefkat.model.ReferenceExtent; import tefkat.model.SourceTerm; import tefkat.model.TRule; import tefkat.model.TefkatException; import tefkat.model.TefkatFactory; import tefkat.model.Term; import tefkat.model.Transformation; import tefkat.model.Var; import tefkat.model.internal.ModelUtils; import tefkat.model.parser.TefkatLexer; import tefkat.model.parser.TefkatParser; import tefkat.model.parser.TefkatResourceFactory; import antlr.RecognitionException; import antlr.TokenStreamException; import antlr.TokenStreamHiddenTokenFilter; import antlr.debug.MessageAdapter; import antlr.debug.MessageEvent; /** * @author lawley * */ public class Main { private static final int DELAY = 1; private static final TefkatResourceFactory TEFKAT_RESOURCE_FACTORY = new TefkatResourceFactory(); private static final Resource.Factory XMI_RESOURCE_FACTORY = new XMIResourceFactoryImpl(); private static final Resource.Factory XSD_RESOURCE_FACTORY = new XSDResourceFactoryImpl(); private static boolean quiet = false; private static boolean force = false; private static boolean visualize = false; private static boolean layout = false; private static ResourceSetModel model; private static ResourceView graph; private static void usage(String message) { System.err.println(message); System.err.println("usage: tefkat [-quiet] [-debug] [-force] [-fixpoint] [-statistics] [-save] [-layout] [-vis mtsT] [-mapURI from to]*"); System.err.println("\t[-conf configURI | -transformation mappingURI"); System.err.println("\t[-source srcURI | -sourceVar var=srcURI]* [-target targetURI]* [-trace traceURI]]"); System.exit(1); } public static void main(String[] args) { boolean mapVis = false, targetVis = false, sourceVis = false, traceVis = false; boolean queryMode = false; boolean debugger = false; String configURI = null; String transformationURI = null; List sourceURIs = new ArrayList(); List targetURIs = new ArrayList(); String traceURI = null; boolean saveResult = false; JFrame frame = null; final Tefkat engine = new Tefkat(); engine.addTefkatListener(new TefkatListenerAdapter() { public void resourceLoaded(Resource res) { if (!quiet) { System.err.println("Loaded " + res.getURI()); } displayDiagnostics("Warning", res.getWarnings()); final List<Diagnostic> errors = res.getErrors(); displayDiagnostics("Error", errors); if (errors.size() > 0) { System.exit(-1); } } private void displayDiagnostics(final String prefix, final List<Diagnostic> errors) { for (final Iterator<Diagnostic> itr = errors.iterator(); itr.hasNext(); ) { final Diagnostic e = itr.next(); System.err.println(prefix + ": (" + e.getLine() + ", " + e.getColumn() + ") " + e.getMessage()); } } public void info(String message) { if (!quiet) { System.err.println("Info: " + message); } } public void warning(String message) { System.err.println("Warn: " + message); } public void error(String message, Throwable cause) { if (cause instanceof RuntimeException) { cause.printStackTrace(); } else { System.err.println("Error: " + message); for (StackTraceElement elt: cause.getStackTrace()) { if (elt.getClassName().startsWith("tefkat")) { System.err.println(" at " + elt); // break; } } } } }); ResourceSet rs = engine.getResourceSet(); Map URIMap = rs.getURIConverter().getURIMap(); Map parameters = new HashMap(); for (int i = 0; i < args.length; i++) { if (args[i].equals("-query")) { queryMode = true; } else if (args[i].equals("-layout")) { layout = true; } else if (args[i].equals("-debug")) { debugger = true; } else if (args[i].equals("-force")) { force = true; } else if (args[i].equals("-quiet")) { quiet = true; } else if (args[i].equals("-fixpoint")) { engine.setIncremental(false); } else if (args[i].equals("-statistics")) { engine.setPrintingStats(true); } else if (args[i].equals("-save")) { saveResult = true; } else if (args[i].equals("-vis")) { visualize = true; i += 1; for (int j = 0; j < args[i].length(); j++) { char c = args[i].charAt(j); switch (c) { case 'm': mapVis = true; break; case 's': sourceVis = true; break; case 't': targetVis = true; break; case 'T': traceVis = true; break; default: usage("Unknown flag for visualisation: " + c); } } } else if (args[i].equals("-mapURI")) { URI uri1 = URI.createURI(args[i+1]); URI uri2 = URI.createURI(args[i+2]); URIMap.put(uri1, uri2); URIConverter.URI_MAP.put(uri1, uri2); i += 2; } else if (args[i].equals("-conf")) { i += 1; configURI = args[i]; } else if (args[i].equals("-transformation")) { i += 1; transformationURI = args[i]; } else if (args[i].equals("-source")) { i += 1; sourceURIs.add(args[i]); } else if (args[i].equals("-sourceVar")) { i += 1; int idx = args[i].indexOf("="); String var = args[i].substring(0, idx); String uri = args[i].substring(idx+1); parameters.put(var, uri); } else if (args[i].equals("-target")) { i += 1; targetURIs.add(args[i]); } else if (args[i].equals("-trace")) { i += 1; traceURI = args[i]; } else { usage("Unknown flag: " + args[i]); } } TefkatConfigPackageImpl.init(); TracePackageImpl.init(); engine.registerFactory("qvt", TEFKAT_RESOURCE_FACTORY); engine.registerFactory("xsd", XSD_RESOURCE_FACTORY); engine.registerFactory("wsdl", XSD_RESOURCE_FACTORY); engine.registerFactory("*", XMI_RESOURCE_FACTORY); try { if (debugger) { System.err.println("debugging mode"); createDebuggerListener(engine); } if (configURI != null) { if (visualize) { frame = createUI(rs, new ArrayList(0), layout); createVisualisationListener(engine, mapVis, sourceVis, targetVis, traceVis); } Resource config = rs.getResource(URI.createURI(configURI), true); for (Iterator configItr = config.getContents().iterator(); configItr.hasNext(); ) { Object obj = configItr.next(); if (obj instanceof Configuration) { Configuration configuration = (Configuration) obj; for (Iterator pkgClsItr = configuration.getPackageClasses().iterator(); pkgClsItr.hasNext(); ) { String pkgClsName = (String) pkgClsItr.next(); Class pkgClass = Class.forName(pkgClsName); pkgClass.getDeclaredField("eINSTANCE").get(null); } for (Iterator transItr = configuration.getTransformationTasks().iterator(); transItr.hasNext(); ) { TransformationTask task = (TransformationTask) transItr.next(); if (task.isEnabled()) { // override trace URI if (null != traceURI) { task.getTrace().setLocationUri(traceURI); } // override target URIs if (targetURIs.size() > 0) { List targets = task.getTargetModels(); for (int i = 0; i < targets.size(); i++) { ((Model) targets.get(i)).setLocationUri((String) targetURIs.get(i)); } } engine.transform(task, saveResult, force); } } } else { System.err.println("Warning: " + obj + " is not a Configuration instance."); } } } else if (queryMode) { ReferenceExtent extent = TefkatFactory.eINSTANCE.createReferenceExtent(); List extentResources = extent.getResources(); // for (Iterator itr = parameters.entrySet().iterator(); itr.hasNext(); ) { // Map.Entry entry = (Map.Entry) itr.next(); // URI uri = URI.createURI((String) entry.getValue()); // entry.setValue(rs.getResource(uri, true)); // } for (Iterator itr = sourceURIs.iterator(); itr.hasNext(); ) { URI uri = URI.createURI((String) itr.next()); extentResources.add(rs.getResource(uri, true)); } Query query = TefkatFactory.eINSTANCE.createQuery(); query.setName(""); Var srcExtent = TefkatFactory.eINSTANCE.createVar(); srcExtent.setName("Source"); Resource r = rs.createResource(URI.createURI("query")); r.getContents().add(query); Binding context = new Binding(); context.add(srcExtent, extent); final Map packageNameMap = new HashMap(); System.out.println("Global packages: " + Registry.INSTANCE.keySet()); System.out.println("Local packages: " + rs.getPackageRegistry().keySet()); ModelUtils.buildPackageNameMaps(Registry.INSTANCE.values(), packageNameMap, "global"); ModelUtils.buildPackageNameMaps(rs.getPackageRegistry().values(), packageNameMap, "locate"); // loop until EOF boolean done; do { try { done = readAndEvalQuery(engine, query, srcExtent, context, packageNameMap); } catch (ResolutionException e) { System.err.println(e); done = false; } catch (RecognitionException e) { System.err.println(e); done = false; } catch (TokenStreamException e) { System.err.println(e); done = false; } } while (!done); } else { if (transformationURI == null) { usage("Must specify a config URI or a transformation URI"); } Resource transformation = rs.getResource(URI.createURI(transformationURI), true); int j; for (Iterator itr = parameters.entrySet().iterator(); itr.hasNext(); ) { Map.Entry entry = (Map.Entry) itr.next(); URI uri = URI.createURI((String) entry.getValue()); entry.setValue(rs.getResource(uri, true)); } Resource[] srcs = new Resource[sourceURIs.size()]; j = 0; for (Iterator itr = sourceURIs.iterator(); itr.hasNext(); j++) { URI uri = URI.createURI((String) itr.next()); srcs[j] = rs.getResource(uri, true); } Resource[] tgts = new Resource[targetURIs.size()]; j = 0; for (Iterator itr = targetURIs.iterator(); itr.hasNext(); j++) { URI uri = URI.createURI((String) itr.next()); tgts[j] = rs.createResource(uri); } Resource trace = null; if (traceURI != null) { trace = rs.createResource(URI.createURI(traceURI)); } if (visualize) { List resList = new ArrayList(); if (mapVis) { resList.add(transformation); } if (sourceVis) { resList.addAll(Arrays.asList(srcs)); } if (targetVis) { resList.addAll(Arrays.asList(tgts)); } if (traceVis) { resList.add(trace); } frame = createUI(engine.getResourceSet(), resList, layout); createVisualisationListener(engine, mapVis, sourceVis, targetVis, traceVis); } System.out.println("transforming..."); engine.transform(transformation, parameters, srcs, tgts, trace, false); if (saveResult) { Map options = new HashMap(); options.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); options.put(XMLResource.OPTION_EXTENDED_META_DATA, ExtendedMetaData.INSTANCE); for (int i = 0; i < tgts.length; i++) { setObjectIds(tgts[i]); tgts[i].save(options); } if (null != trace) { setObjectIds(trace); trace.save(options); } } System.out.println("...done"); } if (visualize) { final JFrame theFrame = frame; // Be thread-safe EventQueue.invokeLater(new Runnable() { public void run() { theFrame.repaint(); } }); Thread.sleep(5000); } } catch (ResolutionException e) { } catch (Throwable t) { t.printStackTrace(); // } finally { // System.exit(0); } } private static boolean readAndEvalQuery(final Tefkat engine, final Query query, final Var srcExtent, final Binding context, final Map namespace) throws RecognitionException, TokenStreamException, ResolutionException, TefkatException, IOException { System.out.println("Enter query:"); final StringBuilder sb = new StringBuilder(); final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // Need to preserve EOL in input since parsing of NAMESPACE/IMPORT depends on it :( String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); final String trim = line.trim(); if (trim.endsWith(";") || trim.startsWith("NAMESPACE")) { break; } } TefkatLexer lexer = new TefkatLexer(new StringReader(sb.toString())); // use nonstandard token object lexer.setTokenObjectClass("antlr.CommonHiddenStreamToken"); // create the filter TokenStreamHiddenTokenFilter filter = new TokenStreamHiddenTokenFilter(lexer); // hide not discard filter.hide(TefkatParser.COMMENT); filter.hide(TefkatParser.WS); TefkatParser parser = new TefkatParser(filter); parser.addMessageListener(new MessageAdapter() { public void reportError(MessageEvent e) { System.err.println("parser error: " + e); } public void reportWarning(MessageEvent e) { System.err.println("parser warning: " + e); } }); parser.trackingMap.putAll(namespace); query.getVars().clear(); query.getParameterVar().clear(); query.getVars().add(srcExtent); SourceTerm stmt = parser.queryStatement(query, srcExtent); if (null != stmt) { query.setTerm(stmt); Collection<Binding> answers = engine.evaluateQuery(context, query); if (null != answers) { for (Binding b: answers) { System.out.println(b); } System.out.println(answers.size() + " results."); } else { System.out.println("No."); } } namespace.putAll(parser.trackingMap); return sb.length() == 0 && null == line; } /** * Sets the XMI IDs of the objects and avoids duplicates in the XMIResource * @param res */ private static void setObjectIds(Resource res) { if (res instanceof XMIResource) { XMIResource xres = (XMIResource) res; Object[] roots = xres.getContents().toArray(); for (int i = roots.length - 1; i >= 0; i--) { EObject obj = (EObject) roots[i]; fixObjectId(xres, obj); } } } private static void fixObjectId(XMIResource xres, EObject obj) { // Set XMI ID if not already set if (null == xres.getID(obj)) { xres.setID(obj, String.valueOf(obj.hashCode())); } // remove direct containment for things that are transitively contained if (null != obj.eContainer()) { xres.getContents().remove(obj); } Object[] children = obj.eContents().toArray(); for (int i = children.length - 1; i >= 0; i--) { fixObjectId(xres, (EObject) children[i]); } } /** * @param engine */ private static void createDebuggerListener(final Tefkat engine) { engine.addTefkatListener(new TefkatListenerAdapter() { int depth = 0; public void started() { engine.pause(); } public void suspended() { try { int c; do { c = System.in.read(); } while (c >= 0 && c != '\n'); if (c < 0) { engine.setInterrupted(true); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } engine.step(); } public void enterTerm(Node node) { depth++; indent(depth, '>'); System.err.print(" " + node.selectedLiteral() + " ? "); } public void exitTerm(Node node) { System.err.println(node.getBindings()); indent(depth, '<'); System.err.println(" " + !node.isFailure()); depth--; } public void delayTerm(Node node) { System.err.println(node.getBindings()); indent(depth, '-'); System.err.println(" delayed"); depth--; } private void indent(int n, char c) { for (int i = 0; i < n; i++) { System.err.print(c); } } }); } /** * @param engine */ private static void createVisualisationListener(Tefkat engine, final boolean mapVis, final boolean sourceVis, final boolean targetVis, final boolean traceVis) { engine.addTefkatListener(new TefkatListenerAdapter() { public void resourceLoaded(Resource res) { System.err.println("Loaded " + res.getURI()); } public void transformationStarted(Transformation transformation, Extent[] srcs, Extent[] tgts, Extent trace, Binding context) { if (mapVis) { model.addResource(transformation.eResource()); } if (sourceVis) { for (int i = 0; i < srcs.length; i++) { if (srcs[i] instanceof ContainerExtent) { model.addResource(((ContainerExtent) srcs[i]).getResource()); } else { for (Iterator itr = ((ReferenceExtent) srcs[i]).getResources().iterator(); itr.hasNext(); ) { model.addResource((Resource) itr.next()); } } } } if (targetVis) { for (int i = 0; i < tgts.length; i++) { if (tgts[i] instanceof ContainerExtent) { model.addResource(((ContainerExtent) tgts[i]).getResource()); } else { for (Iterator itr = ((ReferenceExtent) tgts[i]).getResources().iterator(); itr.hasNext(); ) { model.addResource((Resource) itr.next()); } } } } if (traceVis) { if (trace instanceof ContainerExtent) { model.addResource(((ContainerExtent) trace).getResource()); } else { for (Iterator itr = ((ReferenceExtent) trace).getResources().iterator(); itr.hasNext(); ) { model.addResource((Resource) itr.next()); } } } } public void evaluateRule(TRule rule, Binding context, boolean cached) { if (mapVis) { ExtentUtil.highlightNode(rule, ExtentUtil.RULE_EVAL); } } public void enterTerm(Node node) { if (mapVis) { Term term = node.selectedLiteral(); if (term instanceof PatternUse) { ExtentUtil.highlightNode(((PatternUse) term) .getDefn(), ExtentUtil.TERM_ENTER); } ExtentUtil.highlightNode(term, ExtentUtil.TERM_ENTER); } } public void exitTerm(Node node) { if (mapVis) { Term term = node.selectedLiteral(); if (term instanceof PatternUse) { ExtentUtil.highlightNode(((PatternUse) term) .getDefn(), ExtentUtil.TERM_EXIT); } ExtentUtil.highlightNode(term, ExtentUtil.TERM_EXIT); } } public void delayTerm(Node node) { if (mapVis) { Term term = node.selectedLiteral(); if (term instanceof PatternUse) { ExtentUtil.highlightNode(((PatternUse) term).getDefn(), ExtentUtil.TERM_DELAY); } ExtentUtil.highlightNode(term, ExtentUtil.TERM_DELAY); } } }); } private static JFrame createUI(ResourceSet resourceSet, List resources, boolean layout) { model = new ResourceSetModel(resourceSet); graph = new ResourceView(model); for (int i = 0; i < resources.size(); i++) { model.addResource((Resource) resources.get(i)); } ToolTipManager.sharedInstance().registerComponent(graph); try { final RadialTreeLayoutAlgorithm layoutAlg = new RadialTreeLayoutAlgorithm(); final Properties props = new Properties(); props.setProperty(RadialTreeLayoutAlgorithm.KEY_WIDTH, "1200"); props.setProperty(RadialTreeLayoutAlgorithm.KEY_HEIGHT, "1000"); layoutAlg.perform(graph, true, props); if (layout) { final LayoutThread layoutThread = new LayoutThread(props, layoutAlg); layoutThread.start(); graph.getModel().addGraphModelListener( new GraphModelListener() { public void graphChanged(GraphModelEvent evt) { Object[] inserted = evt.getChange().getInserted(); if (null == inserted || inserted.length == 0) { return; } if (graph.getModel().getRootCount() > 0) { layoutThread.requestLayout(); // layoutAlg.perform(graph, true, props); } } }); } } catch (Exception e) { e.printStackTrace(); } graph.setMinimumSize(new Dimension(1200, 1000)); final JFrame frame = new JFrame(); frame.getContentPane().add(new JScrollPane(graph)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); // Be thread-safe EventQueue.invokeLater(new Runnable() { public void run() { frame.setVisible(true); } }); ExtentUtil.addExtentListener(new Visualiser(graph, DELAY)); return frame; } private static final class LayoutThread extends Thread { private transient boolean layoutRequested = false; private final Properties props; private final RadialTreeLayoutAlgorithm layoutAlg; LayoutThread(Properties props, RadialTreeLayoutAlgorithm layoutAlg) { this.props = props; this.layoutAlg = layoutAlg; } synchronized public void requestLayout() { layoutRequested = true; if (!isAlive()) { System.err.println("launch"); start(); } notifyAll(); System.err.println("requested"); } public void run() { boolean doLayout = false; while (true) { synchronized (this) { if (layoutRequested) { doLayout = true; layoutRequested = false; } else { doLayout = false; try { wait(); } catch (InterruptedException e) { } } } if (doLayout) { long start = System.currentTimeMillis(); try { System.err.println("start..."); layoutAlg.perform(graph, true, props); System.err.println("...stop"); } catch (Throwable t) { t.printStackTrace(); } finally { long end = System.currentTimeMillis(); System.err.println("layout time: " + (end - start)); } } } } } }