/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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.factory; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.naming.TimeLimitExceededException; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.NullArgumentException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dresdenocl.essentialocl.EssentialOclPlugin; import org.dresdenocl.essentialocl.expressions.BooleanLiteralExp; import org.dresdenocl.essentialocl.expressions.CollectionItem; import org.dresdenocl.essentialocl.expressions.CollectionKind; import org.dresdenocl.essentialocl.expressions.CollectionLiteralExp; import org.dresdenocl.essentialocl.expressions.CollectionLiteralPart; import org.dresdenocl.essentialocl.expressions.CollectionRange; import org.dresdenocl.essentialocl.expressions.EnumLiteralExp; import org.dresdenocl.essentialocl.expressions.ExpressionInOcl; import org.dresdenocl.essentialocl.expressions.ExpressionsFactory; import org.dresdenocl.essentialocl.expressions.IfExp; import org.dresdenocl.essentialocl.expressions.IntegerLiteralExp; import org.dresdenocl.essentialocl.expressions.InvalidLiteralExp; import org.dresdenocl.essentialocl.expressions.IterateExp; import org.dresdenocl.essentialocl.expressions.IteratorExp; import org.dresdenocl.essentialocl.expressions.LetExp; import org.dresdenocl.essentialocl.expressions.OclExpression; import org.dresdenocl.essentialocl.expressions.OperationCallExp; import org.dresdenocl.essentialocl.expressions.PropertyCallExp; import org.dresdenocl.essentialocl.expressions.RealLiteralExp; import org.dresdenocl.essentialocl.expressions.StringLiteralExp; import org.dresdenocl.essentialocl.expressions.TupleLiteralExp; import org.dresdenocl.essentialocl.expressions.TupleLiteralPart; import org.dresdenocl.essentialocl.expressions.TypeLiteralExp; import org.dresdenocl.essentialocl.expressions.UndefinedLiteralExp; import org.dresdenocl.essentialocl.expressions.UnlimitedNaturalExp; import org.dresdenocl.essentialocl.expressions.Variable; import org.dresdenocl.essentialocl.expressions.VariableExp; import org.dresdenocl.essentialocl.expressions.WellformednessException; import org.dresdenocl.essentialocl.types.OclLibrary; import org.dresdenocl.essentialocl.types.util.TypeResolver; import org.dresdenocl.model.IModel; import org.dresdenocl.model.ModelAccessException; import org.dresdenocl.model.TypeNotFoundException; import org.dresdenocl.pivotmodel.ConstrainableElement; import org.dresdenocl.pivotmodel.Constraint; import org.dresdenocl.pivotmodel.ConstraintKind; import org.dresdenocl.pivotmodel.Enumeration; import org.dresdenocl.pivotmodel.EnumerationLiteral; import org.dresdenocl.pivotmodel.Expression; import org.dresdenocl.pivotmodel.Feature; import org.dresdenocl.pivotmodel.Operation; import org.dresdenocl.pivotmodel.Parameter; import org.dresdenocl.pivotmodel.PivotModelFactory; import org.dresdenocl.pivotmodel.Property; import org.dresdenocl.pivotmodel.Type; /** * Standard implementation of the {@link EssentialOclFactory} interface which * relies on a given {@link IModel} instance to find types in the model. * * @author Matthias Braeuer * @version 1.0 10.04.2007 */ public class EssentialOclFactory { /** The {@link Logger} for this class. */ private static final Logger LOGGER = EssentialOclPlugin .getLogger(EssentialOclFactory.class); /** The {@link OclLibrary} instance. */ private OclLibrary oclLibrary; /** The {@link ITypeResolver} used for looking up types. */ private TypeResolver typeResolver; /** The {@link IModel} the created OCL expressions belong to. */ private IModel model; /** * <p> * Creates a new {@link EssentialOclFactory}. * </p> * * @param oclLibrary * The {@link OclLibrary} this {@link EssentialOclFactory} belongs * to. * @param model * the {@link IModel} the created OCL expressions belong to. */ public EssentialOclFactory(OclLibrary oclLibrary, IModel model) { if (LOGGER.isDebugEnabled()) { LOGGER .debug("EssentialOclFactory(oclLibrary=" + oclLibrary + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } // no else. if (oclLibrary == null) { throw new IllegalArgumentException( "Paramter 'oclLibrary' must not be null."); //$NON-NLS-1$ } // no else. if (model == null) { throw new IllegalArgumentException("Paramter 'model' must not be null."); //$NON-NLS-1$ } // no else. /* initialize the reference to the model. */ this.model = model; this.oclLibrary = oclLibrary; if (LOGGER.isDebugEnabled()) { LOGGER.debug("OclLibrary() - exit"); //$NON-NLS-1$ } // no else. } /** * <p> * Creates a {@link BooleanLiteralExp}. * </p> * * @param booleanSymbol * The <code>boolean</code> value of the {@link BooleanLiteralExp}. * @return A {@link BooleanLiteralExp} instance. */ public BooleanLiteralExp createBooleanLiteralExp(boolean booleanSymbol) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createBooleanLiteralExp(booleanSymbol=" + booleanSymbol //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } BooleanLiteralExp booleanLiteralExp; booleanLiteralExp = ExpressionsFactory.INSTANCE.createBooleanLiteralExp(); booleanLiteralExp.setBooleanSymbol(booleanSymbol); booleanLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createBooleanLiteralExp() - exit - return value=" //$NON-NLS-1$ + booleanLiteralExp); } return booleanLiteralExp; } /** * <p> * Creates a {@link CollectionItem}. * </p> * * @param item * The {@link OclExpression} of the item. * @return A {@link CollectionItem} instance. */ public CollectionItem createCollectionItem(OclExpression item) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createCollectionItem(item=" + item + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } if (item == null) { throw new IllegalArgumentException( "The parameter 'item' must not be null."); //$NON-NLS-1$ } CollectionItem collectionItem; collectionItem = ExpressionsFactory.INSTANCE.createCollectionItem(); collectionItem.setItem(item); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createCollectionItem() - exit - return value=" //$NON-NLS-1$ + collectionItem); } return collectionItem; } /** * <p> * Creates a {@link CollectionLiteralExp}. * </p> * * @param kind * The {@link CollectionKind} of the {@link CollectionLiteralExp} . * @param parts * The {@link CollectionLiteralPart}s of the * {@link CollectionLiteralExp}. * @return A {@link CollectionLiteralExp} instance. */ public CollectionLiteralExp createCollectionLiteralExp(CollectionKind kind, Type elementType, CollectionLiteralPart... parts) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createCollectionLiteralExp(kind=" + kind + ", parts=" //$NON-NLS-1$ //$NON-NLS-2$ + ArrayUtils.toString(parts) + ") - enter"); //$NON-NLS-1$ } // check parameters if (kind == null || parts == null) { throw new IllegalArgumentException( "Parameters must not be null: kind=" + kind + ", parts=" + parts + "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } CollectionLiteralExp collectionLiteralExp; collectionLiteralExp = ExpressionsFactory.INSTANCE.createCollectionLiteralExp(); collectionLiteralExp.setKind(kind); collectionLiteralExp.setElementType(elementType); collectionLiteralExp.getPart().addAll(Arrays.asList(parts)); // set the reference to the OCL Library collectionLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createCollectionLiteralExp() - exit - return value=" //$NON-NLS-1$ + collectionLiteralExp); } return collectionLiteralExp; } /** * <p> * Creates a {@link CollectionRange}. * </p> * * @param first * The {@link OclExpression} for the first element. * @param last * The {@link OclExpression} for the last element. * @return A {@link CollectionRange} instance. */ public CollectionRange createCollectionRange(OclExpression first, OclExpression last) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createCollectionRange(first=" + first + ", last=" + last //$NON-NLS-1$ //$NON-NLS-2$ + ") - enter"); //$NON-NLS-1$ } if (first == null || last == null) { throw new NullArgumentException("first or last"); //$NON-NLS-1$ } CollectionRange collectionRange; collectionRange = ExpressionsFactory.INSTANCE.createCollectionRange(); collectionRange.setFirst(first); collectionRange.setLast(last); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createCollectionRange() - exit - return value=" //$NON-NLS-1$ + collectionRange); } return collectionRange; } /** * <p> * Creates a new {@link Constraint}. The name is optional. but the other * parameters need to have valid values. * </p> * * @param name * An optional name for the {@link Constraint}. * @param kind * One of the constants defined in {@link ConstraintKind}. * @param specification * The {@link Expression} that specifies the {@link Constraint}. * @param constrainedElement * At least one element that is the target of the {@link Constraint}. * * @return A {@link Constraint} instance. */ public Constraint createConstraint(String name, ConstraintKind kind, Expression specification, Feature definedFeature, ConstrainableElement... constrainedElement) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createConstraint(name=" + name + ", kind=" + kind //$NON-NLS-1$ //$NON-NLS-2$ + ", specification=" + specification + ", constrainedElement=" //$NON-NLS-1$//$NON-NLS-2$ + ArrayUtils.toString(constrainedElement) + ") - enter"); //$NON-NLS-1$ } if (kind == null || specification == null || constrainedElement == null) { throw new NullArgumentException( "kind or specification or constrainedElement"); //$NON-NLS-1$ } Constraint constraint = PivotModelFactory.eINSTANCE.createConstraint(); constraint.setName(name); constraint.setKind(kind); constraint.setSpecification(specification); constraint.setDefinedFeature(definedFeature); constraint.getConstrainedElement() .addAll(Arrays.asList(constrainedElement)); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createConstraint() - exit - return value=" + constraint); //$NON-NLS-1$ } return constraint; } /** * <p> * Creates a {@link EnumLiteralExp}. * </p> * * @param referredEnumLiteralPathName * The fully qualified name of the referred * {@link EnumerationLiteral} as a {@link String}. * @return A {@link EnumLiteralExp} instance. * @throws EssentialOclFactoryException * Thrown, if the creation fails. */ public EnumLiteralExp createEnumLiteralExp(List<String> pathName) throws EssentialOclFactoryException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createEnumLiteralExp(pathName=" + pathName + ") - enter"); //$NON-NLS-1$//$NON-NLS-2$ } if (pathName == null || pathName.size() < 2) { throw new IllegalArgumentException( "The path name '" + pathName //$NON-NLS-1$ + "' is either null or does not have the minimal number of two segments."); //$NON-NLS-1$ } // separate the enumeration name and the literal name String enumLiteralName = pathName.get(pathName.size() - 1); pathName = pathName.subList(0, pathName.size() - 1); // find the enumeration Type enumeration = findType(pathName); // check that we found an enumeration if (!(enumeration instanceof Enumeration)) { throw new IllegalArgumentException("The path name " + pathName //$NON-NLS-1$ + " does not denote an enumeration."); //$NON-NLS-1$ } EnumerationLiteral enumLiteral = ((Enumeration) enumeration).lookupLiteral(enumLiteralName); if (enumLiteral == null) { throw new IllegalArgumentException( "There is no literal with name '" + enumLiteralName //$NON-NLS-1$ + "' in enumeration '" + enumeration.getQualifiedName() + "'."); //$NON-NLS-1$ //$NON-NLS-2$ } EnumLiteralExp enumLiteralExp; enumLiteralExp = ExpressionsFactory.INSTANCE.createEnumLiteralExp(); enumLiteralExp.setReferredEnumLiteral(enumLiteral); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createEnumLiteralExp() - exit - return value=" //$NON-NLS-1$ + enumLiteralExp); } return enumLiteralExp; } /** * <p> * Creates a new {@link ExpressionInOcl}. The body expression and the context * variable must not be <code>null</code>. The result and parameter variables * are optional since they are only required for constraints whose context is * an operation. * </p> * * @param body * The body expression as a {@link String} in OCL concrete syntax. * @param bodyExpression * The {@link OclExpression} that is the body of the * {@link ExpressionInOcl}. * @param context * The {@link Variable} representing the contextual classifier. * @param result * The result {@link Variable} of an operation {@link Constraint} . * @param parameter * The parameters of an operation {@link Constraint}. * * @return An {@link ExpressionInOcl} instance. */ public ExpressionInOcl createExpressionInOcl(String body, OclExpression bodyExpression, Variable context, Variable result, Variable... parameter) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createExpressionInOcl(bodyExpression=" + bodyExpression //$NON-NLS-1$ + ", context=" + context + ", result=" + result + ", parameter=" //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + ArrayUtils.toString(parameter) + ") - enter"); //$NON-NLS-1$ } if (bodyExpression == null || context == null) { throw new NullArgumentException("bodyExpression or context"); //$NON-NLS-1$ } ExpressionInOcl expressionInOcl; expressionInOcl = ExpressionsFactory.INSTANCE.createExpressionInOcl(); expressionInOcl.setBodyExpression(bodyExpression); expressionInOcl.setContext(context); if (StringUtils.isNotEmpty(body)) { expressionInOcl.setBody(body.replaceAll("\r\n|\r|\n", " ")); } if (result != null) { expressionInOcl.setResult(result); } if (parameter != null) { expressionInOcl.getParameter().addAll(Arrays.asList(parameter)); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("createExpressionInOcl() - exit - return value=" //$NON-NLS-1$ + expressionInOcl); } return expressionInOcl; } /** * <p> * Creates an {@link IfExp}. * </p> * * @param condition * The condition {@link OclExpression}. * @param thenExpression * The then {@link OclExpression}. * @param elseExpression * The else {@link OclExpression}. * @return An {@link IfExp} instance. */ public IfExp createIfExp(OclExpression condition, OclExpression thenExpression, OclExpression elseExpression) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIfExp(condition=" + condition + ", thenExpression=" //$NON-NLS-1$ //$NON-NLS-2$ + thenExpression + ", elseExpression=" + elseExpression //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } if (condition == null || thenExpression == null || elseExpression == null) { throw new NullArgumentException( "condition or thenExpression or elseExpression"); //$NON-NLS-1$ } IfExp ifExp = ExpressionsFactory.INSTANCE.createIfExp(); ifExp.setCondition(condition); ifExp.setThenExpression(thenExpression); ifExp.setElseExpression(elseExpression); ifExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIfExp() - exit - return value=" + ifExp); //$NON-NLS-1$ } return ifExp; } /** * <p> * Creates an {@link IntegerLiteralExp}. * </p> * * @param integerSymbol * The <code>int</code> value of the {@link IntegerLiteralExp}. * @return An {@link IntegerLiteralExp} instance. */ public IntegerLiteralExp createIntegerLiteralExp(int integerSymbol) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIntegerLiteralExp(integerSymbol=" + integerSymbol //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } IntegerLiteralExp integerLiteralExp = ExpressionsFactory.INSTANCE.createIntegerLiteralExp(); integerLiteralExp.setIntegerSymbol(integerSymbol); // initialize reference to the OCL Library integerLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIntegerLiteralExp() - exit - return value=" //$NON-NLS-1$ + integerLiteralExp); } return integerLiteralExp; } /** * <p> * Creates an {@link InvalidLiteralExp}. * </p> * * @return The {@link InvalidLiteralExp} instance. */ public InvalidLiteralExp createInvalidLiteralExp() { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createInvalidLiteralExp() - enter"); //$NON-NLS-1$ } InvalidLiteralExp invalidLiteralExp = ExpressionsFactory.INSTANCE.createInvalidLiteralExp(); invalidLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createInvalidLiteralExp() - exit - return value=" //$NON-NLS-1$ + invalidLiteralExp); } return invalidLiteralExp; } /** * <p> * Creates a new {@link IterateExp}. * </p> * * @param source * The source {@link OclExpression}. * @param name * The name of the {@link IterateExp}. * @param body * The body {@link OclExpression} of the {@link IterateExp}. * @param result * The result {@link Variable}. * @param iterator * The optional iterator {@link Variable}s as an array. * @return The {@link IterateExp} instance. */ public IterateExp createIterateExp(OclExpression source, OclExpression body, Variable result, Variable... iterator) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIterateExp(source=" + source + ", body=" + body //$NON-NLS-1$ //$NON-NLS-2$ + ", result=" + result + ", iterator=" //$NON-NLS-1$//$NON-NLS-2$ + ArrayUtils.toString(iterator) + ") - enter"); //$NON-NLS-1$ } if (source == null || body == null || result == null) { throw new NullArgumentException("source or body or result"); //$NON-NLS-1$ } IterateExp iterateExp = ExpressionsFactory.INSTANCE.createIterateExp(); iterateExp.setSource(source); iterateExp.setBody(body); iterateExp.setResult(result); if (iterator != null) { iterateExp.getIterator().addAll(Arrays.asList(iterator)); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIterateExp() - exit - return value=" + iterateExp); //$NON-NLS-1$ } return iterateExp; } /** * <p> * Creates a new {@link IteratorExp}. * </p> * * @param source * The source {@link OclExpression}. * @param name * The name of the {@link IteratorExp}. * @param body * The body {@link OclExpression}. * @param iterator * The iterator {@link Variable}s as an array. * * @return A {@link IteratorExp} instance. */ public IteratorExp createIteratorExp(OclExpression source, String name, OclExpression body, Variable... iterator) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIteratorExp(source=" + source + ", name=" + name //$NON-NLS-1$ //$NON-NLS-2$ + ", body=" + body + ", iterator=" + ArrayUtils.toString(iterator) //$NON-NLS-1$//$NON-NLS-2$ + ") - enter"); //$NON-NLS-1$ } if (source == null || StringUtils.isEmpty(name) || body == null) { throw new IllegalArgumentException( "Parameters must not be null or empty: source=" + source //$NON-NLS-1$ + ", name=" + name + ", body=" + body + "."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ } IteratorExp iteratorExp = ExpressionsFactory.INSTANCE.createIteratorExp(); iteratorExp.setSource(source); iteratorExp.setName(name); iteratorExp.setBody(body); if (iterator != null) { iteratorExp.getIterator().addAll(Arrays.asList(iterator)); } // set the reference to the OCL library iteratorExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createIteratorExp() - exit - return value=" + iteratorExp); //$NON-NLS-1$ } return iteratorExp; } /** * <p> * Creates a {@link LetExp} instance. * </p> * * @param variable * The {@link Variable} of the {@link LetExp}. * @param in * The {@link OclExpression} of the {@link LetExp}. * @return A {@link LetExp} instance. */ public LetExp createLetExp(Variable variable, OclExpression in) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createLetExp(variable=" + variable + ", in=" + in //$NON-NLS-1$ //$NON-NLS-2$ + ") - enter"); //$NON-NLS-1$ } if (variable == null || in == null) { throw new IllegalArgumentException( "Parameters must not be null: variable=" + variable //$NON-NLS-1$ + ", in=" + in + "."); //$NON-NLS-1$//$NON-NLS-2$ } LetExp letExp = ExpressionsFactory.INSTANCE.createLetExp(); letExp.setVariable(variable); letExp.setIn(in); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createLetExp() - exit - return value=" + letExp); //$NON-NLS-1$ } return letExp; } /** * <p> * Creates a new {@link OperationCallExp}. * </p> * * @param source * The source {@link OclExpression} of the {@link OperationCallExp}. * @param referredOperationName * The fully qualified name of the operation (i.e., including the * fully qualified name of its owning {@link Type}). * @param argument * An optional list of arguments as {@link OclExpression}s. * * @return The created {@link OperationCallExp}. */ public OperationCallExp createOperationCallExp(OclExpression source, String referredOperationName, OclExpression... argument) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createOperationCallExp(source=" + source //$NON-NLS-1$ + ", referredOperationName=" + referredOperationName + ", argument=" //$NON-NLS-1$ //$NON-NLS-2$ + ArrayUtils.toString(argument) + ") - enter"); //$NON-NLS-1$ } if (source == null || StringUtils.isEmpty(referredOperationName)) { throw new IllegalArgumentException( "Parameters must not be null or empty: source=" + source //$NON-NLS-1$ + ", referredOperationName=" + referredOperationName + ","); //$NON-NLS-1$ //$NON-NLS-2$ } // collect the parameter types List<Type> paramTypes = new ArrayList<Type>(); if (argument != null) { for (int i = 0; i < argument.length; i++) { paramTypes.add(argument[i].getType()); } } // lookup the operation Type sourceType = source.getType(); Operation operation = sourceType.lookupOperation(referredOperationName, paramTypes); if (operation == null) { StringBuilder paramTypeNames = new StringBuilder(); if (paramTypes.size() == 0) paramTypeNames.append(" with no argument"); if (paramTypes.size() == 1) paramTypeNames.append(" with argument type "); if (paramTypes.size() > 1) paramTypeNames.append(" with argument types "); for (int i = 0; i < paramTypes.size(); i++) { Type paramType = paramTypes.get(i); if (i > 0) paramTypeNames.append(", "); paramTypeNames.append("'"); paramTypeNames.append(paramType.getName()); paramTypeNames.append("'"); } throw new IllegalArgumentException( "Unable to find operation '" + referredOperationName //$NON-NLS-1$ + "'" + paramTypeNames + " in type '" //$NON-NLS-1$ //$NON-NLS-2$ + source.getType().getQualifiedName() + "'."); //$NON-NLS-1$ } OperationCallExp operationCallExp = ExpressionsFactory.INSTANCE.createOperationCallExp(); operationCallExp.setSource(source); operationCallExp.setReferredOperation(operation); if (argument != null) { operationCallExp.getArgument().addAll(Arrays.asList(argument)); } // a property call expression needs access to the OCL library operationCallExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER .debug("createOperationCallExp() - exit - return value=" + operationCallExp); //$NON-NLS-1$ } return operationCallExp; } /** * <p> * Creates a new {@link OperationCallExp} for a static operation. The * <code>referredOperationPathName</code> must not be <code>null</code>, the * arguments are optional. The owning type must exist in the associated * {@link IModel model} and the specified operation must be static. * </p> * * @param referredOperationPathName * The fully qualified name of the operation (i.e., including the * fully qualified name of its owning {@link Type}). * @param argument * An optional list of arguments as {@link OclExpression}s. * * @return An {@link OperationCallExp} instance. * * @throws EssentialOclFactoryException * If the expression cannot be created. */ public OperationCallExp createOperationCallExp(List<String> pathName, OclExpression... argument) throws EssentialOclFactoryException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createOperationCallExp(pathName=" + pathName //$NON-NLS-1$ + ", argument=" + ArrayUtils.toString(argument) + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } if (pathName == null || pathName.size() < 2) { throw new IllegalArgumentException( "The static operation path name '" + pathName //$NON-NLS-1$ + "' is either null or does not have the required number of at least two segments."); //$NON-NLS-1$ } // split the pathname into the type and operation part String referredOperation = pathName.get(pathName.size() - 1); pathName = pathName.subList(0, pathName.size() - 1); // collect the parameter types List<Type> paramTypes = new ArrayList<Type>(); if (argument != null) { for (int i = 0; i < argument.length; i++) { paramTypes.add(argument[i].getType()); } } // lookup the type Type owningType = findType(pathName); // FIXME Michael: This is wrong, but the parser treats this as a static // operation. A new parser should avoid this, so this code can move to // another place (non-static operation) // lookup the operation on OclType first (allInstances, probably more) Operation operation = oclLibrary.getOclType().lookupOperation(referredOperation, paramTypes); if (operation == null) { operation = owningType.lookupOperation(referredOperation, paramTypes); if (operation == null || !operation.isStatic()) { throw new IllegalArgumentException( "Unable to find a static operation '" + referredOperation //$NON-NLS-1$ + "' with argument types " + paramTypes + "' in type " //$NON-NLS-1$ //$NON-NLS-2$ + owningType.getQualifiedName() + "."); //$NON-NLS-1$ } } // no else. // create the expression OperationCallExp operationCallExp = ExpressionsFactory.INSTANCE.createOperationCallExp(); operationCallExp.setSourceType(owningType); operationCallExp.setReferredOperation(operation); if (argument != null) { operationCallExp.getArgument().addAll(Arrays.asList(argument)); } // a property call expression needs access to the OCL library for // determining its type operationCallExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createOperationCallExp() - exit - return value=" //$NON-NLS-1$ + operationCallExp); } return operationCallExp; } /** * @author Lars Schuetze * @param source * The source {@link OclExpression} of the {@link PropertyCallExp}. * @param referredProperty * The referred {@link Property property} * @param qualifier * qualifier {@link OclExpression} as an Array. * @return A {@link PropertyCallExp} instance. * @throws EssentialOclFactoryException */ public PropertyCallExp createPropertyCallExp(OclExpression source, Property referredProperty, OclExpression... qualifier) throws EssentialOclFactoryException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createPropertyCallExp(source=" + source + ", refferedProperty=" + referredProperty + ", qualifier=" + ArrayUtils.toString(qualifier)); } if (source == null || referredProperty == null) { throw new IllegalArgumentException( "Parameters must not be null: source=" + source //$NON-NLS-1$ + ", referredProperty=" + referredProperty + "."); //$NON-NLS-1$//$NON-NLS-2$ } // create the expression PropertyCallExp propertyCallExp = ExpressionsFactory.INSTANCE.createPropertyCallExp(); propertyCallExp.setSource(source); propertyCallExp.setSourceType(referredProperty.getOwningType()); propertyCallExp.setReferredProperty(referredProperty); // a property call expression needs access to the OCL library propertyCallExp.setOclLibrary(oclLibrary); // set the qualifiers if existing if (qualifier != null) { propertyCallExp.getQualifier().addAll(Arrays.asList(qualifier)); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("createPropertyCallExp() - exit - return value=" //$NON-NLS-1$ + propertyCallExp); } return propertyCallExp; } /** * <p> * Creates a {@link PropertyCallExp}. * </p> * * @param source * The source {@link OclExpression} of the {@link PropertyCallExp}. * @param referredPropertyName * The referred property's name as a {@link String}. * @param qualifier * qualifier {@link OclExpression} as an Array. * * @return A {@link PropertyCallExp} instance. * @throws EssentialOclFactoryException */ public PropertyCallExp createPropertyCallExp(OclExpression source, String referredPropertyName, OclExpression... qualifier) throws EssentialOclFactoryException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createPropertyCallExp(source=" + source //$NON-NLS-1$ + ", referredPropertyName=" + referredPropertyName + ", qualifier=" //$NON-NLS-1$ //$NON-NLS-2$ + ArrayUtils.toString(qualifier) + ") - enter"); //$NON-NLS-1$ } if (source == null || StringUtils.isEmpty(referredPropertyName)) { throw new IllegalArgumentException( "Parameters must not be null or empty: source=" + source //$NON-NLS-1$ + ", referredPropertyName=" + referredPropertyName + "."); //$NON-NLS-1$//$NON-NLS-2$ } // lookup the property Type sourceType = source.getType(); Property property = sourceType.lookupProperty(referredPropertyName); // invalid and undefined conform to all types, so we ignore if we // haven't found a property if (property == null) { throw new EssentialOclFactoryException( "Unable to find property '" + referredPropertyName //$NON-NLS-1$ + "' in type '" + source.getType().getQualifiedName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$ } // create the expression PropertyCallExp propertyCallExp = ExpressionsFactory.INSTANCE.createPropertyCallExp(); propertyCallExp.setSource(source); propertyCallExp.setSourceType(sourceType); propertyCallExp.setReferredProperty(property); // a property call expression needs access to the OCL library propertyCallExp.setOclLibrary(oclLibrary); // set the qualifiers if existing if (qualifier != null) { propertyCallExp.getQualifier().addAll(Arrays.asList(qualifier)); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("createPropertyCallExp() - exit - return value=" //$NON-NLS-1$ + propertyCallExp); } return propertyCallExp; } /** * <p> * Creates a {@link PropertyCallExp}. * </p> * * @param referredPropertyPathName * The referred property's name as a {@link String}. * @param qualifier * qualifier {@link OclExpression} as an Array. * @return A {@link PropertyCallExp} instance. * @throws EssentialOclFactoryException * Thrown, if the creation fails. */ public PropertyCallExp createPropertyCallExp(List<String> pathName, OclExpression... qualifier) throws EssentialOclFactoryException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createPropertyCallExp(pathName=" + pathName //$NON-NLS-1$ + ", qualifier=" + ArrayUtils.toString(qualifier) + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } if (pathName == null || pathName.size() < 2) { throw new IllegalArgumentException( "The static property path name '" + pathName //$NON-NLS-1$ + "' is either null or does not have the required number of at least two segments."); //$NON-NLS-1$ } // split the path name into the type name and the property name String referredProperty = pathName.get(pathName.size() - 1); pathName = pathName.subList(0, pathName.size() - 1); // lookup the type Type owningType = findType(pathName); // lookup the property Property property = owningType.lookupProperty(referredProperty); if (property == null || !property.isStatic()) { throw new IllegalArgumentException( "Unable to find a static property '" + referredProperty //$NON-NLS-1$ + "' in type " + owningType.getQualifiedName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ } // create the expression PropertyCallExp propertyCallExp = ExpressionsFactory.INSTANCE.createPropertyCallExp(); propertyCallExp.setSourceType(owningType); propertyCallExp.setReferredProperty(property); // add qualifiers if (qualifier != null) { propertyCallExp.getQualifier().addAll(Arrays.asList(qualifier)); } // set reference to OCL library propertyCallExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createPropertyCallExp() - exit - return value=" //$NON-NLS-1$ + propertyCallExp); } return propertyCallExp; } /** * <p> * Creates a {@link RealLiteralExp}. * </p> * * @param realSymbol * The <code>float</code> value of the {@link RealLiteralExp} .</p> * @return The {@link RealLiteralExp}. */ public RealLiteralExp createRealLiteralExp(float realSymbol) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createRealLiteralExp(realSymbol=" + realSymbol //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } RealLiteralExp realLiteralExp = ExpressionsFactory.INSTANCE.createRealLiteralExp(); realLiteralExp.setRealSymbol(realSymbol); realLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createRealLiteralExp() - exit - return value=" //$NON-NLS-1$ + realLiteralExp); } return realLiteralExp; } /** * <p> * Creates a {@link StringLiteralExp}. * </p> * * @param stringSymbol * The {@link String} value of the {@link StringLiteralExp}. * @return A {@link StringLiteralExp} instance. */ public StringLiteralExp createStringLiteralExp(String stringSymbol) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createStringLiteralExp(stringSymbol=" + stringSymbol //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } if (stringSymbol == null) { throw new IllegalArgumentException( "The argument 'stringSymbol' must not be null."); //$NON-NLS-1$ } StringLiteralExp stringLiteralExp; // create and initialize a new StringLiteralExp stringLiteralExp = ExpressionsFactory.INSTANCE.createStringLiteralExp(); stringLiteralExp.setStringSymbol(stringSymbol); stringLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createStringLiteralExp() - exit - return value=" //$NON-NLS-1$ + stringLiteralExp); } return stringLiteralExp; } /** * <p> * Creates a {@link TupleLiteralExp}. * </p> * * @param parts * The {@link TupleLiteralPart}s of the {@link TupleLiteralExp}. * @return A {@link TupleLiteralExp} instance. */ public TupleLiteralExp createTupleLiteralExp(TupleLiteralPart... parts) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createTupleLiteralExp(parts=" + ArrayUtils.toString(parts) //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } TupleLiteralExp tupleLiteralExp; // create new expression and add parts tupleLiteralExp = ExpressionsFactory.INSTANCE.createTupleLiteralExp(); if (parts != null) { tupleLiteralExp.getPart().addAll(Arrays.asList(parts)); } // set reference to OCL library tupleLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createTupleLiteralExp() - exit - return value=" //$NON-NLS-1$ + tupleLiteralExp); } return tupleLiteralExp; } /** * <p> * Creates a new {@link TupleLiteralPart} from a {@link Variable variable * declaration}. * </p> * * @param variableDeclaration * The variable declaration for which the tuple literal part should * be created * * @return A {@link TupleLiteralPart} instance. */ public TupleLiteralPart createTupleLiteralPart(Variable variableDeclaration) { if (variableDeclaration == null) { throw new NullArgumentException("variableDeclaration"); //$NON-NLS-1$ } TupleLiteralPart part; // create a new part part = ExpressionsFactory.INSTANCE.createTupleLiteralPart(); // set the property and the value of the part part.setProperty(variableDeclaration.asProperty()); part.setValue(variableDeclaration.getInitExpression()); return part; } /** * <p> * Creates a {@link TypeLiteralExp}. * </p> * * @param referredTypePathName * The fully qualified name of the {@link Type} this * {@link TimeLimitExceededException} refers to. * * @return A {@link TypeLiteralExp} instance. * @throws EssentialOclFactoryException * Thrown, if the creation fails. */ public TypeLiteralExp createTypeLiteralExp(List<String> referredTypeName) throws EssentialOclFactoryException { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createTypeLiteralExp(referredTypeName=" + referredTypeName //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } if (referredTypeName == null || referredTypeName.size() == 0) { throw new IllegalArgumentException( "The argument 'referredTypeName' must not be null or empty."); //$NON-NLS-1$ } Type type = findType(referredTypeName); TypeLiteralExp typeLiteralExp = ExpressionsFactory.INSTANCE.createTypeLiteralExp(); typeLiteralExp.setReferredType(type); // initialize reference to the OCL Library typeLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createTypeLiteralExp() - exit - return value=" //$NON-NLS-1$ + typeLiteralExp); } return typeLiteralExp; } /** * <p> * Creates an {@link UndefinedLiteralExp}. * </p> * * @return An {@link UndefinedLiteralExp} instance. */ public UndefinedLiteralExp createUndefinedLiteralExp() { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createUndefinedLiteralExp() - enter"); //$NON-NLS-1$ } UndefinedLiteralExp undefinedLiteralExp = ExpressionsFactory.INSTANCE.createUndefinedLiteralExp(); undefinedLiteralExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createUndefinedLiteralExp() - exit - return value=" //$NON-NLS-1$ + undefinedLiteralExp); } return undefinedLiteralExp; } /** * <p> * Creates an {@link UnlimitedNaturalExp}. * </p> * * @param symbol * The <code>long</code> value of the {@link UnlimitedNaturalExp} . * @return A {@link UnlimitedNaturalExp} instance. */ public UnlimitedNaturalExp createUnlimitedNaturalExp(long symbol) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createUnlimitedNaturalExp(symbol=" + symbol + ") - enter"); //$NON-NLS-1$ //$NON-NLS-2$ } UnlimitedNaturalExp unlimitedNaturalExp = ExpressionsFactory.INSTANCE.createUnlimitedNaturalExp(); unlimitedNaturalExp.setSymbol(symbol); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createUnlimitedNaturalExp() - exit - return value=" //$NON-NLS-1$ + unlimitedNaturalExp); } return unlimitedNaturalExp; } /** * <p> * Creates a new {@link Variable}. The name must not be <code>null</code>. * Type and init expression are optional (OCL Specification, Section 9.3). If * none is given, however, it is likely that a {@link WellformednessException} * will be thrown at a later time when the type is requested. If both a type * and an init expression are given, this method will not check whether the * type of the init expression conforms to the given type. Instead, this will * be checked by the {@link Variable} implementation once the type is accessed * for the first time. * </p> * * @param name * The name of the {@link Variable}. * @param type * The {@link Type} of the {@link Variable}. * @param initExpression * An (optional) initialization {@link OclExpression}. * * @return A {@link Variable} instance. */ public Variable createVariable(String name, Type type, OclExpression initExpression) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createVariable(name=" + name + ", type=" + type //$NON-NLS-1$ //$NON-NLS-2$ + ", initExpression=" + initExpression + ") - enter"); //$NON-NLS-1$//$NON-NLS-2$ } // precondition check if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException( "The 'name' argument must not be null or empty."); //$NON-NLS-1$ } // create the variable and initialize Variable variable = ExpressionsFactory.INSTANCE.createVariable(); variable.setName(name); if (type != null) { variable.setType(type); } if (initExpression != null) { variable.setInitExpression(initExpression); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("createVariable() - exit - return value=" + variable); //$NON-NLS-1$ } return variable; } /** * <p> * Creates a new {@link Variable} that represents a {@link Parameter} in an * expression that constrains an {@link Operation}. The name and type of the * {@link Variable} will be determined automatically. * </p> * * @param representedParameter * The {@link Parameter} represented by the {@link Variable}. * * @return A {@link Variable} instance. */ public Variable createVariable(Parameter representedParameter) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createVariable(representedParameter=" //$NON-NLS-1$ + representedParameter + ") - enter"); //$NON-NLS-1$ } if (representedParameter == null) { throw new IllegalArgumentException( "The represented parameter must not be null."); //$NON-NLS-1$ } Variable variable = ExpressionsFactory.INSTANCE.createVariable(); variable.setRepresentedParameter(representedParameter); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createVariable() - exit - return value=" + variable); //$NON-NLS-1$ } return variable; } /** * <p> * Creates a {@link VariableExp}. * </p> * * @param referredVariable * The referred {@link Variable}. * @return A {@link VariableExp} instance. */ public VariableExp createVariableExp(Variable referredVariable) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("createVariableExp(referredVariable=" + referredVariable //$NON-NLS-1$ + ") - enter"); //$NON-NLS-1$ } if (referredVariable == null) { throw new IllegalArgumentException( "The referred variable must not be null."); //$NON-NLS-1$ } VariableExp variableExp = ExpressionsFactory.INSTANCE.createVariableExp(); variableExp.setReferredVariable(referredVariable); // a variable expression needs access to the OCL library variableExp.setOclLibrary(oclLibrary); if (LOGGER.isDebugEnabled()) { LOGGER.debug("createVariableExp() - exit - return value=" + variableExp); //$NON-NLS-1$ } return variableExp; } /** * <p> * Helper method to look up a type using the associated type resolver. Handles * all possible checked exceptions by converting them into a factory * exception. * </p> */ public Type findType(List<String> pathName) throws EssentialOclFactoryException { Type type; if (typeResolver == null) { typeResolver = new TypeResolver(oclLibrary); } try { type = typeResolver.findType(pathName, model); } catch (TypeNotFoundException e) { LOGGER.error("findType(pathName=" + pathName + ")", e); //$NON-NLS-1$//$NON-NLS-2$ throw new EssentialOclFactoryException( "Failed to lookup type " + pathName //$NON-NLS-1$ + ", both in the OCL Standard Library and the associated model '" //$NON-NLS-1$ + model.getDisplayName() + "'.", e); //$NON-NLS-1$ } catch (ModelAccessException e) { LOGGER.error("findType(pathName=" + pathName + ")", e); //$NON-NLS-1$ //$NON-NLS-2$ throw new EssentialOclFactoryException( "An error occured when accessing model '" + model.getDisplayName() //$NON-NLS-1$ + "'.", e); //$NON-NLS-1$ } return type; } }