All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.ocl.util.CollectionUtil Maven / Gradle / Ivy

/**
 * 
 *
 * Copyright (c) 2006, 2008, 2011 IBM Corporation, Zeligsoft Inc., and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   IBM - Initial API and implementation
 *   Zeligsoft - Bugs 244946, 248869
 *   Axel Uhl (SAP AG) - Bug 342644
 *
 * 
 *
 * $Id: CollectionUtil.java,v 1.10 2011/05/01 10:56:50 auhl Exp $
 */
package org.eclipse.ocl.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EvaluationEnvironment;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.internal.OCLPlugin;
import org.eclipse.ocl.internal.l10n.OCLMessages;
import org.eclipse.ocl.types.CollectionType;

/**
 * Utility methods for working with OCL collection values.
 *
 * @author Christian W. Damus (cdamus)
 */
public class CollectionUtil {

    // not instantiable
	private CollectionUtil() {
		super();
	}

    /**
     * Implementation of the OCL
     * Collection::includes(object : T) : Boolean
     * operation.
     * 
     * @param self the source collection
     * @param object an object
     * @return whether the collection includes the object
     */
    public static boolean includes(Collection self, Object object) {
    	return self.contains(object);
    }

    /**
     * Implementation of the OCL
     * Collection::excludes(object : T) : Boolean
     * operation.
     * 
     * @param self the source collection
     * @param object an object
     * @return whether the collection does not include the object
     */
    public static boolean excludes(Collection self, Object object) {
        return !includes(self, object);
    }

    /**
     * Implementation of the OCL
     * Collection::count(object : T) : Integer
     * operation.
     * 
     * @param self the source collection
     * @param object an object
     * @return the number of occurrences of the object in the collection
     */
	public static int count(Collection self, Object object) {
		int count = 0;
		for (Object next : self) {
			if (ObjectUtil.equal(next, object)) {
				count++;
			}
		}
		return count;
	}

    /**
     * Implementation of the OCL
     * Collection::includesAll(c : Collection(T)) : Boolean
     * operation.
     * 
     * @param self the source collection
     * @param c another collection
     * @return whether the source collection includes all of the elements
     *     of the other
     */
    public static boolean includesAll(Collection self, Collection c) {
    	for (Object next : c) {
    		if (!includes(self, next)) {
    			return false;
    		}
    	}
    	
        return true;
    }

