/******************************************************************************* * 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 * 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.ocl.transformations; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; import org.eclipse.m2m.internal.qvt.oml.ast.binding.ASTBindingHelper; 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.QvtOperationalUtil; import org.eclipse.m2m.internal.qvt.oml.blackbox.BlackboxUnitDescriptor; import org.eclipse.m2m.internal.qvt.oml.cst.CSTFactory; import org.eclipse.m2m.internal.qvt.oml.evaluator.ModuleInstance; import org.eclipse.m2m.internal.qvt.oml.expressions.DirectionKind; import org.eclipse.m2m.internal.qvt.oml.expressions.Helper; import org.eclipse.m2m.internal.qvt.oml.expressions.Module; import org.eclipse.m2m.internal.qvt.oml.expressions.VarParameter; import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandler; import org.eclipse.m2m.internal.qvt.oml.stdlib.CallHandlerAdapter; import org.eclipse.ocl.Environment; /** * This class facilitates registration and invocation of legacy java native * operation hooked into QVT environments. * <p> * Remark: It has come from the initial contribution. */ public class LegacyNativeLibSupport { public static final LegacyNativeLibSupport INSTANCE = createInstance(); private LegacyNativeLibSupport() { } public QvtOperationalModuleEnv defineLibrary(Library lib, Map<String, List<EOperation>> definedOperations) throws LibraryCreationException { org.eclipse.m2m.internal.qvt.oml.expressions.Library libModule = QvtOperationalStdLibrary.createLibrary(lib.getId()); // FIXME - set isBlackBox=TRUE, as soon is it gets into the AST metamodel QvtOperationalModuleEnv libEnv = initLibEnvironment(lib, libModule); URI libUri = URI.createHierarchicalURI(BlackboxUnitDescriptor.URI_QVTO_SCHEME, BlackboxUnitDescriptor.URI_BLACKBOX_AUTHORITY, null, new String[] {lib.getId()}, null, null); libModule.eResource().setURI(libUri); org.eclipse.m2m.internal.qvt.oml.expressions.Library opModule = QvtOperationalStdLibrary.createLibrary(lib.getId()); QvtOperationalModuleEnv opEnv = initLibEnvironment(lib, opModule); for (LibraryOperation libOp : lib.getLibraryOperations()) { Helper helper = defineOperation(opModule, opEnv, libOp); libEnv.defineImperativeOperation(helper, false, true); List<EOperation> listOp = definedOperations.get(helper.getName()); if (listOp == null) { listOp = new LinkedList<EOperation>(); definedOperations.put(helper.getName(), listOp); } listOp.add(helper); } // FIXME - workaround to make Environment available with the module ASTBindingHelper.createCST2ASTBinding(CSTFactory.eINSTANCE.createLibraryCS(), libEnv.getModuleContextType(), libEnv); return libEnv; } private static QvtOperationalModuleEnv initLibEnvironment(Library lib, Module libModule) { EPackage.Registry registry = new EPackageRegistryImpl(); QvtOperationalModuleEnv libEnv = new QvtOperationalEnvFactory(registry).createModuleEnvironment(libModule); EPackage.Registry libEnvRegistry = libEnv.getEPackageRegistry(); // set our desired stdlib version to be resolved by oclstdlib package name EPackage oclStdlibPackage = libEnv.getOCLStandardLibrary().getOclAny().getEPackage(); libEnv.getEPackageRegistry().put(oclStdlibPackage.getNsURI(), oclStdlibPackage); if (lib.getInMetamodels() != null) { for (String mm : lib.getInMetamodels()) { EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(mm); if(ePackage != null) { libEnvRegistry.put(mm, ePackage); } } } if (lib.getOutMetamodels() != null) { for (String mm : lib.getOutMetamodels()) { EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(mm); if(ePackage != null) { libEnvRegistry.put(mm, ePackage); } } } return libEnv; } private static class Handler extends CallHandler { private LibraryOperation fOperation; private Class<?> fReturnClass; private Handler(LibraryOperation operation, Class<?> returnClass) { assert operation != null; fOperation = operation; fReturnClass = returnClass; } public Object invoke(ModuleInstance module, Object source, Object[] args, QvtOperationalEvaluationEnv evalEnv) { return callOperation(evalEnv, fOperation, source, args, fReturnClass); } } private static Object callOperation(QvtOperationalEvaluationEnv evalEnv, LibraryOperation libOp, Object source, Object[] args, Class<?> returnClass) { if(source == null || source == CallHandlerAdapter.getInvalidResult(evalEnv)) { return CallHandlerAdapter.getInvalidResult(evalEnv); } // reset OclInvalid to 'null' Object[] callArgs = null; if(args != null) { for (int i = 0; i < args.length; i++) { if(evalEnv.isOclInvalid(args[i])) { if(callArgs == null) { callArgs = new Object[args.length]; System.arraycopy(args, 0, callArgs, 0, args.length); } callArgs[i] = null; } } callArgs = (callArgs == null) ? args : callArgs; } Object result = libOp.run(source, callArgs, new Object[0], returnClass); if (result == null) { return QvtOperationalUtil.getInvalid(evalEnv); } return result; } private Helper defineOperation(org.eclipse.m2m.internal.qvt.oml.expressions.Library opModule, QvtOperationalModuleEnv opEnv, LibraryOperation libOp) throws LibraryCreationException { QvtLibraryOperation qvtLibOp = new QvtLibraryOperation(opEnv, libOp); Helper helper = org.eclipse.m2m.internal.qvt.oml.expressions.ExpressionsFactory.eINSTANCE.createHelper(); helper.setName(libOp.getName()); helper.setEType(qvtLibOp.getReturnType()); int index = 1; for (EClassifier type : qvtLibOp.getParamTypes()) { VarParameter varParam = org.eclipse.m2m.internal.qvt.oml.expressions.ExpressionsFactory.eINSTANCE.createVarParameter(); varParam.setKind(DirectionKind.IN); varParam.setEType(type); varParam.setName("arg" + index); //$NON-NLS-1$; ++index; helper.getEParameters().add(varParam); } if (qvtLibOp.getContextType() != opModule) { VarParameter varParam = org.eclipse.m2m.internal.qvt.oml.expressions.ExpressionsFactory.eINSTANCE.createVarParameter(); varParam.setKind(DirectionKind.IN); varParam.setEType(qvtLibOp.getContextType()); varParam.setName(Environment.SELF_VARIABLE_NAME); helper.setContext(varParam); } Class<?> returnClass = (helper.getEType() != null) ? helper.getEType().getInstanceClass() : null; CallHandlerAdapter.attach(helper, new Handler(libOp, returnClass)); return helper; } private static LegacyNativeLibSupport createInstance() { LegacyNativeLibSupport lib = new LegacyNativeLibSupport(); return lib; } }