diff options
author | sboyko | 2014-01-29 07:34:32 +0000 |
---|---|---|
committer | sboyko | 2014-01-29 07:34:32 +0000 |
commit | d21c22ea2ac43cdde470c99089948b12b15b4e03 (patch) | |
tree | 4cdad10a48a363843974d0f6a8f89609f6ee2c82 /plugins/org.eclipse.m2m.qvt.oml/src | |
parent | e92ca950ea3f97103251c7c9b6f18faffa34129a (diff) | |
download | org.eclipse.qvto-d21c22ea2ac43cdde470c99089948b12b15b4e03.tar.gz org.eclipse.qvto-d21c22ea2ac43cdde470c99089948b12b15b4e03.tar.xz org.eclipse.qvto-d21c22ea2ac43cdde470c99089948b12b15b4e03.zip |
[289982] - Support concrete syntax definition of blackbox libraries
Diffstat (limited to 'plugins/org.eclipse.m2m.qvt.oml/src')
25 files changed, 652 insertions, 155 deletions
diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/QvtEnvironmentBase.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/QvtEnvironmentBase.java index 4e040f9f6..7edac866b 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/QvtEnvironmentBase.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/QvtEnvironmentBase.java @@ -17,14 +17,17 @@ import static org.eclipse.ocl.utilities.UMLReflection.SAME_TYPE; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import lpg.runtime.ParseErrorCodes; import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.UniqueEList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; @@ -113,7 +116,8 @@ public abstract class QvtEnvironmentBase extends EcoreEnvironment implements QVT private QVTUMLReflection fQVUMLReflection; private List<QvtEnvironmentBase> fByAccess; private List<QvtEnvironmentBase> fByExtension; - private List<QvtEnvironmentBase> fAllExtendedModuleEnvs; + private List<QvtEnvironmentBase> fAllExtendedModuleEnvs; + private Map<URI, Set<String>> fImportedNativeLibs; private Set<EOperation> fOperationsHolder; protected QvtEnvironmentBase(QvtEnvironmentBase parent) { @@ -414,7 +418,7 @@ public abstract class QvtEnvironmentBase extends EcoreEnvironment implements QVT } if(importedEnv == null || importedEnv == this || isOneOfParents(importedEnv)) { - throw new IllegalArgumentException("Illegal import environemnt"); //$NON-NLS-1$ + throw new IllegalArgumentException("Illegal import environment: " + String.valueOf(importedEnv)); //$NON-NLS-1$ } List<QvtEnvironmentBase> container; @@ -430,6 +434,7 @@ public abstract class QvtEnvironmentBase extends EcoreEnvironment implements QVT container = fByExtension; fAllExtendedModuleEnvs = null; } + fImportedNativeLibs = null; assert container != null; container.add(importedEnv); @@ -475,6 +480,38 @@ public abstract class QvtEnvironmentBase extends EcoreEnvironment implements QVT return fByExtension != null ? fByExtension : Collections.<QvtEnvironmentBase>emptyList(); } + + public Map<URI, Set<String>> getImportedNativeLibs() { + QvtEnvironmentBase rootEnv = getRootEnv(); + if(rootEnv != this) { + return rootEnv.getImportedNativeLibs(); + } + + if(fImportedNativeLibs == null) { + Collection<QvtEnvironmentBase> imports = new LinkedHashSet<QvtEnvironmentBase>(); + imports.addAll(getImportsByExtends()); + imports.addAll(getImportsByAccess()); + + Map<URI, Set<String>> result = new LinkedHashMap<URI, Set<String>>(imports.size()); + for (QvtEnvironmentBase sibling : imports) { + Module module = sibling.getModuleContextType(); + if (module == null || module.eResource() == null) { + continue; + } + URI uri = module.eResource().getURI(); + Set<String> names = result.get(uri); + if (names == null) { + names = new LinkedHashSet<String>(); + result.put(uri, names); + } + names.add(module.getName()); + } + + fImportedNativeLibs = Collections.unmodifiableMap(result); + } + + return fImportedNativeLibs; + } protected final CollisionStatus findCollidingOperation(EClassifier ownerType, ImperativeOperation operation) { try { diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/TypeCheckerImpl.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/TypeCheckerImpl.java index a88bce809..d97132ebc 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/TypeCheckerImpl.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/env/TypeCheckerImpl.java @@ -206,6 +206,9 @@ class TypeCheckerImpl extends AbstractTypeChecker<EClassifier, EOperation, EStru if(type1 == type2) { return UMLReflection.SAME_TYPE; } + if (type1 == null) { + return UMLReflection.UNRELATED_TYPE; + } boolean isList1 = type1 instanceof ListType; boolean isList2 = type2 instanceof ListType; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalParserUtil.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalParserUtil.java index 25491c796..d25cec02e 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalParserUtil.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalParserUtil.java @@ -8,6 +8,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.ast.parser; @@ -41,11 +42,16 @@ import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtEnvironmentBase; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalStdLibrary; import org.eclipse.m2m.internal.qvt.oml.compiler.CompiledUnit; +import org.eclipse.m2m.internal.qvt.oml.cst.ConstructorCS; import org.eclipse.m2m.internal.qvt.oml.cst.ImportCS; import org.eclipse.m2m.internal.qvt.oml.cst.LibraryCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingDeclarationCS; +import org.eclipse.m2m.internal.qvt.oml.cst.MappingExtensionCS; +import org.eclipse.m2m.internal.qvt.oml.cst.MappingExtensionKindCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingMethodCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingModuleCS; +import org.eclipse.m2m.internal.qvt.oml.cst.MappingQueryCS; +import org.eclipse.m2m.internal.qvt.oml.cst.MappingRuleCS; import org.eclipse.m2m.internal.qvt.oml.cst.ModelTypeCS; import org.eclipse.m2m.internal.qvt.oml.cst.ModulePropertyCS; import org.eclipse.m2m.internal.qvt.oml.cst.ScopedNameCS; @@ -56,7 +62,6 @@ import org.eclipse.m2m.internal.qvt.oml.expressions.ContextualProperty; import org.eclipse.m2m.internal.qvt.oml.expressions.DirectionKind; import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.ImportKind; -import org.eclipse.m2m.internal.qvt.oml.expressions.MappingOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.Module; import org.eclipse.m2m.internal.qvt.oml.expressions.ModuleImport; import org.eclipse.m2m.internal.qvt.oml.expressions.VarParameter; @@ -71,6 +76,7 @@ import org.eclipse.ocl.cst.SimpleNameCS; import org.eclipse.ocl.cst.TupleTypeCS; import org.eclipse.ocl.cst.TypeCS; import org.eclipse.ocl.cst.VariableCS; +import org.eclipse.ocl.cst.impl.CSTNodeImpl; import org.eclipse.ocl.ecore.CallOperationAction; import org.eclipse.ocl.ecore.CollectionType; import org.eclipse.ocl.ecore.Constraint; @@ -93,7 +99,7 @@ public class QvtOperationalParserUtil { private static final String NAMESPACE_SEPARATOR = "."; //$NON-NLS-1$ public static final String QVT_NAMESPACE_URI = "http://www.eclipse.org/m2m/1.0.0/QVT"; //$NON-NLS-1$ - private static final String QVT_IS_ABSTACT = "abstract"; //$NON-NLS-1$ + private static final String QVT_IS_ABSTRACT = "abstract"; //$NON-NLS-1$ private static final String QVT_IS_STATIC = "static"; //$NON-NLS-1$ private static final String QVT_INIT_EXPRESSION_URI = QVT_NAMESPACE_URI + "/initExp"; //$NON-NLS-1$ @@ -547,18 +553,18 @@ public class QvtOperationalParserUtil { return context instanceof EClass; } - public static String safeGetMappingQualifiedName(QvtOperationalEnv env, MappingOperation mappingOperation) { - if(mappingOperation != null) { + public static String safeGetMappingQualifiedName(QvtOperationalEnv env, ImperativeOperation operation) { + if(operation != null) { StringBuilder buf = new StringBuilder(); - EClassifier ctxType = getContextualType(mappingOperation); + EClassifier ctxType = getContextualType(operation); if(ctxType != null) { buf.append(safeGetQualifiedName(env, ctxType)); buf.append(EmfUtil.PATH_SEPARATOR); } - if(mappingOperation.getName() != null) { - buf.append(mappingOperation.getName()); + if(operation.getName() != null) { + buf.append(operation.getName()); } return buf.toString(); @@ -663,17 +669,17 @@ public class QvtOperationalParserUtil { return null; } - public static void markAsAbstractMappingOperation(MappingOperation mappingOperation) { + static void markAsAbstractOperation(ImperativeOperation operation) { EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(QVT_NAMESPACE_URI); - annotation.getDetails().put(QVT_IS_ABSTACT, Boolean.toString(true)); - mappingOperation.getEAnnotations().add(annotation); + annotation.getDetails().put(QVT_IS_ABSTRACT, Boolean.toString(true)); + operation.getEAnnotations().add(annotation); } - public static boolean isAbstractMappingOperation(MappingOperation mappingOperation) { - EAnnotation annotation = mappingOperation.getEAnnotation(QVT_NAMESPACE_URI); + static boolean isAbstractOperation(ImperativeOperation operation) { + EAnnotation annotation = operation.getEAnnotation(QVT_NAMESPACE_URI); if(annotation != null) { - String value = annotation.getDetails().get(QVT_IS_ABSTACT); + String value = annotation.getDetails().get(QVT_IS_ABSTRACT); return Boolean.valueOf(value); } return false; @@ -706,16 +712,62 @@ public class QvtOperationalParserUtil { return cstNode; } - public static CSTNode getImperativeOperationProblemNode(MappingMethodCS methodCS) { + public static CSTNode getMethodNameProblemNodeCS(MappingMethodCS methodCS) { MappingDeclarationCS mappingDeclCS = methodCS.getMappingDeclarationCS(); if(mappingDeclCS != null) { + final int pos[] = {mappingDeclCS.getStartOffset(), mappingDeclCS.getEndOffset()}; + + if(mappingDeclCS.getContextType() != null) { + pos[0] = mappingDeclCS.getContextType().getStartOffset(); + pos[1] = mappingDeclCS.getContextType().getEndOffset(); + } + if(mappingDeclCS.getSimpleNameCS() != null) { - return mappingDeclCS.getSimpleNameCS(); + pos[1] = mappingDeclCS.getSimpleNameCS().getEndOffset(); } + return new CSTNodeImpl() { + @Override + public int getStartOffset() { + return pos[0]; + } + @Override + public int getEndOffset() { + return pos[1]; + } + }; + } + return methodCS; + } + + public static CSTNode getMethodHeaderProblemNodeCS(MappingMethodCS methodCS) { + MappingDeclarationCS mappingDeclCS = methodCS.getMappingDeclarationCS(); + if(mappingDeclCS != null) { + final int pos[] = {mappingDeclCS.getStartOffset(), mappingDeclCS.getEndOffset()}; + if(mappingDeclCS.getContextType() != null) { - return mappingDeclCS.getContextType(); + pos[1] = mappingDeclCS.getContextType().getEndOffset(); } + if(mappingDeclCS.getSimpleNameCS() != null) { + pos[1] = mappingDeclCS.getSimpleNameCS().getEndOffset(); + } + if(!mappingDeclCS.getParameters().isEmpty()) { + pos[1] = mappingDeclCS.getParameters().get(mappingDeclCS.getParameters().size()-1).getEndOffset(); + } + if(!mappingDeclCS.getResult().isEmpty()) { + pos[1] = mappingDeclCS.getResult().get(mappingDeclCS.getResult().size()-1).getEndOffset(); + } + + return new CSTNodeImpl() { + @Override + public int getStartOffset() { + return pos[0]; + } + @Override + public int getEndOffset() { + return pos[1]; + } + }; } return methodCS; } @@ -818,5 +870,23 @@ public class QvtOperationalParserUtil { } return result; } + + public static boolean hasOperationBody(MappingMethodCS methodCS) { + return + (methodCS instanceof MappingRuleCS && ((MappingRuleCS) methodCS).getMappingBody() != null) || + (methodCS instanceof ConstructorCS && !((ConstructorCS) methodCS).getExpressions().isEmpty()) || + (methodCS instanceof MappingQueryCS && !((MappingQueryCS) methodCS).getExpressions().isEmpty()) || + (methodCS instanceof ConstructorCS && !((ConstructorCS) methodCS).getExpressions().isEmpty()); + } + + public static boolean isDisjunctiveMappingOperation(MappingMethodCS methodCS) { + for (MappingExtensionCS extensionCS : methodCS.getMappingDeclarationCS().getMappingExtension()) { + if(extensionCS.getKind() == MappingExtensionKindCS.DISJUNCTS) { + return true; + } + } + + return false; + } }
\ No newline at end of file diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalUtil.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalUtil.java index f2f8eb684..6e67538a9 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalUtil.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Borland Software Corporation and others. + * Copyright (c) 2007, 2013 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 v1.0 @@ -147,7 +147,7 @@ public class QvtOperationalUtil { return false; } - public static boolean hasAbstractOutputParamerter(ImperativeOperation operation) { + public static boolean hasAbstractOutputParameter(ImperativeOperation operation) { for (VarParameter nextParam : operation.getResult()) { if(nextParam.getEType() != null && isAbstract(nextParam.getEType())) { return true; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalValidationVisitor.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalValidationVisitor.java index 0b8103f95..818424f7d 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalValidationVisitor.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalValidationVisitor.java @@ -431,8 +431,8 @@ public class QvtOperationalValidationVisitor extends QvtOperationalAstWalker { if(mappingCallExp.getReferredOperation() instanceof MappingOperation) { MappingOperation mappingOperation = (MappingOperation) mappingCallExp.getReferredOperation(); - if(QvtOperationalUtil.hasAbstractOutputParamerter(mappingOperation) && - QvtOperationalParserUtil.isAbstractMappingOperation(mappingOperation) && + if(QvtOperationalUtil.hasAbstractOutputParameter(mappingOperation) && + QvtOperationalParserUtil.isAbstractOperation(mappingOperation) && mappingOperation.getDisjunct().isEmpty()) { String errMessage = NLS.bind(ValidationMessages.directCallToAbstractMappingDisallowed, QvtOperationalParserUtil.safeGetMappingQualifiedName(fEnv, mappingOperation)); diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalVisitorCS.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalVisitorCS.java index 606da4440..ba559c1ef 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalVisitorCS.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/QvtOperationalVisitorCS.java @@ -7,7 +7,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation - * Christopher Gerking - bugs 302594, 310991 + * Christopher Gerking - bugs 302594, 310991, 289982 * Alex Paperno - bugs 272869, 268636, 404647, 414363, 414363, 401521, * 419299, 414619, 403440, 415024, 420970, 413391 *******************************************************************************/ @@ -57,6 +57,7 @@ import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalFileEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalStdLibrary; +import org.eclipse.m2m.internal.qvt.oml.blackbox.BlackboxRegistry; import org.eclipse.m2m.internal.qvt.oml.compiler.CompilerMessages; import org.eclipse.m2m.internal.qvt.oml.compiler.QvtCompilerOptions; import org.eclipse.m2m.internal.qvt.oml.compiler.UnitProxy; @@ -2209,29 +2210,56 @@ public class QvtOperationalVisitorCS } // process operation qualifiers - EList<QualifierKindCS> qualifiersCS = (methodCS.getMappingDeclarationCS() == null) ? null + List<QualifierKindCS> qualifiersCS = (methodCS.getMappingDeclarationCS() == null) ? Collections.<QualifierKindCS>emptyList() : methodCS.getMappingDeclarationCS().getQualifiers(); - if(imperativeOp instanceof MappingOperation) { - if (qualifiersCS != null) { - for (QualifierKindCS nextQualifierCS : qualifiersCS) { - if(nextQualifierCS != QualifierKindCS.ABSTRACT) { - // only 'abstract' qualifier for mapping is currently supported - String errMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_unsupportedQualifierOnOperation, - nextQualifierCS.getName(), QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); - env.reportError(errMessage, QvtOperationalParserUtil.getImperativeOperationProblemNode(methodCS)); - } else { - QvtOperationalParserUtil.markAsAbstractMappingOperation((MappingOperation) imperativeOp); - } - } - } - } + for (QualifierKindCS nextQualifierCS : qualifiersCS) { + switch (nextQualifierCS) { + case ABSTRACT: + if(imperativeOp instanceof MappingOperation) { + QvtOperationalParserUtil.markAsAbstractOperation(imperativeOp); + } + if(imperativeOp instanceof Constructor) { + // only 'blackbox' qualifier for constructor is currently supported + String errMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_unsupportedQualifierOnConstructor, nextQualifierCS.getName(), + QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportWarning(errMessage, QvtOperationalParserUtil.getMethodNameProblemNodeCS(methodCS)); + } + break; + case BLACKBOX: + if (QvtOperationalParserUtil.hasOperationBody(methodCS)) { + if(imperativeOp instanceof Constructor) { + String errMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_blackboxConstructorWithBodyNotAllowed, + QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportError(errMessage, QvtOperationalParserUtil.getMethodHeaderProblemNodeCS(methodCS)); + } + else { + String errMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_blackboxOperationWithBodyNotAllowed, + QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportError(errMessage, QvtOperationalParserUtil.getMethodHeaderProblemNodeCS(methodCS)); + } + } + if (QvtOperationalParserUtil.isDisjunctiveMappingOperation(methodCS)) { + String errMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_unsupportedBlackboxQualifierOnDisjunctiveMapping, + QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportError(errMessage, QvtOperationalParserUtil.getMethodNameProblemNodeCS(methodCS)); + } + imperativeOp.setIsBlackbox(true); + break; + case STATIC: + String msg = (imperativeOp instanceof Constructor) ? ValidationMessages.QvtOperationalVisitorCS_unsupportedQualifierOnConstructor + : ValidationMessages.QvtOperationalVisitorCS_unsupportedQualifierOnOperation; + String errMessage = NLS.bind(msg, nextQualifierCS.getName(), QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportWarning(errMessage, QvtOperationalParserUtil.getMethodNameProblemNodeCS(methodCS)); + break; + } + } Collection<QualifierKindCS> qualifierDups = QvtOperationalParserUtil.selectDuplicateQualifiers(qualifiersCS); for(QualifierKindCS duplicate : qualifierDups) { String errMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_duplicateQualifierOnOperation, duplicate.getName(), QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); - env.reportError(errMessage, QvtOperationalParserUtil.getImperativeOperationProblemNode(methodCS)); + env.reportError(errMessage, QvtOperationalParserUtil.getMethodNameProblemNodeCS(methodCS)); } if(myCompilerOptions.isGenerateCompletionData()) { @@ -3535,6 +3563,20 @@ public class QvtOperationalVisitorCS else { visitMappingQueryCS((MappingQueryCS) methodCS, env, methodEnv, declaredOperation); } + + if(declaredOperation.isIsBlackbox() && !QvtOperationalParserUtil.isDisjunctiveMappingOperation(methodCS)) { + Collection<CallHandler> handlers = BlackboxRegistry.INSTANCE.getBlackboxCallHandler(declaredOperation, env.getAdapter(QvtOperationalModuleEnv.class)); + if (handlers.isEmpty()) { + String warning = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_noBlackboxImplementationFound, + QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportWarning(warning, QvtOperationalParserUtil.getMethodHeaderProblemNodeCS(methodCS)); + } + if (handlers.size() > 1) { + String warning = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_ambiguousBlackboxImplementationFound, + QvtOperationalParserUtil.getMappingStringRepresentation(methodCS)); + env.reportWarning(warning, QvtOperationalParserUtil.getMethodHeaderProblemNodeCS(methodCS)); + } + } } private void visitConstructorCS(ConstructorCS methodCS, QvtOperationalEnv env, QvtOperationalEnv newEnv, ImperativeOperation constructor) throws SemanticException { @@ -3658,13 +3700,13 @@ public class QvtOperationalVisitorCS body.getEndSection().addAll(ends); } - checkAbstractOutParamsInitialized(operation.getResult(), methodCS, env); + checkAbstractOutParamsInitialized(operation, methodCS, env); processMappingExtensions(methodCS, operation, env); - + // adjust implicit variables for serialization consolidateImplicitVariables(newEnv); - // + return operation; } @@ -3813,12 +3855,27 @@ public class QvtOperationalVisitorCS boolean isAdded = false; MappingOperation extendedMapping = mappings.get(0); if(kind == MappingExtensionKindCS.INHERITS) { + if (operation.isIsBlackbox()) { + env.reportError(NLS.bind(ValidationMessages.QvtOperationalVisitorCS_unsupportedInheritanceOnBlackboxMapping, + QvtOperationalParserUtil.getStringRepresentation(identifierCS), QvtOperationalParserUtil.getMappingStringRepresentation(mappingCS)), + identifierCS); + } + if (extendedMapping.isIsBlackbox()) { + env.reportError(NLS.bind(ValidationMessages.QvtOperationalVisitorCS_unsupportedInheritedBlackboxMapping, + QvtOperationalParserUtil.getStringRepresentation(identifierCS), QvtOperationalParserUtil.getMappingStringRepresentation(mappingCS)), + identifierCS); + } isAdded = operation.getInherited().add(extendedMapping); MappingExtensionHelper.bind2SourceElement(operation, identifierCS, kind); } else if(kind == MappingExtensionKindCS.MERGES) { + if (extendedMapping.isIsBlackbox()) { + env.reportError(NLS.bind(ValidationMessages.QvtOperationalVisitorCS_unsupportedMergedBlackboxMapping, + QvtOperationalParserUtil.getStringRepresentation(identifierCS), QvtOperationalParserUtil.getMappingStringRepresentation(mappingCS)), + identifierCS); + } isAdded = operation.getMerged().add(extendedMapping); - MappingExtensionHelper.bind2SourceElement(operation, identifierCS, kind); + MappingExtensionHelper.bind2SourceElement(operation, identifierCS, kind); } else if(kind == MappingExtensionKindCS.DISJUNCTS) { isAdded = operation.getDisjunct().add(extendedMapping); @@ -3846,7 +3903,7 @@ public class QvtOperationalVisitorCS if (mappingDeclarationCS == null) { return false; } - mappingDeclarationCS.setAst(operation); + mappingDeclarationCS.setAst(operation); operation.setIsBlackbox(mappingMethodCS.isBlackBox()); operation.setStartPosition(mappingDeclarationCS.getStartOffset()); operation.setEndPosition(mappingDeclarationCS.getEndOffset()); @@ -4385,7 +4442,7 @@ public class QvtOperationalVisitorCS if(referredType != null && (TypeUtil.getRelationship(env, actualType, referredType) & UMLReflection.SAME_TYPE) == 0) { String actualTypeName = QvtOperationalParserUtil.safeGetQualifiedName(env, actualType); String referredTypeName = QvtOperationalParserUtil.safeGetQualifiedName(env, referredType); - String errorMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_instatiatedTypeDoesNotConformToReferredType, + String errorMessage = NLS.bind(ValidationMessages.QvtOperationalVisitorCS_instantiatedTypeDoesNotConformToReferredType, actualTypeName, referredTypeName); env.reportError(errorMessage, getStartOffset(objectExp, problemCS), getEndOffset(objectExp, problemCS)); @@ -5125,8 +5182,8 @@ public class QvtOperationalVisitorCS } } - private void checkAbstractOutParamsInitialized(EList<VarParameter> result, MappingRuleCS methodCS, QvtOperationalEnv env) { - for (VarParameter varParameter : result) { + private void checkAbstractOutParamsInitialized(MappingOperation operation, MappingRuleCS methodCS, QvtOperationalEnv env) { + for (VarParameter varParameter : operation.getResult()) { EClassifier type = varParameter.getEType(); if (type instanceof EClass) { EClass eClass = (EClass) type; @@ -5136,16 +5193,11 @@ public class QvtOperationalVisitorCS // TODO: The check could be more accurate return; } - if((methodCS.getMappingDeclarationCS() != null) && !(methodCS.getMappingDeclarationCS().getQualifiers().contains(QualifierKindCS.ABSTRACT))) { - boolean hasDisjunct = false; - for (MappingExtensionCS extensionCS : methodCS.getMappingDeclarationCS().getMappingExtension()) { - if(extensionCS.getKind() == MappingExtensionKindCS.DISJUNCTS) { - hasDisjunct = true; - break; - } - } + boolean isAbstract = (methodCS.getMappingDeclarationCS() != null && methodCS.getMappingDeclarationCS().getQualifiers().contains(QualifierKindCS.ABSTRACT)); + if(!operation.isIsBlackbox() && !isAbstract) { + boolean hasDisjunct = QvtOperationalParserUtil.isDisjunctiveMappingOperation(methodCS); if(!hasDisjunct) { - env.reportError(ValidationMessages.QvtOperationalVisitorCS_AbstractTypesNotInitialized, methodCS); + env.reportError(ValidationMessages.QvtOperationalVisitorCS_AbstractTypesNotInitialized, QvtOperationalParserUtil.getMethodHeaderProblemNodeCS(methodCS)); } } } diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.java index aaaafdb97..4aaba6899 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.java @@ -9,6 +9,7 @@ * Contributors: * Borland Software Corporation - initial API and implementation * Alex Paperno - bugs 272869, 268636, 414363, 419299, 414619, 420970, 413391 + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.ast.parser; @@ -61,7 +62,12 @@ public final class ValidationMessages extends NLS { public static String QvtOperationalVisitorCS_ContextualPropertyTypeIsMissed; public static String QvtOperationalVisitorCS_duplicateMappingRereferenceInExtensionKind; public static String QvtOperationalVisitorCS_duplicateQualifierOnOperation; - public static String QvtOperationalVisitorCS_instatiatedTypeDoesNotConformToReferredType; + public static String QvtOperationalVisitorCS_unsupportedInheritedBlackboxMapping; + public static String QvtOperationalVisitorCS_unsupportedMergedBlackboxMapping; + public static String QvtOperationalVisitorCS_unsupportedInheritanceOnBlackboxMapping; + public static String QvtOperationalVisitorCS_noBlackboxImplementationFound; + public static String QvtOperationalVisitorCS_ambiguousBlackboxImplementationFound; + public static String QvtOperationalVisitorCS_instantiatedTypeDoesNotConformToReferredType; public static String QvtOperationalVisitorCS_ResolveInMappingNotFound; public static String QvtOperationalVisitorCS_transformationNameDuplicates; public static String QvtOperationalVisitorCS_unresolvedMappingOperationReference; @@ -99,6 +105,10 @@ public final class ValidationMessages extends NLS { public static String QvtOperationalVisitorCS_resultParamNameNotAllowed; public static String QvtOperationalVisitorCS_SeeErrorLogForDetails; public static String QvtOperationalVisitorCS_unsupportedQualifierOnOperation; + public static String QvtOperationalVisitorCS_blackboxOperationWithBodyNotAllowed; + public static String QvtOperationalVisitorCS_unsupportedQualifierOnConstructor; + public static String QvtOperationalVisitorCS_blackboxConstructorWithBodyNotAllowed; + public static String QvtOperationalVisitorCS_unsupportedBlackboxQualifierOnDisjunctiveMapping; public static String QvtOperationalVisitorCS_WrongImperativeIteratorConditionType; public static String QvtOperationalVisitorCS_incrementalAssignmentResultNotAllowed; public static String QvtOperationalVisitorCS_assignmentResultNotAllowed; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.properties b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.properties index 7dbe08473..23c4d644a 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.properties +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/ast/parser/ValidationMessages.properties @@ -10,6 +10,7 @@ # Borland Software Corporation - initial API and implementation # Alex Paperno - bugs 272869, 268636, 414363, 419299, 419299, 414619, # 420970, 413391, 414347 +# Christopher Gerking - bug 289982 ############################################################################### AmbiguousModuleReference=Ambiguous module reference ''{0}'' AmbiguousOperationLookup=Ambiguous operation lookup @@ -99,9 +100,18 @@ QvtOperationalVisitorCS_transformationNameDuplicates=Transformation with name '' QvtOperationalVisitorCS_booleanTypeExpressionExpected=''Boolean'' type expression expected, expression of ''{0}'' type found. QvtOperationalVisitorCS_canNotInstantiateAbstractType=Can''t instantiate abstract type ''{0}'' QvtOperationalVisitorCS_duplicateQualifierOnOperation=Duplicate qualifier ''{0}'' on operation ''{1}'' +QvtOperationalVisitorCS_unsupportedInheritedBlackboxMapping=Unsupported inherited blackbox mapping ''{0}'' on mapping ''{1}'' +QvtOperationalVisitorCS_unsupportedMergedBlackboxMapping=Unsupported merged blackbox mapping ''{0}'' on mapping ''{1}'' +QvtOperationalVisitorCS_unsupportedInheritanceOnBlackboxMapping=Unsupported inherited mapping ''{0}'' on blackbox mapping ''{1}'' +QvtOperationalVisitorCS_noBlackboxImplementationFound=No blackbox implementation found for operation ''{0}''. Make sure that an implementation is available when running the transformation. +QvtOperationalVisitorCS_ambiguousBlackboxImplementationFound=Ambiguous blackbox implementation found for operation ''{0}''. More than one Java method match the operation's signature. QvtOperationalVisitorCS_AbstractTypesNotInitialized=Result and out parameters of abstract types must be instantiated or assigned in the init-section QvtOperationalVisitorCS_unsupportedMetamodelComplianceKind=Metamodel compliance kind ''{0}'' not supported. Assumed 'strict' compliance instead QvtOperationalVisitorCS_unsupportedQualifierOnOperation=Unsupported qualifier ''{0}'' on operation ''{1}'' +QvtOperationalVisitorCS_blackboxOperationWithBodyNotAllowed=Blackbox operation ''{0}'' must not specify an operation body +QvtOperationalVisitorCS_unsupportedQualifierOnConstructor=Unsupported qualifier ''{0}'' on constructor ''{1}'' +QvtOperationalVisitorCS_blackboxConstructorWithBodyNotAllowed=Blackbox constructor ''{0}'' must not specify an operation body +QvtOperationalVisitorCS_unsupportedBlackboxQualifierOnDisjunctiveMapping=Disjunctive mapping ''{0}'' must not be declared as blackbox QvtOperationalVisitorCS_unresolvedMappingOperationReference=Unresolved mapping operation reference ''{0}'' QvtOperationalVisitorCS_metamodelPackageRefInconsistent=Cannot locate metamodel name ''{0}'' under specified URI QvtOperationalVisitorCS_metamodelConditionsNotSupported=Metamodel conditions are not supported in current implementation @@ -140,7 +150,7 @@ returnNotAllowedInMappingYet=Using ''return'' from mapping operation is not yet returnUsedOutsideOperationBody=Using ''return'' outside operation body useReturnExpForOperationResult=Use 'return' expression to return result from operation. The last expression or 'null' from empty body is returned implicitly. directCallToAbstractMappingDisallowed=Can not call abstract mapping ''{0}'' with abstract out/result parameter type directly. Use with 'inherits', 'disjuncts', 'merges' in other mappings -QvtOperationalVisitorCS_instatiatedTypeDoesNotConformToReferredType=Instantiated object type ''{0}'' does not conform to referred object type ''{1}'' +QvtOperationalVisitorCS_instantiatedTypeDoesNotConformToReferredType=Instantiated object type ''{0}'' does not conform to referred object type ''{1}'' QvtOperationalVisitorCS_duplicateMappingRereferenceInExtensionKind=Duplicate ''{0}'' reference to mapping operation ''{1}'' QvtOperationalVisitorCS_LibrarySignatureErrorDirectionKindSpecified=Direction kind cannot be specified here. Library signature must be a list of model types\! QvtOperationalVisitorCS_LibrarySignatureErrorDuplicateModelType=Model type {0} is already present in the library signature\! diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractBlackboxProvider.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractBlackboxProvider.java index 102a17d3f..e38dd5123 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractBlackboxProvider.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractBlackboxProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Borland Software Corporation and others. + * Copyright (c) 2007, 2013 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 v1.0 @@ -8,23 +8,30 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox; +import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; +import org.eclipse.m2m.internal.qvt.oml.compiler.BlackboxUnitResolver; import org.eclipse.m2m.internal.qvt.oml.evaluator.ModuleInstance; import org.eclipse.m2m.internal.qvt.oml.evaluator.ModuleInstanceFactory; +import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.Module; import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler; import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandlerAdapter; public abstract class AbstractBlackboxProvider { + + private static final ResolutionContext GLOBAL_RESOLUTION_CONTEXT = new ResolutionContextImpl(BlackboxUnitResolver.GLOBAL_CONTEXT); public interface InstanceAdapterFactory { Object createAdapter(EObject moduleInstance); @@ -34,12 +41,7 @@ public abstract class AbstractBlackboxProvider { super(); } - protected String getProviderID() { - // FIXME - avoid compilation breakage => - // make it abstract ensure all concrete subclasses provide concrete - // operation - return "unknown"; //$NON-NLS-1$ - } + protected abstract String getProviderID(); protected CompilationUnit createCompilationUnit( QvtOperationalModuleEnv moduleEnv) { @@ -85,7 +87,7 @@ public abstract class AbstractBlackboxProvider { CallHandlerAdapter.attach(operation, actualHandler); } - public abstract List<AbstractCompilationUnitDescriptor> getModuleDescriptors( + public abstract Collection<AbstractCompilationUnitDescriptor> getModuleDescriptors( ResolutionContext resolutionContext); public abstract AbstractCompilationUnitDescriptor getModuleDescriptor( @@ -94,4 +96,22 @@ public abstract class AbstractBlackboxProvider { public abstract CompilationUnit loadCompilationUnit( AbstractCompilationUnitDescriptor descriptor, LoadContext loadContext) throws BlackboxException; + + public Collection<CallHandler> getBlackboxCallHandler(ImperativeOperation operation, QvtOperationalModuleEnv env) { + Collection<CallHandler> result = Collections.emptyList(); + for (AbstractCompilationUnitDescriptor d : getModuleDescriptors(GLOBAL_RESOLUTION_CONTEXT)) { + if (!env.getImportedNativeLibs().containsKey(d.getURI())) { + continue; + } + Collection<CallHandler> handlers = d.getBlackboxCallHandler(operation, env); + if (!handlers.isEmpty()) { + if (result.isEmpty()) { + result = new LinkedList<CallHandler>(); + } + result.addAll(handlers); + } + } + return result; + } + } diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractCompilationUnitDescriptor.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractCompilationUnitDescriptor.java index 09abf3b58..da518ab3d 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractCompilationUnitDescriptor.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/AbstractCompilationUnitDescriptor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2009 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,10 +8,16 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox; +import java.util.Collection; + import org.eclipse.emf.common.util.URI; +import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; +import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; +import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler; @@ -72,4 +78,7 @@ public abstract class AbstractCompilationUnitDescriptor { public String toString() { return "Descriptor: " + fQualifiedName + " - " + getProvider().toString(); //$NON-NLS-1$ //$NON-NLS-2$ } + + public abstract Collection<CallHandler> getBlackboxCallHandler(ImperativeOperation operation, QvtOperationalModuleEnv env); + }
\ No newline at end of file diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/BlackboxRegistry.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/BlackboxRegistry.java index d78afe658..e7f49aa1a 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/BlackboxRegistry.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/BlackboxRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2009 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,10 +8,12 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -21,6 +23,9 @@ import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.common.EMFPlugin; import org.eclipse.m2m.internal.qvt.oml.QvtPlugin; +import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; +import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; +import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler; /* * TODO - handle collisions of multiple descriptors of the same qualified name @@ -110,4 +115,19 @@ public class BlackboxRegistry { return providers; } } + + public Collection<CallHandler> getBlackboxCallHandler(ImperativeOperation operation, QvtOperationalModuleEnv env) { + Collection<CallHandler> result = Collections.emptyList(); + for (AbstractBlackboxProvider provider : fProviders) { + Collection<CallHandler> handlers = provider.getBlackboxCallHandler(operation, env); + if (!handlers.isEmpty()) { + if (result.isEmpty()) { + result = new LinkedList<CallHandler>(); + } + result.addAll(handlers); + } + } + return result; + } + } diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/OperationMatcher.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/OperationMatcher.java new file mode 100644 index 000000000..7146e63d4 --- /dev/null +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/OperationMatcher.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2008, 2014 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 v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Borland Software Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2m.internal.qvt.oml.blackbox; + +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EOperation; +import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv; +import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil; +import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; +import org.eclipse.m2m.internal.qvt.oml.expressions.Library; +import org.eclipse.ocl.util.TypeUtil; + +public class OperationMatcher { + + private OperationMatcher() { + } + + public static boolean matchOperation(QvtOperationalEnv env, ImperativeOperation imperativeOp, EOperation libraryOp) { + + if (!libraryOp.getName().equals(imperativeOp.getName())) { + return false; + } + + EClassifier contextType = QvtOperationalParserUtil.getContextualType(imperativeOp); + EClassifier owner = env.getUMLReflection().getOwningClassifier(libraryOp); + if (contextType == null) { + if (false == owner instanceof Library) { + return false; + } + } + else { + if (!TypeUtil.exactTypeMatch(env, contextType, owner)) { + return false; + } + } + + if (imperativeOp.getEParameters().size() != libraryOp.getEParameters().size()) { + return false; + } + for (int i = 0, in = imperativeOp.getEParameters().size(); i < in; ++i) { + if (!TypeUtil.exactTypeMatch(env, imperativeOp.getEParameters().get(i).getEType(), libraryOp.getEParameters().get(i).getEType())) { + return false; + } + } + + if (imperativeOp.getResult().size() == 0) { + if (libraryOp.getEType() != env.getOCLStandardLibrary().getOclVoid()) { + return false; + } + } + else { + if (!TypeUtil.exactTypeMatch(env, libraryOp.getEType(), imperativeOp.getResult().get(0).getEType())) { + return false; + } + } + + return true; + } + +} diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/BlackboxResourceFactory.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/BlackboxResourceFactory.java index 1a91b90f0..dd70d8fe9 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/BlackboxResourceFactory.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/BlackboxResourceFactory.java @@ -13,7 +13,6 @@ package org.eclipse.m2m.internal.qvt.oml.blackbox.java; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -26,8 +25,8 @@ import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.m2m.internal.qvt.oml.ast.binding.ASTBindingHelper; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; import org.eclipse.m2m.internal.qvt.oml.compiler.BlackboxUnitResolver; -import org.eclipse.m2m.internal.qvt.oml.compiler.UnitProxy; import org.eclipse.m2m.internal.qvt.oml.compiler.UnitContents.ModelContents; +import org.eclipse.m2m.internal.qvt.oml.compiler.UnitProxy; public class BlackboxResourceFactory implements Resource.Factory { @@ -63,7 +62,7 @@ public class BlackboxResourceFactory implements Resource.Factory { ModelContents contents = (ModelContents) unit.getContents(); List<EObject> topElements = contents.loadElements(rs.getPackageRegistry()); - List<QvtOperationalModuleEnv> modelEnvs = new ArrayList<QvtOperationalModuleEnv>(topElements.size()); +// List<QvtOperationalModuleEnv> modelEnvs = new ArrayList<QvtOperationalModuleEnv>(topElements.size()); for (EObject nextElement : topElements) { QvtOperationalModuleEnv nextEnv = ASTBindingHelper.getEnvironment(nextElement, QvtOperationalModuleEnv.class); @@ -72,10 +71,10 @@ public class BlackboxResourceFactory implements Resource.Factory { // clear the environment problems, for now we do not consider errors // like duplicate operation definitions to cause the importing unit to fail nextEnv.clearProblems(); - modelEnvs.add(nextEnv); +// modelEnvs.add(nextEnv); - Resource resource = nextEnv.getModuleContextType().eResource(); - resource.setURI(unit.getURI()); +// Resource resource = nextEnv.getModuleContextType().eResource(); +// resource.setURI(unit.getURI()); } } diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.java index 172100188..16fb6208b 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox.java; @@ -19,6 +20,7 @@ public class JavaBlackboxMessages extends NLS { public static String FirstContextualOperationParameterRequired; public static String QvtoContextParameterRequired; + public static String ConstructorRequiresContextualOperation; public static String InvalidJavaClassForModule; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.properties b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.properties index 5411b80f5..4ff11cdec 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.properties +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxMessages.properties @@ -7,10 +7,12 @@ # # Contributors: # Borland - initial API and implementation +# Christopher Gerking - bug 289982 ############################################################################### BlackboxUnitLoadFailed=Failed to load java black-box unit ''{0}'' FirstContextualOperationParameterRequired=Contextual operation must declare the first parameter to provide a context. Method=''{0}'' QvtoContextParameterRequired=Operation annotated as <withExecutionContext> must declare the first parameter to provide QVTo execution context. Method=''{0}'' +ConstructorRequiresContextualOperation=Constructor operation must be annotated with <contextual=true>. Method=''{0}'' InvalidJavaClassForModule=Invalid java class ''{0}'' for black-box module ''{1}'' LoadModuleDiagnostics=Loading Java module diagnostics ''{0}'' LoadOperationDiagnostics=Loading Operation diagnostics ''{0}'' diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxProvider.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxProvider.java index 89d438b63..763859a03 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxProvider.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaBlackboxProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2009 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,16 +8,20 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox.java; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; @@ -35,9 +39,13 @@ import org.eclipse.m2m.internal.qvt.oml.blackbox.AbstractCompilationUnitDescript import org.eclipse.m2m.internal.qvt.oml.blackbox.BlackboxException; import org.eclipse.m2m.internal.qvt.oml.blackbox.CompilationUnit; import org.eclipse.m2m.internal.qvt.oml.blackbox.LoadContext; +import org.eclipse.m2m.internal.qvt.oml.blackbox.OperationMatcher; import org.eclipse.m2m.internal.qvt.oml.blackbox.ResolutionContext; import org.eclipse.m2m.internal.qvt.oml.cst.CSTFactory; +import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.Module; +import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler; +import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandlerAdapter; public class JavaBlackboxProvider extends AbstractBlackboxProvider { @@ -58,7 +66,8 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { private static final String METAMODEL_ELEM = "metamodel"; //$NON-NLS-1$ private static final String NSURI_ATTR = "nsURI"; //$NON-NLS-1$ - private final Map<String, Descriptor> fDescriptorMap; + private final Map<String, AbstractCompilationUnitDescriptor> fDescriptorMap; + private final Map<Descriptor, CompilationUnit> fBlackboxUnits = new LinkedHashMap<Descriptor, CompilationUnit>(); public JavaBlackboxProvider() { if(EMFPlugin.IS_ECLIPSE_RUNNING) { @@ -80,11 +89,9 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { } @Override - public List<AbstractCompilationUnitDescriptor> getModuleDescriptors(ResolutionContext resolutionContext) { + public Collection<AbstractCompilationUnitDescriptor> getModuleDescriptors(ResolutionContext resolutionContext) { // TODO - Should we necessarily be available in all contexts ? - ArrayList<AbstractCompilationUnitDescriptor> result = new ArrayList<AbstractCompilationUnitDescriptor>(fDescriptorMap.size()); - result.addAll(fDescriptorMap.values()); - return Collections.unmodifiableList(result); + return fDescriptorMap.values(); } @Override @@ -92,15 +99,20 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { if(descriptor instanceof Descriptor == false) { throw new IllegalArgumentException("Invalid descriptor"); //$NON-NLS-1$ } - Descriptor libDescriptor = (Descriptor) descriptor; + + CompilationUnit compilationUnit = fBlackboxUnits.get(libDescriptor); + if (compilationUnit != null) { + return compilationUnit; + } + JavaModuleLoader javaModuleLoader = createJavaModuleLoader(); BasicDiagnostic errors = null; List<QvtOperationalModuleEnv> loadedModules = new LinkedList<QvtOperationalModuleEnv>(); - for (ModuleHandle nextModuleHandle : libDescriptor.fModules) { - Diagnostic diagnostic = javaModuleLoader.loadModule(nextModuleHandle); + for (Map.Entry<ModuleHandle, Map<String, List<EOperation>>> nextEntry : libDescriptor.fModules.entrySet()) { + Diagnostic diagnostic = javaModuleLoader.loadModule(nextEntry.getKey(), nextEntry.getValue()); if(DiagnosticUtil.isSuccess(diagnostic)) { QvtOperationalModuleEnv nextModuleEnv = javaModuleLoader.getLoadedModule(); @@ -125,9 +137,11 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { throw new BlackboxException(errors); } - return createCompilationUnit(loadedModules); + compilationUnit = createCompilationUnit(loadedModules); + fBlackboxUnits.put(libDescriptor, compilationUnit); + return compilationUnit; } - + private JavaModuleLoader createJavaModuleLoader() { return new JavaModuleLoader() { JavaMethodHandlerFactory handlerFactory; @@ -149,7 +163,7 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { } }; } - + static InstanceAdapterFactory createInstanceAdapterFactory(final Class<?> javaModuleClass) { return new InstanceAdapterFactory() { public Object createAdapter(EObject moduleInstance) { @@ -157,7 +171,7 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { return javaModuleClass.newInstance(); } catch (InstantiationException e) { // FIXME - choose a better exception - throw new IllegalArgumentException("Illegal adapter instance", e); //$NON-NLS-1$ + throw new IllegalArgumentException("Illegal adapter instance", e); //$NON-NLS-1$ } catch (IllegalAccessException e) { // FIXME - choose a better exception throw new IllegalArgumentException("Illegal adapter instance", e); //$NON-NLS-1$ @@ -166,8 +180,8 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { }; } - private Map<String, Descriptor> readDescriptors() { - Map<String, Descriptor> providers = new HashMap<String, Descriptor>(); + private Map<String, AbstractCompilationUnitDescriptor> readDescriptors() { + Map<String, AbstractCompilationUnitDescriptor> providers = new HashMap<String, AbstractCompilationUnitDescriptor>(); IConfigurationElement[] configs = Platform.getExtensionRegistry() .getConfigurationElementsFor(QvtPlugin.ID, EXTENSION_POINT); @@ -232,7 +246,7 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { } private class Descriptor extends AbstractCompilationUnitDescriptor { - private List<ModuleHandle> fModules = Collections.emptyList(); + private Map<ModuleHandle, Map<String, List<EOperation>>> fModules = Collections.emptyMap(); private String fContributingBundleId; Descriptor(IConfigurationElement configurationElement, String unitQualifiedName, String description) { @@ -250,6 +264,33 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { } } } + + public Collection<CallHandler> getBlackboxCallHandler(ImperativeOperation imperativeOp, QvtOperationalModuleEnv env) { + Set<String> importedLibs = env.getImportedNativeLibs().get(getURI()); + Collection<CallHandler> result = Collections.emptyList(); + + for(Map.Entry<ModuleHandle, Map<String, List<EOperation>>> nextEntry : fModules.entrySet()) { + if (!importedLibs.contains(nextEntry.getKey().getModuleName())) { + continue; + } + + List<EOperation> listOp = nextEntry.getValue().get(imperativeOp.getName()); + if (listOp == null) { + continue; + } + + for (EOperation libraryOp : listOp) { + if (OperationMatcher.matchOperation(env, imperativeOp, libraryOp)) { + if (result.isEmpty()) { + result = new LinkedList<CallHandler>(); + } + result.add(CallHandlerAdapter.getDispatcher(libraryOp)); + } + } + } + + return result; + } String getContributorId() { return fContributingBundleId; @@ -257,7 +298,7 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { private void addModuleHandle(IConfigurationElement moduleElement) { if(fModules.isEmpty()) { - fModules = new LinkedList<ModuleHandle>(); + fModules = new LinkedHashMap<ModuleHandle, Map<String, List<EOperation>>>(); } String bundleId = moduleElement.getContributor().getName(); @@ -269,7 +310,7 @@ public class JavaBlackboxProvider extends AbstractBlackboxProvider { } ModuleHandle moduleHandle = new BundleModuleHandle(bundleId, className, moduleName, readUsedPackagesNsURIs(moduleElement)); - fModules.add(moduleHandle); + fModules.put(moduleHandle, new LinkedHashMap<String, List<EOperation>>()); } private List<String> readUsedPackagesNsURIs(IConfigurationElement moduleConfigElement) { diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaMethodHandlerFactory.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaMethodHandlerFactory.java index b22e1c9ca..b93d32f23 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaMethodHandlerFactory.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaMethodHandlerFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,6 +8,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox.java; @@ -24,6 +25,7 @@ import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv; import org.eclipse.m2m.internal.qvt.oml.evaluator.ModuleInstance; import org.eclipse.m2m.internal.qvt.oml.evaluator.NumberConversions; import org.eclipse.m2m.internal.qvt.oml.evaluator.QvtRuntimeException; +import org.eclipse.m2m.internal.qvt.oml.evaluator.TransformationInstance; import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler; import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandlerAdapter; import org.eclipse.m2m.qvt.oml.blackbox.java.Operation; @@ -86,7 +88,7 @@ class JavaMethodHandlerFactory { boolean isStatic = Modifier.isStatic(fMethod.getModifiers()); if(!isStatic) { Class<?> moduleJavaClass = fMethod.getDeclaringClass(); - javaCallSource = module.getAdapter(moduleJavaClass); + javaCallSource = getJavaCallSource(module, moduleJavaClass, evalEnv); //module.getAdapter(moduleJavaClass); assert javaCallSource != null; } @@ -105,7 +107,14 @@ class JavaMethodHandlerFactory { evalEnv.getAdapter(InternalEvaluationEnv.class).throwQVTException( new QvtRuntimeException(NLS.bind(JavaBlackboxMessages.MethodInvocationError, fMethod), e)); return CallHandlerAdapter.getInvalidResult(evalEnv); - } + } + catch (InstantiationException e) { + fFatalErrorCount++; + QvtPlugin.error(NLS.bind(JavaBlackboxMessages.MethodInvocationError, fMethod), e); + evalEnv.getAdapter(InternalEvaluationEnv.class).throwQVTException( + new QvtRuntimeException(NLS.bind(JavaBlackboxMessages.MethodInvocationError, fMethod), e)); + return CallHandlerAdapter.getInvalidResult(evalEnv); + } catch (InvocationTargetException e) { fFatalErrorCount++; QvtPlugin.error(NLS.bind(JavaBlackboxMessages.MethodInvocationError, fMethod), e.getTargetException()); @@ -119,6 +128,27 @@ class JavaMethodHandlerFactory { clearArguments(); } } + + private Object getJavaCallSource(ModuleInstance moduleInstance, Class<?> javaClass, QvtOperationalEvaluationEnv evalEnv) + throws IllegalAccessException, InstantiationException { + + Object callSource = moduleInstance.getAdapter(javaClass); + if (callSource != null) { + return callSource; + } + + TransformationInstance rootTransformation = evalEnv.getRoot().getAdapter(InternalEvaluationEnv.class).getCurrentTransformation(); + + callSource = rootTransformation.getAdapter(javaClass); + if (callSource == null) { + callSource = javaClass.newInstance(); + rootTransformation.getAdapter(ModuleInstance.Internal.class).addAdapter(callSource); + } + + moduleInstance.getAdapter(ModuleInstance.Internal.class).addAdapter(callSource); + + return callSource; + } boolean isDisabled() { return fFatalErrorCount > FAILURE_COUNT_TOLERANCE; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaModuleLoader.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaModuleLoader.java index 83f00233f..2d877ce8b 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaModuleLoader.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/JavaModuleLoader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2009 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,6 +8,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox.java; @@ -15,7 +16,9 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; @@ -46,7 +49,7 @@ abstract class JavaModuleLoader { return (fDiagnostics != null) ? fDiagnostics : Diagnostic.OK_INSTANCE; } - public Diagnostic loadModule(ModuleHandle moduleHandle) { + public Diagnostic loadModule(ModuleHandle moduleHandle, Map<String, List<EOperation>> definedOperations) { fDiagnostics = DiagnosticUtil.createRootDiagnostic(NLS.bind(JavaBlackboxMessages.LoadModuleDiagnostics, moduleHandle)); Class<?> javaClass; try { @@ -82,6 +85,13 @@ abstract class JavaModuleLoader { Diagnostic operationStatus = fOperBuilder.getDiagnostics(); if(DiagnosticUtil.isSuccess(operationStatus)) { loadOperation(operation, method); + + List<EOperation> listOp = definedOperations.get(operation.getName()); + if (listOp == null) { + listOp = new LinkedList<EOperation>(); + definedOperations.put(operation.getName(), listOp); + } + listOp.add(operation); } if(operationStatus.getSeverity() != Diagnostic.OK) { @@ -95,7 +105,7 @@ abstract class JavaModuleLoader { protected abstract void loadModule(QvtOperationalModuleEnv moduleEnv, Class<?> javaModule); protected abstract void loadOperation(EOperation eOperation, Method javaOperation); - private boolean isLibraryOperation(Method method) { + private static boolean isLibraryOperation(Method method) { return Modifier.isPublic(method.getModifiers()); } diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/OperationBuilder.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/OperationBuilder.java index 5a195448b..9d53b33c3 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/OperationBuilder.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/blackbox/java/OperationBuilder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,6 +8,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.blackbox.java; @@ -29,8 +30,8 @@ import org.eclipse.m2m.internal.qvt.oml.expressions.Helper; import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.VarParameter; import org.eclipse.m2m.qvt.oml.blackbox.java.Operation; -import org.eclipse.m2m.qvt.oml.blackbox.java.Parameter; import org.eclipse.m2m.qvt.oml.blackbox.java.Operation.Kind; +import org.eclipse.m2m.qvt.oml.blackbox.java.Parameter; import org.eclipse.m2m.qvt.oml.util.IContext; import org.eclipse.ocl.Environment; @@ -73,24 +74,33 @@ class OperationBuilder { method), method); } - Operation.Kind operKind = (operAnnotation != null) ? operAnnotation.kind() : Operation.Kind.OPERATION; - if(operKind == Kind.OPERATION) { - // FIXME - avoid this, create typedef on the keeping this operation instead - operKind = Kind.HELPER; - } + Operation.Kind operKind = getOperationKind(operAnnotation); - EOperation operation; - if(operKind == Kind.OPERATION) { - operation = EcoreFactory.eINSTANCE.createEOperation(); - } else if(operKind == Kind.QUERY || operKind == Kind.HELPER) { - Helper helper = ExpressionsFactory.eINSTANCE.createHelper(); - helper.setIsQuery(operKind == Kind.QUERY); - operation = helper; - } else { - assert false : "unsupported operation kind"; //$NON-NLS-1$ - operation = EcoreFactory.eINSTANCE.createEOperation(); - } - + EOperation operation = null; + switch (operKind) { + case OPERATION: + operation = EcoreFactory.eINSTANCE.createEOperation(); + break; + case MAPPING: + operation = ExpressionsFactory.eINSTANCE.createMappingOperation(); + break; + case CONSTRUCTOR: + if (!isContextual) { + reportError(NLS.bind(JavaBlackboxMessages.ConstructorRequiresContextualOperation, method.getName()), method); + } + operation = ExpressionsFactory.eINSTANCE.createConstructor(); + break; + case QUERY: case HELPER: + Helper helper = ExpressionsFactory.eINSTANCE.createHelper(); + helper.setIsQuery(operKind == Kind.QUERY); + operation = helper; + break; + default: + assert false : "unsupported operation kind"; //$NON-NLS-1$ + operation = EcoreFactory.eINSTANCE.createEOperation(); + break; + } + operation.setName(name); operation.setEType(fTypeResolver.toEClassifier(resultType)); if(operation.getEType() == null) { @@ -150,9 +160,18 @@ class OperationBuilder { } else if(contextType != null) { environment.getTypeResolver().resolveAdditionalOperation(contextType, operation); } - + return operation; - } + } + + static Kind getOperationKind(Operation operAnnotation) { + Operation.Kind operKind = (operAnnotation != null) ? operAnnotation.kind() : Operation.Kind.OPERATION; + if(operKind == Kind.OPERATION) { + // FIXME - avoid this, create typedef on the keeping this operation instead + operKind = Kind.HELPER; + } + return operKind; + } private static Parameter getParameterAnnotation(Annotation[] allAnnotations) { for (Annotation annotation : allAnnotations) { diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/BlackboxUnitResolver.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/BlackboxUnitResolver.java index 810329718..81d682763 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/BlackboxUnitResolver.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/BlackboxUnitResolver.java @@ -39,8 +39,10 @@ import org.eclipse.m2m.internal.qvt.oml.expressions.Module; public class BlackboxUnitResolver implements UnitResolver { + public static final URI GLOBAL_CONTEXT = URI.createURI("/"); //$NON-NLS-1$ + // the global scope black-box resolver - public static final BlackboxUnitResolver DEFAULT = new BlackboxUnitResolver(URI.createURI("/")); //$NON-NLS-1$ + public static final BlackboxUnitResolver DEFAULT = new BlackboxUnitResolver(GLOBAL_CONTEXT); private ResolutionContext fContext; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/CompiledUnit.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/CompiledUnit.java index 83c28c007..7d1916cca 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/CompiledUnit.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/compiler/CompiledUnit.java @@ -45,6 +45,7 @@ import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil; import org.eclipse.m2m.internal.qvt.oml.cst.CSTFactory; import org.eclipse.m2m.internal.qvt.oml.cst.UnitCS; import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; +import org.eclipse.m2m.internal.qvt.oml.expressions.ImportKind; import org.eclipse.m2m.internal.qvt.oml.expressions.Module; import org.eclipse.m2m.internal.qvt.oml.expressions.ModuleImport; import org.eclipse.ocl.Environment; @@ -116,18 +117,28 @@ public class CompiledUnit { this.fImports = new UniqueEList<CompiledUnit>(); unitMap.put(fUri, this); - - computeImports(unitXMIResource, unitMap); + + if (!BlackboxUnitResolver.isBlackboxUnitURI(fUri)) { + computeImports(unitXMIResource, unitMap); + } // Note: Environment initialization should be optional as it make sense to be used // only in case this unit is to be a compilation dependency to parsed CST Unit for(EObject rootElement : new ArrayList<EObject>(unitXMIResource.getContents())) { - if(rootElement instanceof Module) { - Module nextModule = (Module) rootElement; - QvtOperationalModuleEnv nextModuleEnv = QvtOperationalEnvFactory.INSTANCE.createModuleEnvironment(nextModule); + if(false == rootElement instanceof Module) { + continue; + } + Module nextModule = (Module) rootElement; + QvtOperationalModuleEnv nextModuleEnv = null; + + if (BlackboxUnitResolver.isBlackboxUnitURI(fUri)) { + nextModuleEnv = (QvtOperationalModuleEnv) ASTBindingHelper.resolveEnvironment(nextModule); + } + else { + nextModuleEnv = QvtOperationalEnvFactory.INSTANCE.createModuleEnvironment(nextModule); QVTOTypeResolver typeResolver = nextModuleEnv.getTypeResolver(); - - // FIXME - + + // FIXME - // 1) workaround to make Environment available with the module for // non-transformation execution context // 2) move this initialization code to QVTEnvironment related classes @@ -142,8 +153,14 @@ public class CompiledUnit { } } - this.moduleEnvs.add(nextModuleEnv); + for (CompiledUnit importedUnit : getCompiledImports()) { + for (QvtOperationalModuleEnv importedEnv : importedUnit.moduleEnvs) { + nextModuleEnv.addImport(ImportKind.ACCESS, importedEnv); + } + } } + + this.moduleEnvs.add(nextModuleEnv); } //validate(unitXMIResource, this.fAllProblems); @@ -228,10 +245,10 @@ public class CompiledUnit { unitMap.put(importedResourceURI, importedUnit); } - fImports.add(new CompiledUnit(importedResource, unitMap)); + fImports.add(importedUnit); } } else { - throw new IllegalArgumentException("imported module must be in a resource"); //$NON-NLS-1$ + throw new IllegalArgumentException("imported module must be in a resource: " + String.valueOf(importedModule)); //$NON-NLS-1$ } } } diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/EvaluationMessages.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/EvaluationMessages.java index f7a1b519d..ae124206b 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/EvaluationMessages.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/EvaluationMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Borland Software Corporation and others. + * Copyright (c) 2007, 2014 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 v1.0 @@ -32,6 +32,9 @@ public class EvaluationMessages extends NLS { public static String UknownSourceLabel; public static String MappingPreconditionFailed; public static String ModelTypeConstraintFailed; + public static String NoBlackboxOperationFound; + public static String AmbiguousBlackboxOperationFound; + public static String BlackboxMappingFailedToAssignResult; public static String IteratorNotImpl; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java index 1164c6ae8..421b9b21a 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java @@ -52,12 +52,14 @@ import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtEvaluationResult; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnvFactory; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv; +import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalStdLibrary; import org.eclipse.m2m.internal.qvt.oml.ast.parser.ConstructorOperationAdapter; import org.eclipse.m2m.internal.qvt.oml.ast.parser.IntermediateClassFactory; import org.eclipse.m2m.internal.qvt.oml.ast.parser.IntermediateClassFactory.ExceptionClassInstance; import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil; import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalUtil; +import org.eclipse.m2m.internal.qvt.oml.blackbox.BlackboxRegistry; import org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil; import org.eclipse.m2m.internal.qvt.oml.evaluator.TransformationInstance.InternalTransformation; import org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplateCollectSelect; @@ -143,6 +145,7 @@ import org.eclipse.ocl.EvaluationVisitorImpl; import org.eclipse.ocl.ParserException; import org.eclipse.ocl.ecore.CallOperationAction; import org.eclipse.ocl.ecore.Constraint; +import org.eclipse.ocl.ecore.EcoreEnvironment; import org.eclipse.ocl.ecore.EcoreFactory; import org.eclipse.ocl.ecore.EcorePackage; import org.eclipse.ocl.ecore.SendSignalAction; @@ -166,6 +169,7 @@ import org.eclipse.ocl.types.VoidType; import org.eclipse.ocl.util.Bag; import org.eclipse.ocl.util.CollectionUtil; import org.eclipse.ocl.util.Tuple; +import org.eclipse.ocl.utilities.ASTNode; import org.eclipse.ocl.utilities.PredefinedType; import org.eclipse.ocl.utilities.UMLReflection; @@ -498,6 +502,12 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen public Object visitHelper(Helper helper) { visitImperativeOperation(helper); + + if (helper.isIsBlackbox()) { + Object result = doVisitBlackboxOperation(helper); + return new OperationCallResult(result, getOperationalEvaluationEnv()); + } + return new OperationCallResult(visitOperationBody(helper.getBody()), getOperationalEvaluationEnv()); } @@ -527,6 +537,31 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen pushedStack(getOperationalEvaluationEnv()); return null; } + + private Object doVisitBlackboxOperation(ImperativeOperation operation) { + + assert operation.isIsBlackbox() : "Blackbox operation expected"; //$NON-NLS-1$ + + EcoreEnvironment moduleEnv = ASTBindingHelper.resolveEnvironment((ASTNode) operation.eContainer()); + if (false == moduleEnv instanceof QvtOperationalModuleEnv) { + moduleEnv = ASTBindingHelper.getEnvironment(operation.eContainer(), QvtOperationalModuleEnv.class); + } + + Collection<CallHandler> handlers = BlackboxRegistry.INSTANCE.getBlackboxCallHandler(operation, + //getOperationalEnv().getAdapter(QvtOperationalModuleEnv.class)); + (QvtOperationalModuleEnv) moduleEnv); + if (handlers.isEmpty()) { + throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.NoBlackboxOperationFound, + QvtOperationalParserUtil.safeGetMappingQualifiedName(getOperationalEnv(), operation)))); + } + if (handlers.size() > 1) { + throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.AmbiguousBlackboxOperationFound, + QvtOperationalParserUtil.safeGetMappingQualifiedName(getOperationalEnv(), operation)))); + } + + QvtOperationalEvaluationEnv evalEnv = getOperationalEvaluationEnv(); + return handlers.iterator().next().invoke(evalEnv.getThisOfType(QvtOperationalParserUtil.getOwningModule(operation)), evalEnv.getOperationSelf(), evalEnv.getOperationArgs().toArray(), evalEnv); + } public Object visitLibrary(Library library) { return null; @@ -616,24 +651,25 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen } // call merged mappings - if(!currentMappingCalled.getMerged().isEmpty()) { - for (MappingOperation extendedMapping : currentMappingCalled.getMerged()) { - - // consider overriding mapping - ImperativeOperation overridingOper = EvaluationUtil.getOverridingOperation(getOperationalEvaluationEnv(), extendedMapping); - if (overridingOper instanceof MappingOperation) { - extendedMapping = (MappingOperation) overridingOper; - } - - executeImperativeOperation(extendedMapping, evalEnv.getOperationSelf(), evalEnv.getOperationArgs(), true); - } - } + callMergedMappings(currentMappingCalled, evalEnv); // result may have changed in body, end section, or merged mappings, so retrieve it again (fixed by bug 388325) result = getRuntimeValue(Environment.RESULT_VARIABLE_NAME); return result; } + + private void callMergedMappings(MappingOperation mappingOperation, QvtOperationalEvaluationEnv evalEnv) { + for (MappingOperation extendedMapping : mappingOperation.getMerged()) { + // consider overriding mapping + ImperativeOperation overridingOper = EvaluationUtil.getOverridingOperation(getOperationalEvaluationEnv(), extendedMapping); + if (overridingOper instanceof MappingOperation) { + extendedMapping = (MappingOperation) overridingOper; + } + + executeImperativeOperation(extendedMapping, evalEnv.getOperationSelf(), evalEnv.getOperationArgs(), true); + } + } public Object visitMappingCallExp(MappingCallExp mappingCallExp) { return visitOperationCallExp(mappingCallExp); @@ -800,9 +836,25 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen if(!mappingOperation.getDisjunct().isEmpty()) { return dispatchDisjunctMapping(mappingOperation); } - - return new MappingCallResult(((OperationBodyImpl) mappingOperation.getBody()).accept(getVisitor()), - evalEnv, MappingCallResult.BODY_EXECUTED); + + if (mappingOperation.isIsBlackbox()) { + Object result = doVisitBlackboxOperation(mappingOperation); + if (isUndefined(result)) { + throwQVTException(new QvtRuntimeException(NLS.bind(EvaluationMessages.BlackboxMappingFailedToAssignResult, + QvtOperationalParserUtil.safeGetMappingQualifiedName(getOperationalEnv(), mappingOperation)))); + } + + replaceInEnv(Environment.RESULT_VARIABLE_NAME, result, mappingOperation.getEType()); + TraceUtil.addTraceRecord(getOperationalEvaluationEnv(), mappingOperation); + + // call merged mappings + callMergedMappings(mappingOperation, evalEnv); + + return new MappingCallResult(result, evalEnv, MappingCallResult.BODY_EXECUTED); + } + + return new MappingCallResult(((OperationBodyImpl) mappingOperation.getBody()).accept(getVisitor()), evalEnv, + MappingCallResult.BODY_EXECUTED); } public Object execute(OperationalTransformation transformation) throws QvtRuntimeException { @@ -932,6 +984,10 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen Adapter adapter = EcoreUtil.getAdapter(objectExp.eAdapters(), ConstructorOperationAdapter.class); if (adapter != null) { Constructor constructorOp = ((ConstructorOperationAdapter) adapter).getReferredConstructor(); + + for (int i = 0, in = constructorOp.getEParameters().size(); i < in; ++i) { + actualArguments.set(i, doImplicitListCoercion(constructorOp.getEParameters().get(i).getEType(), actualArguments.get(i))); + } executeImperativeOperation(constructorOp, owner, actualArguments, false); } @@ -1444,9 +1500,16 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen public Object visitConstructor(Constructor constructor) { visitImperativeOperation(constructor); + QvtOperationalEvaluationEnv env = getOperationalEvaluationEnv(); + + if (constructor.isIsBlackbox()) { + Object result = doVisitBlackboxOperation(constructor); + return new OperationCallResult(result, env); + } + env.add(Environment.RESULT_VARIABLE_NAME, env.remove(Environment.SELF_VARIABLE_NAME)); - return new OperationCallResult(visitOperationBody(constructor.getBody()), getOperationalEvaluationEnv()); + return new OperationCallResult(visitOperationBody(constructor.getBody()), env); } public Object visitConstructorBody(ConstructorBody constructorBody) { @@ -1715,11 +1778,6 @@ implements QvtOperationalEvaluationVisitor, InternalEvaluator, DeferredAssignmen } private OperationCallResult executeImperativeOperation(ImperativeOperation method, Object source, List<Object> args, boolean isReusingMappingCall) { - if (method.isIsBlackbox() && method.getBody() == null) { - throw new IllegalArgumentException( - "Can't execute blackbox operation" + method.getName()); //$NON-NLS-1$ - } - QvtOperationalEvaluationEnv oldEvalEnv = getOperationalEvaluationEnv(); boolean isMapping = method instanceof MappingOperation; diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/messages.properties b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/messages.properties index 0728d9062..3e9529123 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/messages.properties +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2007, 2009 Borland Software Corporation and others. +# Copyright (c) 2007, 2014 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 v1.0 @@ -23,3 +23,6 @@ QvtOperationalEvaluationVisitorImpl_invalidConfigPropertyValue=Failed to get ''{ QvtOperationalEvaluationVisitorImpl_UndefModelParamInTransf=Undefined model passed to transformation QvtOperationalEvaluationVisitorImpl_unexpectedRuntimeExc=Unexpected runtime exception caught during execution IteratorNotImpl=Iterator ({0}) not yet implemented. +NoBlackboxOperationFound=No blackbox implementation found for operation ''{0}'' +AmbiguousBlackboxOperationFound=Ambiguous blackbox implementation found for operation ''{0}'' +BlackboxMappingFailedToAssignResult=Blackbox operation ''{0}'' failed to assign mapping result
\ No newline at end of file diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/qvt/oml/blackbox/java/Operation.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/qvt/oml/blackbox/java/Operation.java index 4a55dd508..7dc74bd83 100644 --- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/qvt/oml/blackbox/java/Operation.java +++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/qvt/oml/blackbox/java/Operation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Borland Software Corporation and others. + * Copyright (c) 2008, 2013 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 v1.0 @@ -8,6 +8,7 @@ * * Contributors: * Borland Software Corporation - initial API and implementation + * Christopher Gerking - bug 289982 *******************************************************************************/ package org.eclipse.m2m.qvt.oml.blackbox.java; @@ -43,6 +44,16 @@ public @interface Operation { */ QUERY, /** + * The operation is defined as operational<code>mapping</code>. + * @since 3.4 + */ + MAPPING, + /** + * The operation is defined as contextual<code>constructor</code>. + * @since 3.4 + */ + CONSTRUCTOR, + /** * The operation is defined as normal operation. If the associated operation is defined as * <code>contextual</code>, the Typedef class is used to represent it as additional operation * in the owning <code>Module</code> class. |