| /******************************************************************************* |
| * Copyright (c) 2007, 2018 Borland Software Corporation 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: |
| * Borland Software Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.m2m.internal.qvt.oml.ocl.transformations; |
| |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EParameter; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv; |
| import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; |
| import org.eclipse.m2m.internal.qvt.oml.ast.parser.ValidationMessages; |
| import org.eclipse.m2m.internal.qvt.oml.ocl.transformations.LibraryCreationException; |
| import org.eclipse.m2m.internal.qvt.oml.ocl.transformations.LibraryOperation; |
| import org.eclipse.ocl.OCLInput; |
| import org.eclipse.ocl.ParserException; |
| import org.eclipse.ocl.ecore.CallOperationAction; |
| import org.eclipse.ocl.ecore.Constraint; |
| import org.eclipse.ocl.ecore.OCL; |
| import org.eclipse.ocl.ecore.SendSignalAction; |
| import org.eclipse.ocl.expressions.Variable; |
| import org.eclipse.ocl.helper.ConstraintKind; |
| import org.eclipse.ocl.types.AnyType; |
| import org.eclipse.ocl.utilities.ExpressionInOCL; |
| import org.eclipse.ocl.utilities.UMLReflection; |
| |
| /** |
| * @author sboyko |
| * |
| */ |
| class QvtLibraryOperation { |
| |
| QvtLibraryOperation(QvtOperationalModuleEnv parseEnv, LibraryOperation libOp) throws LibraryCreationException { |
| String fakeOperation = getFakeOperation(libOp); |
| ExpressionInOCL<EClassifier, EParameter> exprInOcl = parseConstraintUnvalidated(fakeOperation, parseEnv, libOp); |
| |
| myParamTypes = new ArrayList<EClassifier>(exprInOcl.getParameterVariable().size()); |
| for (Variable<EClassifier, EParameter> param : exprInOcl.getParameterVariable()) { |
| if(param.getType() == null) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| fakeOperation)); |
| } |
| |
| myParamTypes.add(param.getType()); |
| } |
| |
| if (exprInOcl.getContextVariable() == null) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| fakeOperation)); |
| } |
| myContextType = exprInOcl.getContextVariable().getType() == parseEnv.getOCLStandardLibrary().getOclVoid() ? |
| parseEnv.getModuleContextType() : exprInOcl.getContextVariable().getType(); |
| |
| if (exprInOcl.getBodyExpression() == null) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| fakeOperation)); |
| } |
| myReturnType = exprInOcl.getBodyExpression().getType(); |
| } |
| |
| public EClassifier getContextType() { |
| return myContextType; |
| } |
| |
| public EClassifier getReturnType() { |
| return myReturnType; |
| } |
| |
| public EClassifier[] getParamTypes() { |
| return (EClassifier[]) myParamTypes.toArray(new EClassifier[myParamTypes.size()]); |
| } |
| |
| /** |
| * Parses the specified <code>text</code> as an OCL constraint, without |
| * validating it. |
| * |
| * @param text the OCL text |
| * @return the OCL constraint expression, unvalidated |
| */ |
| protected ExpressionInOCL<EClassifier, EParameter> parseConstraintUnvalidated(String text, |
| QvtOperationalEnv env, LibraryOperation libOp) throws LibraryCreationException { |
| OCL ocl = OCL.newInstance(env); |
| Constraint constraint = null; |
| |
| try { |
| if(isOclVoidTypeName(libOp.getContext(), env)) { |
| // Note: a workaround for OclVoid context which is not used for module owned |
| // operations -> trim the def: constraint specification and use library module |
| // type explicitly |
| int startPos = text.indexOf(" " + OCL_DEF) + OCL_DEF.length() + 1; //$NON-NLS-1$ |
| String trimmedText = startPos < text.length() ? text.substring(startPos) : text; |
| |
| OCL.Helper helper = ocl.createOCLHelper(); |
| helper.setContext(env.getModuleContextType()); |
| constraint = helper.createConstraint(ConstraintKind.DEFINITION, trimmedText); |
| } else { |
| List<Constraint> constraints = ocl.parse(new OCLInput(text)); |
| if(!constraints.isEmpty()) { |
| constraint = constraints.get(0); |
| } |
| } |
| } catch (ParserException e) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_ParametersOsReturnTypeNotFound, |
| text, e.getLocalizedMessage())); |
| } catch (IllegalArgumentException e) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_ParametersOsReturnTypeNotFound, |
| text, e.getLocalizedMessage())); |
| } |
| |
| if(constraint == null) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| text)); |
| } |
| |
| ExpressionInOCL<EClassifier, EParameter> result = constraint.getSpecification(); |
| if (result == null) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| text)); |
| } |
| |
| try { |
| if (result.toString() == null) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| text)); |
| } |
| } catch (RuntimeException e) { |
| throw new LibraryCreationException(MessageFormat.format( |
| ValidationMessages.LibOperationAnalyser_OperationParsingError, |
| text)); |
| } |
| |
| return result; |
| } |
| |
| private static boolean isOclVoidTypeName(String typeName, QvtOperationalEnv env) { |
| UMLReflection<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> umlReflection = env |
| .getUMLReflection(); |
| EClassifier oclVoid = env.getOCLStandardLibrary().getOclVoid(); |
| String simpleName = umlReflection.getName(oclVoid); |
| String qName = umlReflection.getQualifiedName(oclVoid); |
| return typeName.equals(simpleName) || typeName.equals(qName); |
| } |
| |
| private String getFakeOperation(LibraryOperation libOp) { |
| StringBuffer result = new StringBuffer(); |
| |
| result.append(OCL_CONTEXT); |
| result.append(Common_SPACE); |
| |
| result.append(libOp.getContext()); |
| result.append(Common_SPACE); |
| |
| result.append(OCL_DEF); |
| result.append(Common_SPACE); |
| |
| result.append(libOp.getName()); |
| result.append(Common_BRACKET_OPEN); |
| int counter = 0; |
| for (String nextType : libOp.getParameterTypes()) { |
| String nextParameterType = getFakeTypeText(nextType); |
| if (counter > 0) { |
| result.append(Common_COMMA); |
| } |
| result.append(PARAMETER_PREFIX); |
| result.append(counter); |
| result.append(Common_COLON); |
| result.append(nextParameterType); |
| counter++; |
| } |
| result.append(Common_BRACKET_CLOSE); |
| result.append(Common_COLON); |
| result.append(getFakeTypeText(libOp.getReturnType())); |
| |
| result.append(Common_EQ).append("let r:"); //$NON-NLS-1$ |
| result.append(getFakeTypeText(libOp.getReturnType())); |
| result.append(Common_EQ); |
| result.append("null in r"); //$NON-NLS-1$ |
| |
| return result.toString(); |
| } |
| |
| private String getFakeTypeText(String type) { |
| return type != null ? type : AnyType.SINGLETON_NAME; |
| } |
| |
| private static final String OCL_CONTEXT = "context"; //$NON-NLS-1$ |
| private static final String OCL_DEF = "def:"; //$NON-NLS-1$ |
| private static final String Common_SPACE = " "; //$NON-NLS-1$ |
| private static final String Common_BRACKET_OPEN = "("; //$NON-NLS-1$ |
| private static final String Common_BRACKET_CLOSE = ")"; //$NON-NLS-1$ |
| private static final String Common_COMMA = ","; //$NON-NLS-1$ |
| private static final String Common_COLON = ":"; //$NON-NLS-1$ |
| private static final String Common_EQ = "="; //$NON-NLS-1$ |
| private static final String PARAMETER_PREFIX = "param_"; //$NON-NLS-1$ |
| |
| private final EClassifier myContextType; |
| private final EClassifier myReturnType; |
| private final List<EClassifier> myParamTypes; |
| |
| } |