/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.dresdenocl.essentialocl.EssentialOclPlugin; import org.dresdenocl.essentialocl.standardlibrary.OclAny; import org.dresdenocl.essentialocl.standardlibrary.OclBag; import org.dresdenocl.essentialocl.standardlibrary.OclBoolean; import org.dresdenocl.essentialocl.standardlibrary.OclCollection; import org.dresdenocl.essentialocl.standardlibrary.OclComparable; import org.dresdenocl.essentialocl.standardlibrary.OclInteger; import org.dresdenocl.essentialocl.standardlibrary.OclIterator; import org.dresdenocl.essentialocl.standardlibrary.OclOrderedSet; import org.dresdenocl.essentialocl.standardlibrary.OclSequence; import org.dresdenocl.essentialocl.standardlibrary.OclSet; import org.dresdenocl.essentialocl.standardlibrary.OclTuple; import org.dresdenocl.essentialocl.types.OclLibrary; import org.dresdenocl.essentialocl.types.TupleType; import org.dresdenocl.modelinstancetype.types.IModelInstanceCollection; import org.dresdenocl.modelinstancetype.types.IModelInstanceElement; import org.dresdenocl.modelinstancetype.types.IModelInstanceInvalid; import org.dresdenocl.modelinstancetype.types.IModelInstanceString; import org.dresdenocl.modelinstancetype.types.base.BasisJavaModelInstanceFactory; import org.dresdenocl.pivotmodel.PivotModelFactory; 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 OclCollection} in Java. * </p> * * @author Ronny Brandt * @author Michael Thiele * @author Franz Eichhorn */ public abstract class JavaOclCollection<T extends OclAny> extends JavaOclLibraryObject implements OclCollection<T> { protected Type genericType; /** * <p> * Instantiates a new {@link JavaOclCollection}. * </p> * * @param imiCollection * The adapted element of this {@link JavaOclCollection}. */ public JavaOclCollection( IModelInstanceCollection<IModelInstanceElement> imiCollection, Type genericType) { /* * No check for undefined values here. See standard, page 194, A.2.5.4 * Constructors: "Note that constructors having element values as arguments * are deliberately defined not to be strict. A collection value therefore * may contain undefined values while still being well defined." But there * might be invalid elements (standard, p. 151), so check for them. */ super(imiCollection); this.genericType = genericType; OclIterator<T> iter = getIterator(); while (iter.hasNext().isTrue()) { T element = iter.next(); if (element.getInvalidReason() != null) { this.invalidReason = new RuntimeException( "Cannot create OclCollection with an invalid element. Reason: " + element.getInvalidReason().getMessage(), element .getInvalidReason()); this.imiElement = IModelInstanceInvalid.INSTANCE; break; } } } public JavaOclCollection(String undefinedReason, Type genericType) { super(undefinedReason); this.genericType = genericType; } public JavaOclCollection(Throwable invalidReason, Type genericType) { super(invalidReason); this.genericType = genericType; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#asBag() */ public OclBag<T> asBag() { OclBag<T> result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getBagType(genericType), this); if (result == null) result = checkUndefined("asBag", EssentialOclPlugin.getOclLibraryProvider() .getOclLibrary().getBagType(genericType), this); if (result == null) { IModelInstanceCollection<IModelInstanceElement> imiCollectionResult = BasisJavaModelInstanceFactory.createModelInstanceCollection( getModelInstanceCollection().getCollection(), EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getSequenceType( genericType)); result = new JavaOclBag<T>(imiCollectionResult, genericType); } return result; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#asOrderedSet * () */ public OclOrderedSet<T> asOrderedSet() { OclOrderedSet<T> result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOrderedSetType(genericType), this); if (result == null) result = checkUndefined("asOrderedSet", EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getOrderedSetType( genericType), this); if (result == null) { IModelInstanceCollection<IModelInstanceElement> imiCollectionResult = BasisJavaModelInstanceFactory.createModelInstanceCollection( getModelInstanceCollection().getCollection(), EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getOrderedSetType( (genericType))); result = new JavaOclOrderedSet<T>(imiCollectionResult, genericType); } return result; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#asSequence * () */ public OclSequence<T> asSequence() { OclSequence<T> result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getSequenceType(genericType), this); if (result == null) result = checkUndefined("asSequence", EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getSequenceType( genericType), this); if (result == null) { IModelInstanceCollection<IModelInstanceElement> imiCollectionResult = BasisJavaModelInstanceFactory.createModelInstanceCollection( getModelInstanceCollection().getCollection(), EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getSequenceType( (genericType))); result = new JavaOclSequence<T>(imiCollectionResult, genericType); } return result; } /* * (non-Javadoc) * @see org.dresdenocl.essentialocl.standardlibrary.OclAny#asSet() */ public OclSet<T> asSet() { OclSet<T> result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getSetType(genericType), this); if (result == null) result = checkAsSet(genericType); if (result == null) { IModelInstanceCollection<IModelInstanceElement> imiCollectionResult = BasisJavaModelInstanceFactory.createModelInstanceCollection( getModelInstanceCollection().getCollection(), EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getSetType( (genericType))); result = new JavaOclSet<T>(imiCollectionResult, genericType); } return result; } /* * (non-Javadoc) * @see org.dresdenocl.essentialocl.standardlibrary.OclCollection#count * (java.lang.Object) */ @SuppressWarnings("unchecked") public OclInteger count(T that) { OclInteger result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclInteger(), this); if (result == null) result = checkUndefined("count", EssentialOclPlugin.getOclLibraryProvider() .getOclLibrary().getOclInteger(), this); if (result == null) { /* Else compute the result. */ Long intResult; intResult = 0L; for (IModelInstanceElement anElement : this.getModelInstanceCollection() .getCollection()) { T oclElement = (T) JavaStandardLibraryFactory.INSTANCE.createOclAny(anElement); if (oclElement.isEqualTo(that).isTrue()) { intResult++; } } result = JavaStandardLibraryFactory.INSTANCE.createOclInteger(intResult); } return result; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#excludes * (java.lang.Object) */ public OclBoolean excludes(T that) { return includes(that).not(); } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#excludesAll * (org.dresdenocl.essentialocl.standardlibrary.OclCollection) */ @SuppressWarnings("unchecked") public OclBoolean excludesAll(OclCollection<T> that) { OclBoolean result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclBoolean(), this, that); if (result == null) result = checkUndefined("excludesAll", EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getOclBoolean(), this, that); if (result == null) { /* Else compute the result. */ boolean booleanResult; OclBoolean excludesElement; booleanResult = true; for (IModelInstanceElement anElement : that.getModelInstanceCollection() .getCollection()) { T oclElement = (T) JavaStandardLibraryFactory.INSTANCE.createOclAny(anElement); excludesElement = this.excludes(oclElement); if (excludesElement.oclIsUndefined().isTrue()) { result = excludesElement; break; } else { booleanResult = (booleanResult && excludesElement.isTrue()); if (!booleanResult) { break; } // no else. } } // end for. result = JavaOclBoolean.getInstance(booleanResult); } return result; } /* * (non-Javadoc) * @seeorg.dresdenocl.essentialocl.standardlibrary.OclCollection# * getGenericType () */ public Type getGenericType() { return genericType; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#getIterator * () */ public OclIterator<T> getIterator() { return new JavaOclIterator<T>(this); } /* * (non-Javadoc) * @seeorg.dresdenocl.essentialocl.standardlibrary.OclCollection# * getModelInstanceCollection() */ @SuppressWarnings("unchecked") public IModelInstanceCollection<IModelInstanceElement> getModelInstanceCollection() { return (IModelInstanceCollection<IModelInstanceElement>) imiElement; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#includes * (java.lang.Object) */ public OclBoolean includes(T that) { OclBoolean result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclBoolean(), this, that); if (result == null) result = checkUndefined("includes", EssentialOclPlugin.getOclLibraryProvider() .getOclLibrary().getOclBoolean(), this); if (result == null) { /* Else iterate and compare with all elements of this collection. */ boolean boolResult; boolResult = false; IModelInstanceElement imiThat = that.getModelInstanceElement(); for (IModelInstanceElement anElement : getModelInstanceCollection() .getCollection()) { if (anElement.equals(imiThat)) { boolResult = true; break; } // no else. } result = JavaOclBoolean.getInstance(boolResult); } return result; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#includesAll * (org.dresdenocl.essentialocl.standardlibrary.OclCollection) */ @SuppressWarnings("unchecked") public OclBoolean includesAll(OclCollection<T> that) { OclBoolean result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclBoolean(), this, that); if (result == null) result = checkUndefined("includesAll", EssentialOclPlugin .getOclLibraryProvider().getOclLibrary().getOclBoolean(), this, that); if (result == null) { /* Else compute the result. */ boolean adaptedResult; adaptedResult = true; /* * Check if all elements of anAdaptedCollection are contained in this * collection. */ for (IModelInstanceElement anElement : that.getModelInstanceCollection() .getCollection()) { T oclElement = (T) JavaStandardLibraryFactory.INSTANCE.createOclAny(anElement); OclBoolean isElementContained; isElementContained = this.includes(oclElement); /* If an element is not contained, return false. */ if (isElementContained.oclIsUndefined().isTrue() || !isElementContained.isTrue()) { adaptedResult = false; break; } // no else. } result = JavaOclBoolean.getInstance(adaptedResult); } return result; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#isEmpty () */ public OclBoolean isEmpty() { OclBoolean result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclBoolean(), this); // see standard, p.138 if (undefinedreason != null) result = JavaOclBoolean.getInstance(true); if (result == null) { /* Else compute the result. */ boolean adaptedResult; adaptedResult = getModelInstanceCollection().getCollection().isEmpty(); result = JavaOclBoolean.getInstance(adaptedResult); } return result; } /* * (non-Javadoc) * @see org.dresdenocl.essentialocl.standardlibrary.OclCollection#max() */ @SuppressWarnings("unchecked") public T max() { T result = null; result = checkInvalid(genericType, this); if (result == null) result = checkUndefined("max", genericType, this); if (result == null) { if (this.isEmpty().isTrue()) result = (T) JavaStandardLibraryFactory.INSTANCE.createOclInteger(0L); else { OclIterator<T> oclIterator = this.getIterator(); /* * safe, since collection is not empty */ T maxElement = oclIterator.next(); final OclInteger integer1 = JavaStandardLibraryFactory.INSTANCE.createOclInteger(1L); while (oclIterator.hasNext().isTrue()) { T element = oclIterator.next(); if (element instanceof OclComparable) { /* * We should not compare the element to an undefined value. */ if (!maxElement.oclIsUndefined().isTrue()) { if (((OclComparable) element).compareTo( (OclComparable) maxElement).isEqualTo(integer1).isTrue()) maxElement = element; } else { maxElement = element; } } } /* * In case there were only undefined values, the return should be zero. */ if (maxElement.oclIsUndefined().isTrue()) result = (T) JavaStandardLibraryFactory.INSTANCE.createOclInteger(0L); else result = maxElement; } } return result; } /* * (non-Javadoc) * @see org.dresdenocl.essentialocl.standardlibrary.OclCollection#min() */ @SuppressWarnings("unchecked") public T min() { T result = null; result = checkInvalid(genericType, this); if (result == null) result = checkUndefined("min", genericType, this); if (result == null) { if (this.isEmpty().isTrue()) result = (T) JavaStandardLibraryFactory.INSTANCE.createOclInteger(0L); else { OclIterator<T> oclIterator = this.getIterator(); /* * safe, since collection is not empty */ T minElement = oclIterator.next(); final OclInteger integer_1 = JavaStandardLibraryFactory.INSTANCE.createOclInteger(-1L); while (oclIterator.hasNext().isTrue()) { T element = oclIterator.next(); if (element instanceof OclComparable) { /* * We should not compare the element to an undefined value. */ if (!minElement.oclIsUndefined().isTrue()) { if (((OclComparable) element).compareTo( (OclComparable) minElement).isEqualTo(integer_1).isTrue()) minElement = element; } else { minElement = element; } } } /* * In case there were only undefined values, the return should be zero. */ if (minElement.oclIsUndefined().isTrue()) result = (T) JavaStandardLibraryFactory.INSTANCE.createOclInteger(0L); else result = minElement; } } return result; } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#notEmpty * () */ public OclBoolean notEmpty() { return this.isEmpty().not(); } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#product * (org.dresdenocl.essentialocl.standardlibrary.OclCollection) */ public <T2 extends OclAny> OclSet<OclTuple> product(OclCollection<T2> that) { // calculate initial size of tuple set int thisSize = this.size().getModelInstanceInteger().getLong().intValue(); int thatSize = that.size().getModelInstanceInteger().getLong().intValue(); // combinated elements as set of tuples Set<OclTuple> tuples = new HashSet<OclTuple>(thisSize * thatSize); List<IModelInstanceString> keys = this.createTupleKeys("first", "second"); TupleType tupleType = this.createProductTupleType(that); // precreate list of values and reuse the elements List<IModelInstanceElement> values = new ArrayList<IModelInstanceElement>(2); // initially fill both values with null // to have access to 0 and 1 in the loop values.add(null); values.add(null); // iterate over *this* elements for (OclIterator<T> it = this.getIterator(); it.hasNext().isTrue();) { values.set(0, it.next().getModelInstanceElement()); // iterate over *that* elements for (OclIterator<T2> it2 = that.getIterator(); it2.hasNext().isTrue();) { T2 elem = it2.next(); values.set(1, elem.getModelInstanceElement()); // add tuple for current pair to set OclTuple tuple = JavaStandardLibraryFactory.INSTANCE.createOclTuple(keys, values, tupleType); tuples.add(tuple); } } return JavaStandardLibraryFactory.INSTANCE.createOclSet(tuples, tupleType); } /* * (non-Javadoc) * @see * org.dresdenocl.essentialocl.standardlibrary.OclCollection#size() */ public OclInteger size() { OclInteger result = null; result = checkInvalid(EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclInteger(), this); if (result == null) result = checkUndefined("size", EssentialOclPlugin.getOclLibraryProvider() .getOclLibrary().getOclInteger(), this); if (result == null) { Long intResult; intResult = Long.valueOf(getModelInstanceCollection().getCollection().size()); result = JavaStandardLibraryFactory.INSTANCE.createOclInteger(intResult); } return result; } /* * (non-Javadoc) * @see org.dresdenocl.essentialocl.standardlibrary.OclCollection#sum() */ @SuppressWarnings("unchecked") public T sum() { T result = null; result = checkInvalid(genericType, this); if (result == null) result = checkUndefined("sum", genericType, this); if (result == null) { /* Else check if this collection is empty. */ if (this.isEmpty().isTrue()) { // TODO: future work; neutral element for addition of T's result = (T) JavaStandardLibraryFactory.INSTANCE.createOclInteger(0L); } /* Else iterate through the collection and compute the sum. */ else { /* Try to add the elements of this collection to a sum. */ for (IModelInstanceElement anElement : getModelInstanceCollection() .getCollection()) { // undefined values are ignored if (!anElement.isUndefined()) { T oclElement = (T) JavaStandardLibraryFactory.INSTANCE.createOclAny(anElement); // first element cannot be added to something if (result == null) { result = oclElement; } else { try { result = (T) ((IAddableElement) result).add(oclElement); } catch (ClassCastException e) { result = (T) JavaStandardLibraryFactory.INSTANCE.createOclInvalid( EssentialOclPlugin.getOclLibraryProvider() .getOclLibrary().getOclReal(), e); } } } } } } return result; } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(this.getClass().getSimpleName()); result.append("["); if (!toStringUndefinedOrInvalid(result)) { OclIterator<T> iter = getIterator(); while (iter.hasNext().isTrue()) { T element = iter.next(); result.append(element); if (iter.hasNext().isTrue()) { result.append(", "); } } } // no else result.append("]"); return result.toString(); } @SuppressWarnings("unchecked") protected Type flatRec(Collection<IModelInstanceElement> imiCollection, Collection<IModelInstanceElement> returnList) { Type result = null; /* Iterate over this bag. */ for (IModelInstanceElement element : imiCollection) { /* * nested collections are flattened, i.e. their elements are added to the * result */ if (element instanceof IModelInstanceCollection<?>) { IModelInstanceCollection<IModelInstanceElement> collection; collection = ((IModelInstanceCollection<IModelInstanceElement>) element); result = this.commonSuperType(result, flatRec(collection.getCollection(), returnList)); } /* other elements are simply added */ else { returnList.add(element); result = this.commonSuperType(result, element.getType()); } } // FIXME Michael: Should this be OclAny or something else? if (result == null) result = EssentialOclPlugin.getOclLibraryProvider().getOclLibrary() .getOclAny(); return result; } /** * Helper function to create tuple type for the type of this collection to * another * * @param that * other collection * @return tuple type with both collection types (*this* is first) */ private <T2 extends OclAny> TupleType createProductTupleType( OclCollection<T2> that) { // attributes List<Property> properties = new ArrayList<Property>(); properties.add(this.createPropertyByNameAndType("first", this .getGenericType())); properties.add(this.createPropertyByNameAndType("second", that .getGenericType())); // TODO: check if refactoring possible OclLibrary oclLib = EssentialOclPlugin.getOclLibraryProvider().getOclLibrary(); return oclLib.makeTupleType(properties); } /** * Returns a property for a given name and type * * @TODO: this method should be moved to a factory class since it is used * probably somewhere else, too! */ private Property createPropertyByNameAndType(String name, Type type) { Property prop = PivotModelFactory.eINSTANCE.createProperty(); prop.setName(name); prop.setType(type); return prop; } /** * helper function to create a list of tuple keys * * @param keys * @return */ private List<IModelInstanceString> createTupleKeys(String... keys) { List<IModelInstanceString> keyList = new ArrayList<IModelInstanceString>(keys.length); for (String key : keys) { keyList.add(BasisJavaModelInstanceFactory.createModelInstanceString(key)); } return keyList; } }