/* * License (BSD Style License): * Copyright (c) 2011 * Software Engineering * Department of Computer Science * Technische Universitiät Darmstadt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the Software Engineering Group or Technische * Universität Darmstadt nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package de.tud.cs.st.vespucci.versioning; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; 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.impl.ResourceSetImpl; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.m2m.qvt.oml.BasicModelExtent; import org.eclipse.m2m.qvt.oml.ExecutionContextImpl; import org.eclipse.m2m.qvt.oml.ExecutionDiagnostic; import org.eclipse.m2m.qvt.oml.ModelExtent; import org.eclipse.m2m.qvt.oml.TransformationExecutor; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import de.tud.cs.st.vespucci.exceptions.VespucciIOException; import de.tud.cs.st.vespucci.exceptions.VespucciTransformationFailedException; import de.tud.cs.st.vespucci.exceptions.VespucciUnexpectedException; import de.tud.cs.st.vespucci.versioning.versions.VespucciVersionTemplate; import de.tud.cs.st.vespucci.vespucci_model.impl.ShapesDiagramImpl; /** * Template class which supplies various methods for Vespucci file transformations. * * @author Dominic Scheurer */ public abstract class VespucciTransformationHelper { /** * @return The progress monitor stored in the specific converter class. */ protected abstract IProgressMonitor getProgressMonitor(); /** * @return The destination version to convert onto. */ protected abstract VespucciVersionTemplate getVespucciVersion(); /** * @param file * The file from which to retrieve the URI * @return The platform resource URI to the given file. */ protected static URI getUriFromFile(final IFile file) { return URI.createPlatformResourceURI(file.getFullPath().toString(), true); } /** * @param fileURI * URI to the file which contents are to be loaded. * @return Returns true only if resource for the given file URI does exists. */ protected static boolean resourceExists(final URI fileURI) { final ResourceSetImpl rs = new ResourceSetImpl(); final EObject result = rs.getEObject(fileURI.appendFragment("/"), true); return result != null; } /** * @return The shell of the active workbench window. */ protected static Shell getShell() { return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); } /** * @param file * The file which is being transformed. * @return The message displayed at the beginning of the transformation. */ protected String getTransformationMessage(final IFile file) { return String.format("Converting Vespucci diagram \"%s\" from version %s to version %s.", file, getVespucciVersion() .getPredecessor().getNamespace(), getVespucciVersion().getNamespace()); } /** * Saves transformation result contents to a given URI. * * @param modelTransformationResult * Transformation result contents for the model part. * @param diagramTransformationResult * Transformation result contents for the notation part. * @param saveToUri * Destination URI. */ protected void saveResults( final ModelExtent modelTransformationResult, final ModelExtent diagramTransformationResult, final URI saveToUri) { final List<EObject> outObjectsModel = modelTransformationResult.getContents(); final List<EObject> outObjectsDiagram = diagramTransformationResult.getContents(); final Resource outputResource = new ResourceSetImpl().createResource(saveToUri); outputResource.getContents().addAll(outObjectsModel); outputResource.getContents().addAll(outObjectsDiagram); try { outputResource.save(Collections.EMPTY_MAP); } catch (final IOException e) { handleError(e); } } /** * Creates a backup of the given file. * * @param originalFile * The file to rename. * @param backupFile * Pointer to the new file location. * @param monitor * The progress monitor to use to illustrate the renaming progress. */ protected void createBackup(final IFile originalFile, final File backupFile, final IProgressMonitor monitor) { File inputFile = originalFile.getRawLocation().toFile(); File outputFile = backupFile; try { FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) { out.write(c); } in.close(); out.close(); } catch (IOException ieException) { throw new VespucciIOException("Could not backup the original File", ieException); } try { originalFile.getParent().refreshLocal(IResource.DEPTH_ONE, monitor); } catch (CoreException coreException) { throw new VespucciUnexpectedException("Could not refresh current folder", coreException); } } /** * Error handling method; shows a message box including the error message and throws a new Vespucci runtime * exception - thus, methods which utilize this error handling routing may return null after calling it. * * @param ex * The source exception. */ private void handleError(final Exception ex) { getProgressMonitor().done(); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { MessageDialog.openError(getShell(), getDefaultErrorString(), MessageFormat.format("{0}: {1}", ex.getClass() .getSimpleName(), ex.getMessage() == null ? "no message" : ex.getMessage())); } }); throw new VespucciTransformationFailedException(getDefaultErrorString(), ex); } /** * @return The default transformation error string for the specific Vespucci version. */ protected String getDefaultErrorString() { return String.format("Conversion of Vespucci diagram to version %s failed.", getVespucciVersion().getNamespace()); } /** * @param inputObjects The list of model contents of the file to transform. * @return * Input objects for the transformation: Vespucci model part first, diagram part at the end. */ protected VespucciTransformationInput[] getModelTransformationInputs(EList<EObject> inputObjects) { if (!(inputObjects.get(0) instanceof ShapesDiagramImpl)) { Collections.swap(inputObjects, 0, 1); } return new VespucciTransformationInput[] { new VespucciTransformationInput( getVespucciVersion().getModelQvtoUri(), inputObjects.get(0)), new VespucciTransformationInput( getVespucciVersion().getDiagramQvtoUri(), inputObjects.get(1)) }; } /** * Executes the QVT transformations defined by the given transformation * input objects. * * @param transformationInputs The input objects for the transformations. * @return * A transformation result object containing status information * and, if existing, the transformation result. */ protected VespucciTransformationOutput executeQvtTransformations( VespucciTransformationInput[] transformationInputs) { ArrayList<ModelExtent> transformationOutputs = new ArrayList<ModelExtent>(2); for (VespucciTransformationInput transformationInput : transformationInputs) { TransformationExecutor executor = new TransformationExecutor(transformationInput.getQvtoUri()); ModelExtent input = new BasicModelExtent(transformationInput.getModelContentAsList()); ModelExtent output = new BasicModelExtent(); ExecutionContextImpl context = new ExecutionContextImpl(); //TODO Look up what the following line is for - @see{http://wiki.eclipse.org/QVTOML/Examples/InvokeInJava} context.setConfigProperty("keepModeling", true); ExecutionDiagnostic transformationOutput = executor.execute(context, input, output); if(transformationOutput.getSeverity() == Diagnostic.OK) { transformationOutputs.add(output); } else { IStatus status = BasicDiagnostic.toIStatus(transformationOutput); Activator.getDefault().getLog().log(status); return new VespucciTransformationOutput(null, status); } } return new VespucciTransformationOutput(transformationOutputs, Status.OK_STATUS); } /** * Simple struct-like class to encapsulate transformation input * information. * * @author Dominic Scheurer */ protected static class VespucciTransformationInput { /** The URI to the QVTO transformation code */ private URI qvtoUri = null; /** The model content to transform */ private EObject modelContent = null; /** * @param qvtoUri The URI to the QVTO transformation code. * @param modelContent The model content to transform. */ protected VespucciTransformationInput( URI qvtoUri, EObject modelContent) { this.qvtoUri = qvtoUri; this.modelContent = modelContent; } /** * @return The URI to the QVTO transformation code. */ public URI getQvtoUri() { return qvtoUri; } /** * @return The model content to transform. */ public List<EObject> getModelContentAsList() { final List<EObject> result = new ArrayList<EObject>(); result.add(modelContent); return result; } } /** * Simple struct-like class to encapsulate transformation output * information. * * @author Dominic Scheurer */ protected static class VespucciTransformationOutput { /** List of transformation result objects */ private ArrayList<ModelExtent> transformationResults = null; /** Status code supplying information about possible errors */ private IStatus returnCode = null; /** * @param transformationResults List of transformation result objects. * @param returnCode Status code supplying information about possible errors. */ protected VespucciTransformationOutput(ArrayList<ModelExtent> transformationResults, IStatus returnCode) { this.transformationResults = new ArrayList<ModelExtent>(transformationResults); this.returnCode = returnCode; } /** * @return List of transformation result objects. */ public ArrayList<ModelExtent> getTransformationResults() { return new ArrayList<ModelExtent>(transformationResults); } /** * @return Status code supplying information about possible errors. */ public IStatus getReturnCode() { return returnCode; } } }