/* Copyright (C) 2010 by Claas Wilke (claaswilke@gmx.net) This file is part of the OCL Interpreter of DresdenOCL. DresdenOCL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. DresdenOCL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with DresdenOCL. If not, see <http://www.gnu.org/licenses/>. */ package org.dresdenocl.interpreter.internal; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import org.dresdenocl.essentialocl.expressions.OperationCallExp; import org.dresdenocl.essentialocl.expressions.Variable; import org.dresdenocl.essentialocl.standardlibrary.OclAny; import org.dresdenocl.essentialocl.standardlibrary.OclModelInstanceObject; import org.dresdenocl.interpreter.IInterpretationEnvironment; import org.dresdenocl.interpreter.IOclInterpreter; import org.dresdenocl.modelinstance.IModelInstance; import org.dresdenocl.modelinstancetype.types.IModelInstanceElement; import org.dresdenocl.modelinstancetype.types.IModelInstanceObject; import org.dresdenocl.pivotmodel.Constraint; import org.dresdenocl.pivotmodel.Type; /** * <p> * This Environment is used to save data needed for interpretation. E.g., values * of parameters, variables, expressions, @pre values etc. * </p> * * @author Claas Wilke (first version by Ronny Brandt). */ public class InterpretationEnvironment implements IInterpretationEnvironment { /** * {@link Map} to store @pre values used during postcondition evaluation. Uses * {@link IModelInstanceElement}s as key to store the values for each specific * {@link IModelInstanceObject} seperately. This {@link Map} is created lazily * since children {@link InterpretationEnvironment}s delegate their requests * to their parent. */ protected Map<IModelInstanceElement, Map<OperationCallExp, OclAny>> atPreValues; /** The {@link IModelInstance} of this {@link InterpretationEnvironment}. */ protected IModelInstance modelInstance; /** * Saved instances of {@link Type}s existing at the latest {@link Constraint} * 's preparation (required for <code>oclIsNew()</code>). This {@link Map} is * initialized lazily since children {@link InterpretationEnvironment}s do not * need such a {@link Map}. */ protected Map<Type, Set<IModelInstanceObject>> oldInstancesByType; /** * A probably existing parent {@link InterpretationEnvironment} of this * {@link InterpretationEnvironment}. */ protected InterpretationEnvironment parentEnvironment = null; /** Containes variables already computed {@link Variable}'s values. */ protected HashMap<String, OclAny> visibleVariableValues = new HashMap<String, OclAny>(); /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment# * createChildEnvironment() */ public IInterpretationEnvironment createChildEnvironment() { InterpretationEnvironment result = new InterpretationEnvironment(); result.parentEnvironment = this; result.modelInstance = this.modelInstance; return result; } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IEnvironment#getPostconditionValue( * tudresden .ocl20.pivot.essentialocl.expressions.OperationCallExp) */ public OclAny getAtPreValue(OperationCallExp operationCallExp) { OclAny result; OclAny contextObject; result = null; /* Probably delegate to parent environment. */ if (this.parentEnvironment != null) { result = this.parentEnvironment.getAtPreValue(operationCallExp); } else { /* Try to get the @pre values for the current 'self' object. */ if (this.atPreValues != null) { Map<OperationCallExp, OclAny> instanceElementSpecificAtPreValues; /* * Get the ModelInstanceObject for which the postcondition is currently * evaluated. */ contextObject = this.getVariableValue(IOclInterpreter.SELF_VARIABLE_NAME); instanceElementSpecificAtPreValues = this.atPreValues.get(contextObject.getModelInstanceElement()); /* Try to get the value for the given expression. */ if (instanceElementSpecificAtPreValues != null) { result = instanceElementSpecificAtPreValues.get(operationCallExp); } // no else. } // no else. } return result; } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment#getModelInstance * () */ public IModelInstance getModelInstance() { return this.modelInstance; } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment#getVariableValue * (java.lang.String) */ public OclAny getVariableValue(String identifier) { OclAny result = visibleVariableValues.get(identifier); /* * Probably delegate to parent environment (Variables are visible for * children as well). */ if (result == null && this.parentEnvironment != null) { result = this.parentEnvironment.getVariableValue(identifier); } // no else. return result; } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment#isNewInstance * (tudresden * .ocl20.pivot.essentialocl.standardlibrary.OclModelInstanceObject) */ public boolean isNewInstance(OclModelInstanceObject object) { boolean result; IModelInstanceObject imiObject; imiObject = (IModelInstanceObject) object.getModelInstanceElement(); /* Probably check the parent environment. */ if (this.parentEnvironment != null) { result = this.parentEnvironment.isNewInstance(object); } /* * If any imiObject's type's instances contains the imiObject, return false. * Else return true. */ else if (this.oldInstancesByType != null && this.oldInstancesByType.containsKey(imiObject.getType())) { result = !this.oldInstancesByType.get(imiObject.getType()).contains(imiObject); } else { result = false; } return result; } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IEnvironment#savePostconditionValue * (tudresden .ocl20.pivot.essentialocl.expressions.OperationCallExp, * org.dresdenocl.essentialocl.standardlibrary.OclAny) */ public void saveAtPreValue(OperationCallExp anOperationCallExp, OclAny value) { /* Probably delegate to parent environment. */ if (this.parentEnvironment != null) { this.parentEnvironment.saveAtPreValue(anOperationCallExp, value); } else { Map<OperationCallExp, OclAny> instanceObjectSpecificValues; OclAny contextObject; /* Check if any @pre values have been stored yet. */ if (this.atPreValues == null) { this.atPreValues = new WeakHashMap<IModelInstanceElement, Map<OperationCallExp, OclAny>>(); } // no else. /* * Get the ModelInstanceObject for which a @pre value shall be stored. */ contextObject = this.getVariableValue(IOclInterpreter.SELF_VARIABLE_NAME); instanceObjectSpecificValues = this.atPreValues.get(contextObject.getModelInstanceElement()); /* Probably initialize the ModelInstanceObject specific @pre values. */ if (instanceObjectSpecificValues == null) { instanceObjectSpecificValues = new HashMap<OperationCallExp, OclAny>(); } // no else. /* Store the postcondition value. */ instanceObjectSpecificValues.put(anOperationCallExp, value); /* Store the specific values. */ this.atPreValues.put(contextObject.getModelInstanceElement(), instanceObjectSpecificValues); } // end else. } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment#saveOldInstances * (org.dresdenocl.pivotmodel.Type) */ public void saveOldInstances(Type type) { /* * If possible use the parent environment to avoid duplicate entries causing * memory overhead. */ if (this.parentEnvironment == null) { /* Lazy initialization. */ if (this.oldInstancesByType == null) { this.oldInstancesByType = new WeakHashMap<Type, Set<IModelInstanceObject>>(); } // no else. this.oldInstancesByType.put(type, this.modelInstance.getAllInstances(type)); } else { this.parentEnvironment.saveOldInstances(type); } } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment#setModelInstance * (org.dresdenocl.modelinstance.IModelInstance) */ public void setModelInstance(IModelInstance modelInstance) { this.modelInstance = modelInstance; } /* * (non-Javadoc) * @see org.dresdenocl.interpreter.IInterpretationEnvironment#setVariableValue * (java.lang.String, org.dresdenocl.essentialocl.standardlibrary.OclAny) */ public void setVariableValue(String identifier, OclAny oclRoot) { this.visibleVariableValues.put(identifier, oclRoot); } public void deleteVariableValue(String identifier) { visibleVariableValues.remove(identifier); } @Override public Map<String, OclAny> getVariableValues() { Map<String, OclAny> result = new HashMap<String, OclAny>(visibleVariableValues); if(parentEnvironment != null) { result.putAll(parentEnvironment.getVariableValues()); } return result; } }