| /******************************************************************************* |
| * Copyright (c) 2008, 2009 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.evaluator; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.eclipse.emf.common.util.UniqueEList; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.m2m.internal.qvt.oml.ast.env.ModelParameterExtent; |
| import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalUtil; |
| import org.eclipse.m2m.internal.qvt.oml.evaluator.TransformationInstance.InternalTransformation; |
| import org.eclipse.m2m.internal.qvt.oml.expressions.ModelParameter; |
| import org.eclipse.m2m.internal.qvt.oml.expressions.ModelType; |
| import org.eclipse.m2m.internal.qvt.oml.expressions.OperationalTransformation; |
| |
| /** |
| * This class encapsulates the logic of model extent binding for imported transformation. |
| * </p> |
| * The QVT <code>1.0</code> model parameter binding is implemented here, taking the following strategy. |
| * <ul> |
| * <li>1. Try binding model parameters that are strictly compatible by modeltype and direction kind</li> |
| |
| * <li>2. Try binding (not yet bound) model parameters by the first available of a compatible direction kind</li> |
| * |
| * <li>3. Create empty model extent for all model parameter remaining unbound</li> |
| * </ul> |
| * |
| * @author dvorak |
| */ |
| public class ModelParameterHelper { |
| |
| private OperationalTransformation fMainTransformation; |
| private List<ModelInstance> fModelArguments; |
| |
| /** |
| * Create actual model arguments for the given transformation. |
| * |
| * @param transformation |
| * the transformation of which the <code>main</code> operation is |
| * to be executed |
| * @param modelExtentArgs |
| * the model extents that are passed to transformation execution |
| */ |
| public static List<ModelInstance> createModelArguments(OperationalTransformation transformation, List<ModelParameterExtent> modelExtentArgs) { |
| if(transformation == null || modelExtentArgs == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| if(modelExtentArgs.size() != transformation.getModelParameter().size()) { |
| throw new IllegalArgumentException("Invalid number of transformation arguments"); //$NON-NLS-1$ |
| } |
| |
| List<ModelInstance> modelArgs = new ArrayList<ModelInstance>(modelExtentArgs.size()); |
| int pos = 0; |
| for (ModelParameterExtent nextExtent : modelExtentArgs) { |
| if(nextExtent == null) { |
| throw new IllegalArgumentException("null model extent argument"); //$NON-NLS-1$ |
| } |
| ModelParameter modelParam = transformation.getModelParameter().get(pos++); |
| modelArgs.add(createModel(modelParam, nextExtent)); |
| } |
| |
| return modelArgs; |
| } |
| |
| ModelParameterHelper(OperationalTransformation mainTransformation, List<ModelInstance> modelArgs) { |
| if(mainTransformation == null || modelArgs == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| if(modelArgs.size() != mainTransformation.getModelParameter().size()) { |
| throw new IllegalArgumentException("Invalid number of transformation arguments"); //$NON-NLS-1$ |
| } |
| |
| int pos = 0; |
| for (ModelInstance nextModel : modelArgs) { |
| if(nextModel == null) { |
| throw new IllegalArgumentException("null model argument"); //$NON-NLS-1$ |
| } |
| |
| ModelParameter modelParam = mainTransformation.getModelParameter().get(pos++); |
| EClassifier modelType = modelParam.getEType(); |
| if(nextModel.eClass().isInstance(modelType)) { |
| throw new IllegalArgumentException("Invalid model for parameter: " + modelParam); //$NON-NLS-1$ |
| } |
| } |
| |
| fMainTransformation = mainTransformation; |
| fModelArguments = new ArrayList<ModelInstance>(modelArgs); |
| } |
| |
| /** |
| * Binds model extents to model parameters of the given |
| * transformation in the context of the main transformation and its imported transformations. |
| * |
| * @param transformation |
| * the transformation to be bind with its model parameters. It must be the trasnformation |
| * assigned to this helper or one of its imported transformations |
| */ |
| void initModelParameters(TransformationInstance transformation) { |
| if(transformation == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| boolean isMainTransformation = transformation.getTransformation() == fMainTransformation; |
| OperationalTransformation transformationType = transformation.getTransformation(); |
| Collection<ModelInstance> alreadyBound = new UniqueEList.FastCompare<ModelInstance>(); |
| |
| int pos = 0; |
| for (ModelParameter modelParam : transformationType.getModelParameter()) { |
| ModelInstance passedModel; |
| if(isMainTransformation) { |
| passedModel = fModelArguments.get(pos); |
| } else { |
| passedModel = findAvailableStrictlyCompatibleExtent(modelParam, alreadyBound); |
| } |
| |
| if(passedModel == null) { |
| continue; |
| } |
| |
| ModelInstance actualModel; |
| if(passedModel.getModelType() == modelParam.getEType()) { |
| // model parameter refer the same modeltype as the model instance |
| // => reuse the model instance for passing as model argument |
| actualModel = passedModel; |
| } else { |
| // we are just compatible by referred metamodels, so create |
| // new model instance of a specific modeltype |
| actualModel = createModel(modelParam, passedModel.getExtent()); |
| } |
| |
| transformation.getAdapter(InternalTransformation.class).setModel(modelParam, actualModel); |
| |
| pos++; |
| } |
| |
| if(isMainTransformation) { |
| return; |
| } |
| |
| // second pass |
| // 1) try resolving by compatible direction only |
| // 2) create unbound extents to capture the contents for not yet bound model parameters |
| for (ModelParameter modelParam : transformationType.getModelParameter()) { |
| // process only not set parameters |
| if(transformation.getModel(modelParam) == null) { |
| ModelInstance resolvedModel = findFirstDirectionCompatibleExtent(modelParam, alreadyBound); |
| |
| ModelInstance actualModel; |
| if(resolvedModel == null) { |
| // can't find any compatible model parameter, just create an empty extent |
| actualModel = createModel(modelParam, new ModelParameterExtent()); |
| } else { |
| // take just the content as we have not found strictly compatible model parameter |
| // in the 1. pass, we have to create new model instance but reusing the extent |
| actualModel = createModel(modelParam, resolvedModel.getExtent()); |
| } |
| |
| transformation.getAdapter(InternalTransformation.class).setModel(modelParam, actualModel); |
| } |
| } |
| } |
| |
| private ModelInstance findFirstDirectionCompatibleExtent(ModelParameter modelParam, Collection<ModelInstance> alreadyBound) { |
| int pos = 0; |
| for (ModelParameter nextParam : fMainTransformation.getModelParameter()) { |
| if(QvtOperationalUtil.isModelParamEqual(nextParam, modelParam, false)) { |
| ModelInstance extent = fModelArguments.get(pos); |
| if(!alreadyBound.contains(extent)) { |
| alreadyBound.add(extent); |
| return extent; |
| } |
| } |
| |
| pos++; |
| } |
| |
| return null; |
| } |
| |
| private ModelInstance findAvailableStrictlyCompatibleExtent(ModelParameter modelParam, Collection<ModelInstance> alreadyBound) { |
| int pos = 0; |
| for (ModelParameter nextParam : fMainTransformation.getModelParameter()) { |
| if(QvtOperationalUtil.isModelParamEqual(nextParam, modelParam, true)) { |
| ModelInstance extent = fModelArguments.get(pos); |
| if(!alreadyBound.contains(extent)) { |
| alreadyBound.add(extent); |
| return extent; |
| } |
| } |
| |
| pos++; |
| } |
| |
| return null; |
| } |
| |
| private static ModelInstance createModel(ModelParameter modelParam, ModelParameterExtent extent) { |
| assert modelParam != null; |
| assert extent != null; |
| |
| ModelType modelType = (ModelType) modelParam.getEType(); |
| ModelInstance model = new ModelInstanceImpl(modelType, extent); |
| return model; |
| } |
| } |