/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2007 Matthias Braeuer (braeuer.matthias@web.de). * * All rights reserved. * * * * This work was done as a project at the Chair for Software Technology, * * Dresden University Of Technology, Germany (http://st.inf.tu-dresden.de). * * It is understood that any modification not identified as such is not * * covered by the preceding statement. * * * * This work is free software; you can redistribute it and/or modify it * * under the terms of the GNU Library General Public License as published * * by the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This work 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 Library General Public * * License for more details. * * * * You should have received a copy of the GNU Library General Public License * * along with this library; if not, you can view it online at * * http://www.fsf.org/licensing/licenses/gpl.html. * * * * To submit a bug report, send a comment, or get the latest news on this * * project, please visit the website: http://dresden-ocl.sourceforge.net. * * For more information on OCL and related projects visit the OCL Portal: * * http://st.inf.tu-dresden.de/ocl * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * $Id$ */ package org.dresdenocl.essentialocl.expressions.impl; import java.util.ArrayList; import org.apache.log4j.Logger; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.dresdenocl.essentialocl.expressions.ExpressionsFactory; import org.dresdenocl.essentialocl.expressions.OclExpression; import org.dresdenocl.essentialocl.expressions.OperationCallExp; import org.dresdenocl.essentialocl.types.AnyType; import org.dresdenocl.essentialocl.types.CollectionType; import org.dresdenocl.essentialocl.types.InvalidType; import org.dresdenocl.essentialocl.types.OclLibrary; import org.dresdenocl.essentialocl.types.VoidType; import org.dresdenocl.pivotmodel.Operation; import org.dresdenocl.pivotmodel.PrimitiveType; import org.dresdenocl.pivotmodel.PrimitiveTypeKind; import org.dresdenocl.pivotmodel.Type; import org.dresdenocl.pivotmodel.impl.OperationImpl; import org.dresdenocl.pivotmodel.impl.TypedElementImpl; /** * <!-- begin-user-doc --> An implementation of the model object ' * <em><b>Ocl Expression</b></em>'. <!-- end-user-doc --> * <p> * The following features are implemented: * <ul> * <li>{@link org.dresdenocl.essentialocl.expressions.impl.OclExpressionImpl#getOclLibrary <em>Ocl Library</em>}</li> * </ul> * </p> * * @generated */ public abstract class OclExpressionImpl extends TypedElementImpl implements OclExpression { /** * Logger for this class */ private static final Logger logger = Logger .getLogger(OclExpressionImpl.class); /** * The cached value of the '{@link #getOclLibrary() <em>Ocl Library</em>}' reference. * <!-- begin-user-doc --> <!-- end-user-doc --> * @see #getOclLibrary() * @generated * @ordered */ protected OclLibrary oclLibrary; /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ protected OclExpressionImpl() { super(); } /** * Overridden to implement lazy caching of evaluated types. Subclasses should * implement {@link #evaluateType()} for the actual type evaluation logic. * * @see org.dresdenocl.pivotmodel.impl.TypedElementImpl#getType() */ @Override public final Type getType() { if (type == null) { type = evaluateType(); } return type; } /** * Evaluates the type of this <code>OclExpression</code>. Subclasses need to * implement this according to the OCL specification. * * @return a <code>Type</code> instance. */ protected abstract Type evaluateType(); /** * Overridden to prevent clients from setting the type of an * <code>OclExpression</code> directly. This method will throw an * {@link UnsupportedOperationException}. * * @see org.dresdenocl.pivotmodel.impl.TypedElementImpl#setType(org.dresdenocl.pivotmodel.Type) */ @Override public void setType(Type newType) { throw new UnsupportedOperationException( "The type of an OclExpression cannot be set directly because it is evaluated automatically."); //$NON-NLS-1$ } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public OclLibrary getOclLibrary() { return oclLibrary; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setOclLibrary(OclLibrary newOclLibrary) { OclLibrary oldOclLibrary = oclLibrary; oclLibrary = newOclLibrary; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, ExpressionsPackageImpl.OCL_EXPRESSION__OCL_LIBRARY, oldOclLibrary, oclLibrary)); } /** * Additional operation defined in the OCL specification, Section 8.3.9: * * <p> * The following operation returns an operation call expression for the * predefined <em>atPre()</em> operation with the self expression as its * source. * * <pre> * context OclExpression::withAtPre() : OperationCallExp * post: result.name = �atPre� * post: result.argument->isEmpty() * post: result.source = self * </pre> * * </p> * * @generated NOT */ public OperationCallExp withAtPre() { if (logger.isDebugEnabled()) { logger.debug("withAtPre() - enter"); //$NON-NLS-1$ } OperationCallExp atPre; // create a new operation call expression atPre = ExpressionsFactory.INSTANCE.createOperationCallExp(); atPre.setName("atPre"); //$NON-NLS-1$ atPre.setSource(this); if (logger.isDebugEnabled()) { logger.debug("withAtPre() - exit - return value=" + atPre); //$NON-NLS-1$ } return atPre; } /** * Additional operation defined in the OCL Specification, Section 8.3.9: * * <p> * The following operation returns an operation call expression for the * predefined asSet() operation with the self expression as its source. * * <pre> * context OclExpression::withAsSet() : OperationCallExp * post: result.name = �asSet� * post: result.argument->isEmpty() * post: result.source = self * </pre> * * </p> * * <p> * Note that this implementation additionally sets the referred operation of * the new <code>OperationCallExp</code> to the corresponding * <code>asSet</code> operation, The OCL specification seems to be incomplete * here because it remains open how the referred operation should be found by * an OCL code generator or interpreter. Since <code>asSet</code> is a generic * operation, it is {@link OperationImpl#bindTypeParameter() bound} with the * type of this <code>OclExpression</code>. * </p> * * @generated NOT * */ public OperationCallExp withAsSet() { if (logger.isDebugEnabled()) { logger.debug("withAsSet() - enter"); //$NON-NLS-1$ } // lookup the asSet operation Operation asSetOperation = getType().lookupOperation( "asSet", new ArrayList<Type>()); //$NON-NLS-1$ if (asSetOperation == null) { throw new IllegalStateException( "Failed to lookup the 'asSet' operation in type '" //$NON-NLS-1$ + getType().getName() + "'."); //$NON-NLS-1$ } // check that the operation defines a single type parameter if (asSetOperation.getOwnedTypeParameter().size() != 1) { throw new IllegalStateException( "The 'asSet' operation in type '" + getType().getName() //$NON-NLS-1$ + "' does not define the expected type parameter."); //$NON-NLS-1$ } // create a new operation call expression OperationCallExp withAsSet = ExpressionsFactory.INSTANCE .createOperationCallExp(); withAsSet.setName("asSet"); //$NON-NLS-1$ withAsSet.setSource(this); withAsSet.setReferredOperation(asSetOperation); // set the reference to the OCL Library withAsSet.setOclLibrary(oclLibrary); if (logger.isDebugEnabled()) { logger.debug("withAsSet() - exit - return value=" + withAsSet); //$NON-NLS-1$ } return withAsSet; } /** * Helper method to be used in subclasses when determining the * {@link #getType() type} of an OCL expression. The method will make sure * that a Pivot Model <code>Type</code> can be used within OCL expressions. * * <p> * If the given type is a {@link PrimitiveType} whose kind is not * {@link PrimitiveTypeKind#UNKNOWN UNKNOWN}, it will be transformed into the * corresponding primitive type from the OCL Library. Otherwise, unless the * type is an OCL {@link CollectionType}, {@link VoidType} or * {@link InvalidType}, this method will ensure that the given type descends * from {@link OclLibrary#getOclAny() OclAny} to provide the predefined OCL * operations. * </p> * * <p> * This method will throw an {@link IllegalStateException} if the * {@link #getOclLibrary() OclLibrary reference} has not been initialized. * </p> * * @param type * the type that should be "converted" into an OCL-compatible type * * @return either one of the predefined OCL primitive types or the same type * with <code>OclAny</code> as one of its supertypes * * @throws IllegalStateException * if {@link #getOclLibrary()} is <code>null</code> */ protected Type getOclType(Type type) { if (logger.isDebugEnabled()) { logger.debug("getOclType(type=" + type + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } // check parameter (note that a type of null does NOT imply a conversion to // OclVoid because null and OclVoid are defined on different meta layers) if (type == null) { throw new IllegalArgumentException( "Parameter 'type' must not be null"); //$NON-NLS-1$ } // make sure we have access to the OCL library if (oclLibrary == null) { throw new IllegalStateException( "Unable to determine the OCL type for '" + type.getName() //$NON-NLS-1$ + "' because the OCL Library reference has not been initialized."); //$NON-NLS-1$ } // map primitive types if (type instanceof PrimitiveType) { type = mapPrimitiveType((PrimitiveType) type); } // type must derive from OclAny unless it is a collection, void or invalid else if (!(type instanceof CollectionType || type instanceof VoidType || type instanceof InvalidType)) { type = ensureDescendanceFromOclAny(type); } if (logger.isDebugEnabled()) { logger.debug("getOclType() - exit - return value=" + type); //$NON-NLS-1$ } return type; } // helper method to convert a primitive type into the corresponding OCL type private Type mapPrimitiveType(PrimitiveType type) { if (logger.isDebugEnabled()) { logger.debug("mapPrimitiveType(type=" + type + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } Type mappedType; switch (type.getKind()) { case BOOLEAN: mappedType = oclLibrary.getOclBoolean(); break; case INTEGER: mappedType = oclLibrary.getOclInteger(); break; case REAL: mappedType = oclLibrary.getOclReal(); break; case STRING: mappedType = oclLibrary.getOclString(); break; case UNKNOWN: mappedType = ensureDescendanceFromOclAny(type); break; default: logger.warn("Unknown kind of primitive type: " + type); //$NON-NLS-1$ mappedType = type; } if (logger.isDebugEnabled()) { logger.debug("mapPrimitiveType() - exit - return value=" + mappedType); //$NON-NLS-1$ } return mappedType; } /** * Helper method that will add OclAny to the super types of the given type if * * <ul> * <li>the type is not <code>OclAny</code> itself * <li>the type does not already contain <code>OclAny</code> in its list of * supertypes * <li>the type does not have any other supertypes from which it could inherit * the descendance from <code>OclAny</code> * </ul> * * * @param type * @return */ private Type ensureDescendanceFromOclAny(Type type) { AnyType oclAny = oclLibrary.getOclAny(); if (!type.equals(oclAny) && !type.getSuperType().contains(oclAny)) { /* Only add OclAny to types without super type. */ if (type.getSuperType().size() == 0) { type.addSuperType(oclAny); } else { for (Type superType : type.getSuperType()) { this.ensureDescendanceFromOclAny(superType); } // end for. } } return type; } /** * Helper method for subclasses that returns the reference to the * {@link OclLibrary} if it has been set, otherwise throws an * {@link IllegalStateException}. */ protected OclLibrary getValidOclLibrary() { if (oclLibrary == null) { throw new IllegalStateException( "The reference to the OCL Library has not been initialized."); //$NON-NLS-1$ } return oclLibrary; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case ExpressionsPackageImpl.OCL_EXPRESSION__OCL_LIBRARY: return getOclLibrary(); } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public void eSet(int featureID, Object newValue) { switch (featureID) { case ExpressionsPackageImpl.OCL_EXPRESSION__OCL_LIBRARY: setOclLibrary((OclLibrary) newValue); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public void eUnset(int featureID) { switch (featureID) { case ExpressionsPackageImpl.OCL_EXPRESSION__OCL_LIBRARY: setOclLibrary((OclLibrary) null); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public boolean eIsSet(int featureID) { switch (featureID) { case ExpressionsPackageImpl.OCL_EXPRESSION__OCL_LIBRARY: return oclLibrary != null; } return super.eIsSet(featureID); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override protected EClass eStaticClass() { return ExpressionsPackageImpl.Literals.OCL_EXPRESSION; } } // OclExpressionImpl