/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2007 * Ronny Brandt (Ronny_Brandt@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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package org.dresdenocl.standardlibrary.java.internal.library; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.dresdenocl.essentialocl.EssentialOclPlugin; import org.dresdenocl.essentialocl.standardlibrary.OclAny; import org.dresdenocl.essentialocl.standardlibrary.OclBoolean; import org.dresdenocl.essentialocl.standardlibrary.OclModelInstanceObject; import org.dresdenocl.essentialocl.standardlibrary.OclSet; import org.dresdenocl.modelinstancetype.exception.OperationAccessException; import org.dresdenocl.modelinstancetype.exception.OperationNotFoundException; import org.dresdenocl.modelinstancetype.exception.PropertyAccessException; import org.dresdenocl.modelinstancetype.exception.PropertyNotFoundException; import org.dresdenocl.modelinstancetype.types.IModelInstanceElement; import org.dresdenocl.modelinstancetype.types.IModelInstanceObject; import org.dresdenocl.pivotmodel.Operation; import org.dresdenocl.pivotmodel.Property; import org.dresdenocl.pivotmodel.Type; import org.dresdenocl.standardlibrary.java.factory.JavaStandardLibraryFactory; /** * <p> * This class implements the OCL type {@link OclModelInstanceObject} in Java. * </p> * * @author Ronny Brandt * @author Michael Thiele */ public class JavaOclModelInstanceObject extends JavaOclAny implements OclModelInstanceObject, IAddableElement { protected Type metaType; /** * <p> * Instantiates a new {@link JavaOclObject}. * </p> * * @param adaptee The adapted model instance object. */ public JavaOclModelInstanceObject(IModelInstanceObject imiObject, Type metaType) { super(imiObject); this.metaType = metaType; } public JavaOclModelInstanceObject(String undefinedReason, Type metaType) { super(undefinedReason); this.metaType = metaType; } public JavaOclModelInstanceObject(Throwable invalidReason, Type metaType) { super(invalidReason); this.metaType = metaType; } /* * (non-Javadoc) * * @see org.dresdenocl.standardlibrary.java.internal.library.IAddableElement * #add(org.dresdenocl.essentialocl.standardlibrary.OclAny) */ @Override public OclAny add(OclAny that) { /* * convention: any ModelInstanceElement that has an operation called "+", "add" or "plus" is * considered to be addable. Else return invalid. */ OclAny result; result = checkInvalid(metaType, this, that); if (result == null) result = checkUndefined("+", metaType, this, that); if (result == null) { if (that.getModelInstanceElement().isKindOf(metaType)) { result = findMethod("+", that); if (result == null) result = findMethod("add", that); if (result == null) result = findMethod("plus", that); if (result == null) // not found any matching method -> invalid result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(metaType, new NoSuchMethodException("Cannot find operation +, add or plus on " + this)); } } return result; } /* * (non-Javadoc) * * @see org.dresdenocl.essentialocl.standardlibrary.OclAny#asSet() */ @Override @SuppressWarnings("unchecked") public OclSet<OclModelInstanceObject> asSet() { OclSet<OclModelInstanceObject> result; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getSetType(metaType), this); if (result == null) result = checkAsSet(metaType); if (result == null) { Set<IModelInstanceElement> resultSet = new HashSet<IModelInstanceElement>(); resultSet.add(this.getModelInstanceObject()); result = JavaStandardLibraryFactory.INSTANCE.createOclSet(resultSet, EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getSetType(metaType)); } return result; } /* * (non-Javadoc) * * @see org.dresdenocl.essentialocl.standardlibrary.OclModelInstanceObject * #getModelInstanceObject() */ @Override public IModelInstanceObject getModelInstanceObject() { return (IModelInstanceObject) this.imiElement; } /* * (non-Javadoc) * * @see org.dresdenocl.standardlibrary.java.internal.library.IAddableElement #getNeutralElement() */ @Override public OclAny getNeutralElement() { // FIXME Michael: how to get an instance of an unknown neutral element? return null; } /** * <p> * Returns the {@link OclAny} of a given {@link Property} that is defined on this * {@link IModelInstanceObject}. * </p> * * @param property The {@link Property} whose value shall be returned. * @return The result as an {@link OclAny}. */ @Override public OclAny getProperty(Property property) { OclAny result; /* Check if the source is invalid. */ if (this.oclIsInvalid().isTrue()) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(property.getType(), this.getInvalidReason()); } else if (this.oclIsUndefined().isTrue()) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(property.getType(), new NullPointerException(this.getUndefinedReason())); } /* Else try to get the property. */ else { IModelInstanceElement imiResult; try { imiResult = getModelInstanceObject().getProperty(property); if (imiResult.isUndefined()) { result = JavaStandardLibraryFactory.INSTANCE.createOclUndefined(property.getType(), imiResult.getName() + " is null."); } else { result = JavaStandardLibraryFactory.INSTANCE.createOclAny(imiResult); } } /* Probably create an undefined or invalid result. */ catch (PropertyNotFoundException e) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(property.getType(), e); } catch (PropertyAccessException e) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(property.getType(), e); } // end catch. } // end else. return result; } /* * (non-Javadoc) * * @see org.dresdenocl.essentialocl.standardlibrary.OclAny#isEqualTo(tudresden * .ocl20.pivot.essentialocl.standardlibrary.OclAny) */ @Override public OclBoolean isEqualTo(OclAny that) { OclBoolean result; result = checkIsEqualTo(that); if (result == null) { if (!(that instanceof OclModelInstanceObject)) { result = JavaOclBoolean.getInstance(false); } else { Object thatObject = ((IModelInstanceObject) that.getModelInstanceElement()).getObject(); if (getModelInstanceObject().getObject().equals(thatObject)) { result = JavaOclBoolean.getInstance(true); } else { result = JavaOclBoolean.getInstance(false); } } } return result; } /* * (non-Javadoc) * * @see org.dresdenocl.standardlibrary.java.internal.library.JavaOclAny# * invokeOperation(org.dresdenocl.pivotmodel.Operation, * org.dresdenocl.essentialocl.standardlibrary.OclAny[]) */ @Override public OclAny invokeOperation(Operation operation, OclAny... args) { OclAny result = null; final String operationName = operation.getName(); /* * Handle oclIsTypeOf(), oclIsKindOf() and oclAsType() separately as the argument has no * IMIElement. */ if ((operationName.equals("oclIsTypeOf") || operationName.equals("oclIsKindOf") || operationName .equals("oclAsType")) && args.length == 1) { result = super.invokeOperation(operation, args); } /* * Handle oclIsInvalid() and oclIsUndefined separately as they cannot be invoked on IMIElements * and are definitely defined in the Standard Library. */ if (result == null && (operationName.equals("oclIsUndefined") || operationName.equals("oclIsInvalid")) && args.length == 0) result = super.invokeOperation(operation, args); if (result == null && (operationName.equals("asSet") && args.length == 0)) result = this.asSet(); if (result == null) result = checkInvalid(operation, args); if (result == null) { /* Else try to invoke the operation. */ IModelInstanceElement imiResult; List<IModelInstanceElement> imiArguments; imiArguments = new LinkedList<IModelInstanceElement>(); /* Try to invoke the operation. */ try { /* Get the model instance arguments. */ for (OclAny arg : args) { imiArguments.add(arg.getModelInstanceElement()); } imiResult = getModelInstanceObject().invokeOperation(operation, imiArguments); result = JavaStandardLibraryFactory.INSTANCE.createOclAny(imiResult); } /* * If the operation is not defined on the model element, it may be an operation on OclAny. */ catch (OperationNotFoundException e) { result = super.invokeOperation(operation, args); } catch (OperationAccessException e) { result = super.invokeOperation(operation, args); } // end catch. } // no else. return result; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(this.getClass().getSimpleName()); result.append("["); if (!toStringUndefinedOrInvalid(result)) { result.append(getModelInstanceObject().toString()); } result.append("]"); return result.toString(); } /** * Used to determine invalid return values for {@link Operation}s. <code>this</code> is checked to * be <code>undefined</code> or <code>invalid</code> and the arguments are checked for * <code>invalid</code> . * * @param operation the operation to call * @param args the arguments of the operation * @return <code>null</code> if neither the source nor the args are undefined or invalid, the * undefined or invalid source else */ protected OclAny checkInvalid(Operation operation, OclAny... args) { OclAny result = null; /* * see standard, p. 138: all operations on OclInvalid are illegal, except oclIsInvalid(); * oclIsUndefined() is not considered to catch invalid -> this is not conform to the standard! */ if (this.oclIsInvalid().isTrue() && !(operation.getName().equals("oclIsInvalid") && args.length == 0) && !(operation.getName().equals("isEqualTo") && args.length == 1)) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(operation.getType(), this.getInvalidReason()); } /* * see standard, p. 138: all operations on OclVoid are illegal, except oclIsInvalid() and * oclIsUndefined() */ else if (this.oclIsUndefined().isTrue() && !(operation.getName().equals("oclIsInvalid") && args.length == 0) && !(operation.getName().equals("oclIsUndefined") && args.length == 0) && !(operation.getName().equals("isEqualTo") && args.length == 1)) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(operation.getType(), new RuntimeException("Tried to invoke operation " + operation.getName() + " on null. Reason: " + this.getUndefinedReason())); } if (result == null) { /* The same for all the arguments */ for (OclAny arg : args) { if (arg.oclIsInvalid().isTrue()) { result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(operation.getType(), arg.getInvalidReason()); break; } } } return result; } @SuppressWarnings("unchecked") private OclAny findMethod(String methodName, OclAny that) { OclAny result = null; try { findMethod(methodName, this.getClass(), that.getClass()); /* * if no exception has been thrown, search for the operation in the PivotModel */ Operation operation = null; List<Type> argTypes; argTypes = new ArrayList<Type>(); argTypes.add(that.getModelInstanceElement().getType()); operation = this.imiElement.getType().lookupOperation(methodName, argTypes); if (operation != null) result = super.invokeOperation(operation, that); else result = JavaStandardLibraryFactory.INSTANCE.createOclInvalid(metaType, new NoSuchMethodException("Cannot find " + methodName + " on " + this)); } catch (NoSuchMethodException e) { // ignore } return result; } }