    /**
     * Implementation of the OCL
     * Collection::excludesAll(c : Collection(T)) : Boolean
     * operation.
     * 
     * @param self the source collection
     * @param c another collection
     * @return whether the source collection does not contain any of the
     *     elements of the other
     */
    public static boolean excludesAll(Collection self, Collection c) {
        for (Object next : c) {
            if (includes(self, next)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Implementation of the OCL
     * Collection::isEmpty() : Boolean
     * operation.
     * 
     * @param self the source collection
     * @return whether the collection does not have any elements
     */
    public static boolean isEmpty(Collection self) {
        return self.isEmpty();
    }

    /**
     * Implementation of the OCL
     * Collection::notEmpty() : Boolean
     * operation.
     * 
     * @param self the source collection
     * @return whether the collection has any elements
     */
    public static boolean notEmpty(Collection self) {
        return !self.isEmpty();
    }

    /**
     * Implementation of the OCL
     * Collection::sum() : T
     * operation.
     * 
     * @param self the source collection
     * @return the sum of the collection's elements
     */
    // Assumes the elements of the collection are all Integer or
    // all Double.
    public static Object sum(Collection self) {

        if (self.isEmpty()) {
            return null; // undefined
        }
        
        Iterator it = self.iterator();
        Object object = it.next();

        // two cases: Integer and Double
        if (object instanceof Integer) {
            int currVal = 0;
            for (it = self.iterator(); it.hasNext();) {
                currVal += ((Integer) it.next()).intValue();
            }
            return new Integer(currVal);
        } else if (object instanceof Double) {
            double currVal = 0.0;
            for (it = self.iterator(); it.hasNext();) {
                currVal += ((Double) it.next()).doubleValue();
            }
            return new Double(currVal);
        } else {
            IllegalArgumentException error = new IllegalArgumentException(
            		OCLMessages.SumOperator_ERROR_);
            OCLPlugin.throwing(CollectionUtil.class, "sum", error);//$NON-NLS-1$
            throw error;
        }
    }

    /**
     * Implementation of the OCL
     * 
    *
  • Set::=(set : Set(T)) : Boolean
  • *
  • OrderedSet::=(set : OrderedSet(T)) : Boolean
  • *
  • Bag::=(bag : Bag(T)) : Boolean
  • *
  • Sequence::=(s : Sequence(T)) : Boolean
  • *
* operations. * * @param self the source collection * @param c another collection of the same kind * @return whether collections are equal */ public static boolean equals(Collection self, Collection c) { if (self.size() != c.size()) { // collections of different sizes cannot be equal return false; } else if (self instanceof Bag && c instanceof Bag) { return ((Bag) self).equals(c); } else if (self instanceof List && c instanceof List) { return ((List) self).equals(c); } else if (self instanceof LinkedHashSet && c instanceof LinkedHashSet) { // OrderedSet // LinkedHashSet.equals() doesn't care about order but we do int size1 = self.size(); int size2 = c.size(); if (size1 != size2) { return false; } Iterator it1 = self.iterator(); Iterator it2 = c.iterator(); while (it1.hasNext()) { Object o1 = it1.next(); Object o2 = it2.next(); if (!o1.equals(o2)) { return false; } } return true; } else if (self instanceof Set && c instanceof Set) { return ((Set) self).equals(c); } else { // incompatible OCL types return false; } } /** * Computes the hash of a collection, accounting for the similar hashing of * primitive numeric values that OCL considers equal but Java does not. * * @param c a collection * * @return its hash */ public static int hashCode(Collection c) { int result = 1; for (Object next : c) { result = 37 * result + ObjectUtil.hashCode(next); } return result; } /** * Implementation of the OCL *
    *
  • Set::intersection(set : Set(T)) : Set(T)
  • *
  • Set::intersection(bag : Bag(T)) : Set(T)
  • *
  • Bag::intersection(set : Set(T)) : Set(T)
  • *
  • Bag::intersection(bag : Bag(T)) : Set(T)
  • *
* operations. * * @param self the source set or bag * @param c another set or bag * @return the intersection of the source set or bag with the other set or bag */ public static Collection intersection( Collection self, Collection c) { int size1 = self.size(); int size2 = c.size(); // if either collection is empty, then so is the result if (size1 == 0 || size2 == 0) { if (self instanceof Set || c instanceof Set) { return Collections.emptySet(); } else { return BagImpl.emptyBag(); } } Collection result = null; if (self instanceof Set || c instanceof Set) { // if either argument is a set, so is the result if (size1 == 0 || size2 == 0) { return Collections.emptySet(); } result = createNewSet(); } else { // both arguments are bags, so is the result if (size1 == 0 || size2 == 0) { return BagImpl.emptyBag(); } result = createNewBag(); } // loop over the smaller collection and add only elements // that are in the larger collection if (self.size() > c.size()) { for (E e : c) { if (includes(self, e)) { result.add(e); } } } else { for (E e : self) { if (includes(c, e)) { result.add(e); } } } return result; } /** * Implementation of the OCL *
    *
  • Set::union(set : Set(T)) : Set(T)
  • *
  • Set::union(bag : Bag(T)) : Bag(T)
  • *
  • Bag::union(set : Set(T)) : Bag(T)
  • *
  • Bag::union(bag : Bag(T)) : Bag(T)
  • *
  • Sequence::union(s : Sequence(T)) : Sequence(T)
  • *
* operations. * * @param self the source collection * @param c another collection * @return the union of the source collection with the other */ public static Collection union( Collection self, Collection c) { // if either argument is empty, then the union is the other, // except the source is a set and the other is a bag in which // case the result has to be a bag if (self.isEmpty()) { if (self instanceof Bag || c instanceof Bag) { return createNewBag(c); } else { return createNewCollection(c); } } else if (c.isEmpty()) { if (self instanceof Bag || c instanceof Bag) { return createNewBag(self); } else { return createNewCollection(self); } } Collection result = null; if (self instanceof Bag || c instanceof Bag) { result = createNewBag(self); } else if (self instanceof List || c instanceof List) { result = createNewSequence(self); } else { result = createNewSet(self); } result.addAll(c); return result; } /** * Implementation of the OCL *
    *
  • Set::flatten() : Set(T2)
  • *
  • Bag::flatten() : Bag(T2)
  • *
  • Sequence::flatten() : Sequence(T2)
  • *
* operations. * * @param self the source collection * @return the flattened collection */ public static Collection flatten(Collection self) { // Note: As OCL 2.3 (OMG 10-11-42) section A.2.5.8 fails to specify how to // flatten an OrderedSet, we choose to flatten it into an OrderedSet // represented by a LinkedHashSet. Collection result = self; for (;;) { if (result.isEmpty()) { break; } Iterator it = result.iterator(); Object object = it.next(); // if the element type is not a collection type, the result is the // current collection. if (!(object instanceof Collection)) { break; } Collection newResult = null; if (result instanceof Bag) { newResult = createNewBag(); } else if (result instanceof Set) { newResult = createNewSet(); } else { // Sequence newResult = createNewSequence(); } // the element type is a collection type -- flatten one level newResult.addAll((Collection) object); while (it.hasNext()) { newResult.addAll((Collection) it.next()); } result = newResult; // loop until the result is empty or the first element is not a // collection } return result; } /** * Obtains the type of the flattened form of the specified collection type. * * @param type a collection type * @return the flattened collection type * * @since 1.2 */ @SuppressWarnings("unchecked") public static C getFlattenedElementType( CollectionType type) { C result = type.getElementType(); while (result instanceof CollectionType) { result = ((CollectionType) result).getElementType(); } return result; } /** * Implementation of the OCL * Set::-(set : Set(T)) : Set(T) * operation. * * @param self the source set * @param set another set * @return the subtraction of the other set from the source set */ public static Set minus(Set self, Set set) { Set result = createNewSet(self); result.removeAll(set); return result; } /** * Implementation of the OCL *
    *
  • Set::excluding(object : T) : Set(T)
  • *
  • Bag::excluding(object : T) : Bag(T)
  • *
  • Sequence::excluding(object : T) : Sequence(T)
  • *
* operations. * * @param self the source collection * @param object an object * @return the source collection without any occurences of the object */ public static Collection excluding(Collection self, Object object) { Collection result = null; if (self instanceof LinkedHashSet) { result = createNewOrderedSet(self); } else if (self instanceof Set) { result = createNewSet(self); } else if (self instanceof Bag) { result = createNewBag(self); } else if (self instanceof List) { List resultSeq = createNewSequence(self); while (resultSeq.remove(object)) { ; // for sequences we need to remove all the matching elements } return resultSeq; } else { throw new RuntimeException("Unsupported collection type "+self.getClass().getName()); //$NON-NLS-1$ } // non-sequences (bags remove all occurrences internally) result.remove(object); return result; } /** * Implementation of the OCL * Set::symmetricDifference(set : Set(T)) : Set(T) * operation. * * @param self the source set * @param set another set * @return the set of elements in either the source or the other set but not * in both */ public static Set symmetricDifference(Set self, Set set) { Set result = createNewSet(self); for (E e : set) { if (result.contains(e)) { result.remove(e); } else { result.add(e); } } return result; } /** * Implementation of the OCL *
    *
  • Set::including(object : T) : Set(T)
  • *
  • Bag::including(object : T) : Bag(T)
  • *
  • Sequence::including(object : T) : Sequence(T)
  • *
* operations. * * @param self the source collection * @param object an object * @return the source collection with the object added */ public static Collection including(Collection self, E object) { Collection result; if (self instanceof LinkedHashSet) { result = createNewOrderedSet(self); } else if (self instanceof Set) { result = createNewSet(self); } else if (self instanceof Bag) { result = createNewBag(self); } else { result = createNewSequence(self); } result.add(object); return result; } /** * Implementation of the OCL *
    *
  • Set::asSet() : Set(T)
  • *
  • Bag::asSet() : Set(T)
  • *
  • Sequence::asSet() : Set(T)
  • *
* operations. * * @param self the source collection * @return the source collection as a set */ public static Set asSet(Collection self) { if (self instanceof Set && !(self instanceof LinkedHashSet)) { return (Set) self; } return createNewSet(self); } /** * Implementation of the OCL *
    *
  • Set::asBag() : Bag(T)
  • *
  • Bag::asBag() : Bag(T)
  • *
  • Sequence::asBag() : Bag(T)
  • *
* operations. * * @param self the source collection * @return the source collection as a bag */ public static Bag asBag(Collection self) { if (self instanceof Bag) { return (Bag) self; } return createNewBag(self); } /** * Implementation of the OCL *
    *
  • Set::asSequence() : Sequence(T)
  • *
  • Bag::asSequence() : Sequence(T)
  • *
  • Sequence::asSequence() : Sequence(T)
  • *
* operations. * * @param self the source collection * @return the source collection as a sequence */ public static List asSequence(Collection self) { if (self instanceof List) { return (List) self; } return createNewSequence(self); } /** * Implementation of the OCL *
    *
  • Set::asOrderedSet() : OrderedSet(T)
  • *
  • Bag::asOrderedSet() : OrderedSet(T)
  • *
  • Sequence::asOrderedSet() : OrderedSet(T)
  • *
* operations. * * @param self the source collection * @return the source collection as an ordered set */ public static LinkedHashSet asOrderedSet(Collection self) { // TODO: create an interface for OrderedSet if (self instanceof LinkedHashSet) { return (LinkedHashSet) self; } return createNewOrderedSet(self); } /** * Implementation of the OCL * Collection::product(c : Collection(T2)) : Set(Tuple(first : T, second : T2)) * operations. * * @param evalEnv the current evaluation environment (for construction of * tuples) * @param env the current OCL environment (for introspection of the tuple type) * @param self the source collection * @param c another collection * @return the product of the collections */ public static Set> product(EvaluationEnvironment evalEnv, Environment env, Collection self, Collection c, C tupleType) { Set> result = createNewSet(); Map propertyValues = new HashMap(); P firstProperty = env.lookupProperty( tupleType, OCLStandardLibraryUtil.PRODUCT_FIRST); P secondProperty = env.lookupProperty( tupleType, OCLStandardLibraryUtil.PRODUCT_SECOND); for (Object next1 : self) { for (Object next2 : c) { propertyValues.put(firstProperty, next1); propertyValues.put(secondProperty, next2); result.add(evalEnv.createTuple(tupleType, propertyValues)); } } return result; } /** * Implementation of the OCL *
    *
  • OrderedSet::append(object : T) : OrderedSet(T)
  • *
  • Sequence::append(object : T) : Sequence(T)
  • *
* operations. * * @param self the source collection * @param object an object * @return the source collection with the object appended */ public static Collection append(Collection self, E object) { Collection result; // TODO: make an interface for OrderedSet if (self instanceof LinkedHashSet) { result = createNewOrderedSet(self); result.remove(object); // appended object must be last } else { result = createNewSequence(self); } result.add(object); return result; } /** * Implementation of the OCL *
    *
  • OrderedSet::prepend(object : T) : OrderedSet(T)
  • *
  • Sequence::prepend(object : T) : Sequence(T)
  • *
* operations. * * @param self the source collection * @param object an object * @return the source collection with the object prepended */ public static Collection prepend(Collection self, E object) { Collection result; if (self instanceof LinkedHashSet) { result = createNewOrderedSet(); } else { result = createNewSequence(); } result.add(object); result.addAll(self); return result; } /** * Implementation of the OCL *
    *
  • OrderedSet::insertAt(index : Integer, object : T) : OrderedSet(T)
  • *
  • Sequence::insertAt(index : Integer, object : T) : Sequence(T)
  • *
* operations. * * @param self the source collection * @param index the 1-based (in OCL fashion) index * @param object an object * @return the source collection with the object inserted at the index * * @throws IndexOutOfBoundsException if the index is out of bounds */ public static Collection insertAt(Collection self, int index, E object) { index = index - 1; if (index < 0 || index > self.size()) { throw new IndexOutOfBoundsException( "index: " + (index + 1) + ", size: " //$NON-NLS-1$ //$NON-NLS-2$ + self.size()); } Collection result; if (self instanceof LinkedHashSet) { result = createNewOrderedSet(); } else { result = createNewSequence(); } int curr = 0; for (Iterator it = self.iterator(); it.hasNext();) { if (curr == index) { result.add(object); } result.add(it.next()); curr++; } if (index == self.size()) { // the loop finished before we could add the object result.add(object); } return result; } /** * Implementation of the OCL * OrderedSet::subOrderedSet(lower : Integer, upper : Integer) : OrderedSet(T) * operation. * * @param self the source set * @param lower the 1-based (in OCL fashion) inclusive lower bound * @param upper the 1-based (in OCL fashion) inclusive upper bound * @return the slice of the source set * * @throws IndexOutOfBoundsException if an index is out of bounds * @throws IllegalArgumentException if the lower bound is greater than the upper */ public static Collection subOrderedSet(Collection self, int lower, int upper) { lower = lower - 1; upper = upper - 1; if (lower < 0) { throw new IndexOutOfBoundsException("lower: " + (lower + 1)); //$NON-NLS-1$ } else if (upper >= self.size()) { throw new IndexOutOfBoundsException( "upper: " + (upper + 1) + ", size: " //$NON-NLS-1$ //$NON-NLS-2$ + self.size()); } else if (upper < lower) { throw new IllegalArgumentException( "lower: " + (lower + 1) + ", upper: " //$NON-NLS-1$ //$NON-NLS-2$ + (upper + 1)); } Collection result; if (self instanceof LinkedHashSet) { result = createNewOrderedSet(); } else { result = createNewSequence(); } int curr = 0; for (Iterator it = self.iterator(); it.hasNext();) { E object = it.next(); if (curr >= lower && curr <= upper) { result.add(object); } curr++; } return result; } /** * Implementation of the OCL * Sequence::subSequence(lower : Integer, upper : Integer) : Sequence(T) * operation. * * @param self the source sequence * @param lower the 1-based (in OCL fashion) inclusive lower bound * @param upper the 1-based (in OCL fashion) inclusive upper bound * @return the source collection with the object inserted at the index * * @throws IndexOutOfBoundsException if an index is out of bounds * @throws IllegalArgumentException if the lower bound is greater than the upper */ public static Collection subSequence(Collection self, int lower, int upper) { lower = lower - 1; upper = upper - 1; if (lower < 0) { throw new IndexOutOfBoundsException("lower: " + (lower + 1)); //$NON-NLS-1$ } else if (upper >= self.size()) { throw new IndexOutOfBoundsException( "upper: " + (upper + 1) + ", size: " //$NON-NLS-1$ //$NON-NLS-2$ + self.size()); } else if (upper < lower) { throw new IllegalArgumentException( "lower: " + (lower + 1) + ", upper: " //$NON-NLS-1$ //$NON-NLS-2$ + (upper + 1)); } Collection result = createNewSequence(); int curr = 0; for (Iterator it = self.iterator(); it.hasNext();) { E object = it.next(); if (curr >= lower && curr <= upper) { result.add(object); } curr++; } return result; } /** * Implementation of the OCL *
    *
  • OrderedSet::at(index : Integer) : T
  • *
  • Sequence::at(index : Integer) : T
  • *
* operations. * * @param self the source collection * @param index the 1-based (in OCL fashion) index * @return the object at the specified index of the source collection * * @throws IndexOutOfBoundsException if the index is out of bounds */ public static E at(Collection self, int index) { index = index - 1; if (index < 0 || index >= self.size()) { throw new IndexOutOfBoundsException( "index: " + (index + 1) + ", size: " //$NON-NLS-1$ //$NON-NLS-2$ + self.size()); } int curr = 0; for (Iterator it = self.iterator(); it.hasNext();) { E object = it.next(); if (curr++ == index) { return object; } } return null; // undefined } /** * Implementation of the OCL *
    *
  • OrderedSet::first() : T
  • *
  • Sequence::first() : T
  • *
* operations. * * @param self the source collection * @return the first object of the source collection */ public static E first(Collection self) { if (self.isEmpty()) { return null; // undefined } return self.iterator().next(); } /** * Implementation of the OCL *
    *
  • OrderedSet::lset() : T
  • *
  • Sequence::lset() : T
  • *
* operations. * * @param self the source collection * @return the last object in the source collection */ public static E last(Collection self) { if (self.isEmpty()) { return null; // undefined } E result = null; for (E next : self) { result = next; } return result; } /** * Implementation of the OCL *
    *
  • OrderedSet::indexOf(object : T) : Integer
  • *
  • Sequence::indexOf(object : T) : Integer
  • *
* operations. * * @param self the source collection * @param object an object * @return the index of the object in the source collection */ public static Integer indexOf(Collection self, E object) { int index = 1; for (E next : self) { if (ObjectUtil.equal(object, next)) { return index; } index++; } return null; // invalid } /** * Creates a new OCL Set. */ @SuppressWarnings("unchecked") public static Set createNewSet() { return (Set) createNewCollection(CollectionKind.SET_LITERAL); } /** * Creates a new OCL Set with initial contents supplied. */ @SuppressWarnings("unchecked") public static Set createNewSet(Collection c) { return (Set) createNewCollection(CollectionKind.SET_LITERAL, c); } /** * Creates a new OCL Bag. */ @SuppressWarnings("unchecked") public static Bag createNewBag() { return (Bag) createNewCollection(CollectionKind.BAG_LITERAL); } /** * Creates a new OCL Bag with initial contents supplied. */ @SuppressWarnings("unchecked") public static Bag createNewBag(Collection c) { return (Bag) createNewCollection(CollectionKind.BAG_LITERAL, c); } /** * Creates a new OCL OrderedSet. */ @SuppressWarnings("unchecked") public static LinkedHashSet createNewOrderedSet() { return (LinkedHashSet) createNewCollection( CollectionKind.ORDERED_SET_LITERAL); } /** * Creates a new OCL OrderedSet with initial contents supplied. */ @SuppressWarnings("unchecked") public static LinkedHashSet createNewOrderedSet(Collection c) { return (LinkedHashSet) createNewCollection( CollectionKind.ORDERED_SET_LITERAL, c); } /** * Creates a new OCL Sequence. */ @SuppressWarnings("unchecked") public static List createNewSequence() { return (List) createNewCollection(CollectionKind.SEQUENCE_LITERAL); } /** * Creates a new OCL Sequence with initial contents supplied. */ @SuppressWarnings("unchecked") public static List createNewSequence(Collection c) { return (List) createNewCollection(CollectionKind.SEQUENCE_LITERAL, c); } /** * Creates a new, empty OCL collection of the same kind as the specified * prototype. * * @param c a collection * @return a new, empty collection of the same kind as c */ public static Collection createNewCollectionOfSameKind(Collection c) { Collection result; if (c instanceof Bag) { result = createNewBag(); } else if (c instanceof LinkedHashSet) { result = createNewOrderedSet(); } else if (c instanceof Set) { result = createNewSet(); } else { result = createNewSequence(); } return result; } /** * Creates a new OCL collection of the same kind and contents as the * specified prototype. * * @param c a collection * @return a copy of c */ public static Collection createNewCollection(Collection c) { Collection result; if (c instanceof Bag) { result = createNewBag(c); } else if (c instanceof LinkedHashSet) { result = createNewOrderedSet(c); } else if (c instanceof Set) { result = createNewSet(c); } else { result = createNewSequence(c); } return result; } /** * Creates a new OCL Collection of the specified kind. * * @param kind the OCL collection kind * @return the new collection */ public static Collection createNewCollection(CollectionKind kind) { switch (kind) { case SET_LITERAL: return new HashSet(); case SEQUENCE_LITERAL: return new ArrayList(); case ORDERED_SET_LITERAL: return new LinkedHashSet(); case BAG_LITERAL: return new BagImpl(); default: { String message = OCLMessages.bind( OCLMessages.OCLCollectionKindNotImpl_ERROR_, kind); IllegalArgumentException error = new IllegalArgumentException( message); OCLPlugin.throwing( CollectionUtil.class, "createNewCollection", error);//$NON-NLS-1$ throw error; } } } /** * Creates a new OCL Collection of the specified kind. * * @param kind the OCL collection kind * @param c the contents of the new collection * @return the new collection of the specified kind, containing * the same elements as c */ public static Collection createNewCollection( CollectionKind kind, Collection c) { switch (kind) { case SET_LITERAL: return new HashSet(c); case SEQUENCE_LITERAL: return new ArrayList(c); case BAG_LITERAL: return new BagImpl(c); case ORDERED_SET_LITERAL: return new LinkedHashSet(c); default: { String message = OCLMessages.bind( OCLMessages.OCLCollectionKindNotImpl_ERROR_, kind); IllegalArgumentException error = new IllegalArgumentException( message); OCLPlugin.throwing( CollectionUtil.class, "createNewCollection", error);//$NON-NLS-1$ throw error; } } } /** * Infers the OCL kind of a collection. * * @param c a collection (not null) * * @return its kind (likewise, not null) */ private static CollectionKind kindOf(Collection c) { CollectionKind result; if (c instanceof List){ result = CollectionKind.SEQUENCE_LITERAL; } else if (c instanceof LinkedHashSet) { result = CollectionKind.ORDERED_SET_LITERAL; } else if (c instanceof Set) { result = CollectionKind.SET_LITERAL; } else if (c instanceof Bag) { result = CollectionKind.BAG_LITERAL; } else { result = CollectionKind.COLLECTION_LITERAL; } return result; } /** * Computes the string representation of a collection value using syntax * like OCL's collection literals (e.g., OrderedSet{...}) instead * of Java's default (i.e., [...]). * * @param c a collection (not null) * @return the string representation of the specified collection * * @since 1.2 */ public static String toString(Collection c) { StringBuilder result = new StringBuilder(); result.append(kindOf(c).getName()); result.append('{'); boolean notFirst = false; for (Iterator iter = c.iterator();;) { if (iter.hasNext()) { if (notFirst) { result.append(", "); //$NON-NLS-1$ } else { notFirst = true; } Object next = iter.next(); if (next instanceof Collection) { // nested collection result.append(toString((Collection) next)); } else if (next instanceof String) { // string literal result.append('\'').append(next).append('\''); } else { result.append(next); } } else { break; } } result.append('}'); return result.toString(); } }