| /******************************************************************************* |
| * Copyright (c) 2014, 2018 Willink Transformations and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * R.Dvorak and others - QVTo debugger framework |
| * E.D.Willink - revised API for OCL debugger framework |
| *******************************************************************************/ |
| package org.eclipse.ocl.examples.debug.vm.launching; |
| |
| import java.io.IOException; |
| |
| import org.eclipse.emf.common.util.BasicDiagnostic; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.examples.debug.vm.core.EvaluationContext; |
| import org.eclipse.ocl.examples.debug.vm.evaluator.IVMContext; |
| import org.eclipse.ocl.examples.debug.vm.evaluator.VMExecutor; |
| import org.eclipse.ocl.examples.debug.vm.messages.VMMessages; |
| import org.eclipse.ocl.examples.debug.vm.request.VMStartRequest; |
| import org.eclipse.ocl.examples.debug.vm.utils.CompiledUnit; |
| import org.eclipse.ocl.examples.debug.vm.utils.EmfUtil; |
| import org.eclipse.ocl.examples.debug.vm.utils.ExecutionDiagnostic; |
| import org.eclipse.ocl.examples.debug.vm.utils.ExecutionDiagnosticImpl; |
| import org.eclipse.ocl.examples.debug.vm.utils.Log; |
| import org.eclipse.ocl.examples.debug.vm.utils.Messages; |
| import org.eclipse.ocl.examples.debug.vm.utils.VMException; |
| import org.eclipse.ocl.examples.debug.vm.utils.VMInterruptedExecutionException; |
| import org.eclipse.ocl.examples.debug.vm.utils.VMRuntimeException; |
| import org.eclipse.ocl.examples.debug.vm.utils.VMStackOverFlowError; |
| import org.eclipse.ocl.pivot.NamedElement; |
| import org.eclipse.ocl.pivot.utilities.ParserException; |
| import org.eclipse.ocl.pivot.values.InvalidValueException; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * Internal transformation executor |
| */ |
| public abstract class InternalDebuggableExecutor |
| { |
| private static boolean isSuccess(Diagnostic diagnostic) { |
| int severity = diagnostic.getSeverity(); |
| return severity == Diagnostic.OK || severity == Diagnostic.WARNING |
| || severity == Diagnostic.INFO; |
| } |
| |
| protected final @NonNull IVMContext vmContext; |
| protected final @NonNull URI debuggableURI; |
| // private EPackage.Registry fPackageRegistry; |
| private @Nullable CompiledUnit fCompiledUnit; |
| private ResourceSet fCompilationRs; |
| private ExecutionDiagnosticImpl fLoadDiagnostic; |
| // private Transformation fTransformation; |
| private @Nullable VMExecutor vmExecutor; |
| // private @Nullable Trace fTraces; |
| |
| |
| /** |
| * Constructs the executor for the given transformation URI. |
| * <p> |
| * No attempt to resolve and load the transformation is done at this step |
| */ |
| protected InternalDebuggableExecutor(@NonNull IVMContext vmContext, @NonNull URI debuggableURI) { |
| this.vmContext = vmContext; |
| this.debuggableURI = debuggableURI; |
| } |
| |
| /* private void checkLegalModelParams(ModelExtent[] extents) |
| throws IllegalArgumentException { |
| if (extents == null) { |
| throw new IllegalArgumentException("Null model parameters"); //$NON-NLS-1$ |
| } |
| |
| for (int i = 0; i < extents.length; i++) { |
| if (extents[i] == null) { |
| throw new IllegalArgumentException( |
| "Null model parameter[" + i + "]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } */ |
| |
| public void cleanup() { |
| // setEnvironmentFactory(null); |
| if (fCompilationRs != null) { |
| EmfUtil.cleanupResourceSet(fCompilationRs); |
| } |
| } |
| |
| private static ExecutionDiagnostic createExecutionFailure(@NonNull InvalidValueException vmRuntimeException) { |
| int code = 0; |
| int severity = Diagnostic.ERROR; |
| String message = vmRuntimeException.getLocalizedMessage(); |
| Object[] data = null; |
| |
| if (vmRuntimeException instanceof VMException) { |
| code = /*((VMException) vmRuntimeException).getExceptionType() == QvtOperationalStdLibrary.INSTANCE.getAssertionFailedClass() ? |
| ExecutionDiagnostic.FATAL_ASSERTION :*/ ExecutionDiagnostic.EXCEPTION_THROWN; |
| } else if (vmRuntimeException instanceof VMInterruptedExecutionException) { |
| code = ExecutionDiagnostic.USER_INTERRUPTED; |
| severity = Diagnostic.CANCEL; |
| } else { |
| code = ExecutionDiagnostic.EXCEPTION_THROWN; |
| if (vmRuntimeException instanceof VMStackOverFlowError == false) { |
| Throwable cause = vmRuntimeException.getCause(); |
| data = new Object[] { cause != null ? cause : vmRuntimeException }; |
| } else { |
| message = Messages.StackTraceOverFlowError; |
| } |
| } |
| |
| if (message == null) { |
| message = NLS.bind(Messages.VMRuntimeExceptionCaught, |
| vmRuntimeException.getClass().getName()); |
| } |
| ExecutionDiagnosticImpl diagnostic = new ExecutionDiagnosticImpl(severity, code, message, data); |
| if (vmRuntimeException instanceof VMRuntimeException) { |
| diagnostic.setStackTrace(((VMRuntimeException)vmRuntimeException).getVMStackTrace()); |
| } |
| return diagnostic; |
| } |
| |
| private @NonNull EvaluationContext createInternalContext(@NonNull EvaluationContext evaluationContext) { |
| EvaluationContext ctx = evaluationContext; //new Context(); |
| // ctx.setLog(xtextEvaluator.getLog()); |
| // ctx.setMonitor(xtextEvaluator.getMonitor()); |
| |
| // for (String key : xtextEvaluator.getConfigPropertyNames()) { |
| // String value = xtextEvaluator.getConfigProperty(key); |
| // ctx.setConfigProperty(key, value); |
| // } |
| |
| return ctx; |
| } |
| |
| protected abstract @NonNull VMExecutor createVMExecutor() throws IOException, ParserException; |
| |
| private ExecutionDiagnostic doExecute(@NonNull VMStartRequest startRequest, /*ModelExtent[] args,*/ @NonNull EvaluationContext evaluationContext) throws IOException { |
| // QvtOperationalEnvFactory factory = getEnvironmentFactory(); |
| // QVTiXtextEvaluator evaluator = null; //evaluationContext.getEvaluator(); |
| |
| |
| // ExecutionDiagnostic modelParamsDiagnostic = initArguments(evaluationEnv, fTransformation, args); |
| // if (modelParamsDiagnostic.getSeverity() != Diagnostic.OK) { |
| // return modelParamsDiagnostic; |
| // } |
| |
| // QvtOperationalFileEnv rootEnv = factory.createEnvironment(fCompiledUnit.getURI()); |
| // EvaluationVisitor<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> evaluator = factory |
| // .createEvaluationVisitor(rootEnv, evaluationEnv, null); |
| |
| // perform the actual execution |
| // assert evaluator instanceof InternalEvaluator : "expecting InternalEvaluator implementation"; //$NON-NLS-1$ |
| // InternalEvaluator rawEvaluator = (InternalEvaluator) evaluator; |
| |
| VMExecutor vmEvaluator2 = vmExecutor; |
| if (vmEvaluator2 != null) { |
| vmEvaluator2.setSuspendOnStartUp(startRequest.suspendOnStartup); |
| vmEvaluator2.execute(); |
| } |
| |
| // unpack the internal extents into the passed model parameters |
| /* List<Object> resultArgs = evaluationEnv.getOperationArgs(); |
| int i = 0; |
| for (Object nextResultArg : resultArgs) { |
| ModelInstance modelInstance = (ModelInstance) nextResultArg; |
| ModelParameterExtent extent = modelInstance.getExtent(); |
| |
| List<EObject> allRootElements = extent.getContents().getAllRootElements(); |
| try { |
| args[i++].setContents(allRootElements); |
| } catch (UnsupportedOperationException e) { |
| return new ExecutionDiagnosticImpl(Diagnostic.ERROR, |
| ExecutionDiagnostic.MODEL_PARAMETER_MISMATCH, NLS |
| .bind(Messages.ReadOnlyExtentModificationError, |
| i - 1)); |
| } |
| } */ |
| |
| // do some handy processing with traces |
| // Trace traces = evaluationEnv.getAdapter(InternalEvaluationEnv.class).getTraces(); |
| // handleExecutionTraces(traces); |
| |
| return ExecutionDiagnostic.OK_INSTANCE; |
| } |
| |
| private void doLoad() { |
| fLoadDiagnostic = ExecutionDiagnosticImpl.OK_INSTANCE; |
| try { |
| VMExecutor vmExecutor2 = createVMExecutor(); |
| vmExecutor = vmExecutor2; |
| fCompiledUnit = new CompiledUnit(vmExecutor2.getDebuggable()); |
| } catch (Exception e) { |
| fLoadDiagnostic = new ExecutionDiagnosticImpl(Diagnostic.ERROR, |
| ExecutionDiagnostic.TRANSFORMATION_LOAD_FAILED, NLS.bind( |
| Messages.FailedToCompileUnitError, debuggableURI)); |
| |
| fLoadDiagnostic.merge(BasicDiagnostic.toDiagnostic(e)); |
| } |
| /* UnitProxy unit = UnitResolverFactory.Registry.INSTANCE.getUnit(fURI); |
| if (unit == null) { |
| fLoadDiagnostic = new ExecutionDiagnosticImpl(Diagnostic.ERROR, |
| ExecutionDiagnostic.TRANSFORMATION_LOAD_FAILED, NLS.bind( |
| Messages.UnitNotFoundError, fURI)); |
| return; |
| } |
| |
| OCLCompiler compiler = createCompiler(); |
| try { |
| fCompiledUnit = compiler.compile(unit, null, null); |
| fCompilationRs = compiler.getResourceSet(); |
| // fCompilerKernel = compiler.getKernel(); |
| |
| fLoadDiagnostic = createCompilationDiagnostic(fCompiledUnit); |
| |
| } catch (MdaException e) { |
| fLoadDiagnostic = new ExecutionDiagnosticImpl(Diagnostic.ERROR, |
| ExecutionDiagnostic.TRANSFORMATION_LOAD_FAILED, NLS.bind( |
| Messages.FailedToCompileUnitError, fURI)); |
| |
| fLoadDiagnostic.merge(BasicDiagnostic.toDiagnostic(e)); |
| } |
| |
| if (fCompiledUnit != null |
| && fLoadDiagnostic.getSeverity() == Diagnostic.OK) { |
| fTransformation = getTransformation(); |
| if (fTransformation == null) { |
| fLoadDiagnostic = new ExecutionDiagnosticImpl(Diagnostic.ERROR, |
| ExecutionDiagnostic.TRANSFORMATION_LOAD_FAILED, NLS |
| .bind(Messages.NotTransformationInUnitError, |
| fURI)); |
| return; |
| } |
| |
| ExecutionDiagnosticImpl validForExecution = checkIsExecutable(fTransformation); |
| if (validForExecution.getSeverity() != Diagnostic.OK) { |
| fLoadDiagnostic = validForExecution; |
| } |
| } */ |
| } |
| |
| /** |
| * Executes the transformation referred by this executor using the given |
| * model parameters and execution context. |
| * |
| * @return the diagnostic object indicating the execution result status, |
| * also keeping the details of possible problems |
| * @throws IllegalArgumentException |
| * if the context or any of the model parameters is |
| * <code>null</code> |
| */ |
| public ExecutionDiagnostic execute(@NonNull VMStartRequest startRequest, @NonNull EvaluationContext evaluationContext/*, ModelExtent... modelParameters*/) { |
| // checkLegalModelParams(modelParameters); |
| |
| // ensure transformation unit is loaded |
| loadDebuggable(); |
| |
| // check if we have successfully loaded the transformation unit |
| if (!isSuccess(fLoadDiagnostic)) { |
| return fLoadDiagnostic; |
| } |
| |
| try { |
| return doExecute(startRequest, /*modelParameters,*/ createInternalContext(evaluationContext)); |
| } catch (InvalidValueException e) { |
| Log logger = evaluationContext.getLog(); |
| if (logger != null) { |
| logger.log(VMMessages.TerminatingExecution); |
| } |
| return createExecutionFailure(e); |
| // } catch (VMRuntimeException e) { |
| // Log logger = evaluationContext.getLog(); |
| // if (logger != null) { |
| // logger.log(EvaluationMessages.TerminatingExecution); |
| // } |
| // return createExecutionFailure(e); |
| } catch (Exception e) { |
| Log logger = evaluationContext.getLog(); |
| if (logger != null) { |
| logger.log(VMMessages.TerminatingExecution); |
| } |
| return createExecutionFailure(new VMRuntimeException("Execution failed", e)); |
| } |
| } |
| |
| public @Nullable NamedElement getDebuggable() { |
| // TODO - cached the transformation selected as main |
| // if (fCompiledUnit == null) { |
| // return null; |
| // } |
| |
| // List<Module> allModules = fCompiledUnit.getModules(); |
| // for (Module module : allModules) { |
| // if (module instanceof OperationalTransformation) { |
| // return (OperationalTransformation) module; |
| // } |
| // } |
| |
| VMExecutor xtextEvaluator2 = vmExecutor; |
| return xtextEvaluator2 != null ? xtextEvaluator2.getDebuggable() : null; |
| } |
| |
| public ResourceSet getResourceSet() { |
| return fCompilationRs; |
| } |
| |
| public @NonNull URI getURI() { |
| return debuggableURI; |
| } |
| |
| /** |
| * Retrieves compiled unit if the referencing URI gets successfully resolved |
| * <p> |
| * <b>Remark</b>: This method invocation causes the referenced transformation to |
| * load if not already done before by direct call to |
| * {@linkplain #loadDebuggable()} or |
| * |
| * @return compiled unit or <code>null</code> if it failed to be obtained |
| */ |
| public @Nullable CompiledUnit getUnit() { |
| loadDebuggable(); |
| return fCompiledUnit; |
| } |
| |
| public @NonNull IVMContext getVMContext() { |
| return vmContext; |
| } |
| |
| public VMExecutor getVMExecutor() { |
| return vmExecutor; |
| } |
| |
| /** |
| * Attempts to load the transformation referred by this executor and checks |
| * if it is valid for execution. |
| * <p> |
| * <b>Remark:</b><br> Only the first performs the actual transformation |
| * loading, subsequent calls to this method will return the existing |
| * diagnostic. |
| * |
| * @return the diagnostic indicating possible problems of the load action |
| */ |
| public Diagnostic loadDebuggable() { |
| if (fLoadDiagnostic == null) { |
| doLoad(); |
| } |
| return fLoadDiagnostic; |
| } |
| |
| @Override |
| public String toString() { |
| return "OCL-Executor: " + debuggableURI; //$NON-NLS-1$ |
| } |
| } |