001: package org.andromda.translation.ocl.validation;
002:
003: import java.util.ArrayList;
004: import java.util.Arrays;
005: import java.util.Collection;
006: import java.util.Collections;
007: import java.util.HashSet;
008: import java.util.Iterator;
009: import java.util.List;
010: import java.util.Random;
011: import java.util.Set;
012: import java.util.TreeSet;
013:
014: import org.apache.commons.collections.Bag;
015: import org.apache.commons.collections.CollectionUtils;
016: import org.apache.commons.collections.Predicate;
017: import org.apache.commons.collections.SetUtils;
018: import org.apache.commons.collections.Transformer;
019: import org.apache.commons.collections.bag.HashBag;
020: import org.apache.commons.lang.StringUtils;
021:
022: /**
023: * Used to translated OCL collection expressions to their corresponding Java collection expressions.
024: */
025: public final class OCLCollections {
026: /**
027: * Counts the number of occurrences of the argument item in the source collection.
028: */
029: public static int count(final Collection collection, Object item) {
030: return collection == null ? 0 : CollectionUtils.cardinality(
031: item, collection);
032: }
033:
034: /**
035: * Return true if the object is not an element of the collection, false otherwise.
036: */
037: public static boolean excludes(final Collection collection,
038: final Object item) {
039: return collection == null || !collection.contains(item);
040: }
041:
042: /**
043: * Returns true if all elements of the parameter collection are not present in the current collection, false
044: * otherwise.
045: */
046: public static boolean excludesAll(final Collection collection,
047: final Collection items) {
048: boolean excludesAll = true;
049: for (final Iterator iterator = items.iterator(); iterator
050: .hasNext();) {
051: final Object object = iterator.next();
052: if (!excludes(collection, object)) {
053: excludesAll = false;
054: break;
055: }
056: }
057: return excludesAll;
058: }
059:
060: /**
061: * Returns true if the object is an element of the collection, false otherwise.
062: */
063: public static boolean includes(final Collection collection,
064: final Object item) {
065: return collection != null && collection.contains(item);
066: }
067:
068: /**
069: * Returns true if all elements of the parameter collection are present in the current collection, false otherwise.
070: */
071: public static boolean includesAll(final Collection collection,
072: final Collection items) {
073: return collection != null && collection.containsAll(items);
074: }
075:
076: /**
077: * Returns true if the collection contains no elements, false otherwise.
078: */
079: public static boolean isEmpty(final Collection collection) {
080: return (collection == null) || (collection.isEmpty());
081: }
082:
083: /**
084: * Returns true if the argument is <code>null</code>, false otherwise.
085: */
086: public static boolean isEmpty(final Object object) {
087: boolean isEmpty = object == null;
088: if (!isEmpty) {
089: if (object instanceof Collection) {
090: isEmpty = ((Collection) object).isEmpty();
091: } else if (object instanceof String) {
092: isEmpty = isEmpty((String) object);
093: } else if (object.getClass().isArray()) {
094: isEmpty = ((Object[]) object).length == 0;
095: }
096: }
097: return isEmpty;
098: }
099:
100: /**
101: * Returns true if the argument is either <code>null</code> or only contains whitespace characters, false
102: * otherwise.
103: */
104: public static boolean isEmpty(final String string) {
105: return StringUtils.isBlank(string);
106: }
107:
108: /**
109: * Returns true if the collection contains one or more elements, false otherwise.
110: */
111: public static boolean notEmpty(final Collection collection) {
112: return (collection != null) && !isEmpty(collection);
113: }
114:
115: /**
116: * Returns true if the argument is not <code>null</code>, false otherwise.
117: */
118: public static boolean notEmpty(final Object object) {
119: boolean notEmpty = object != null;
120: if (notEmpty) {
121: if (object instanceof Collection) {
122: notEmpty = !((Collection) object).isEmpty();
123: } else if (object instanceof String) {
124: notEmpty = notEmpty((String) object);
125: } else if (object.getClass().isArray()) {
126: notEmpty = ((Object[]) object).length > 0;
127: }
128: }
129: return notEmpty;
130: }
131:
132: /**
133: * Returns true if the argument is neither <code>null</code> nor only contains whitespace characters, false
134: * otherwise.
135: */
136: public static boolean notEmpty(final String string) {
137: return StringUtils.isNotBlank(string);
138: }
139:
140: /**
141: * Checks the instance of the <code>object</code> and makes sure its a Collection, if the object is a collection the
142: * size is checked and returned, if its NOT a collection, 0 is returned.
143: *
144: * @param object the object to check.
145: * @return the size of the collection
146: */
147: public static int size(final Object object) {
148: int size = 0;
149: if (object != null) {
150: if (object instanceof Collection) {
151: size = size((Collection) object);
152: } else if (object.getClass().isArray()) {
153: size = ((Object[]) object).length;
154: }
155: }
156: return size;
157: }
158:
159: /**
160: * Returns the number of elements in the collection.
161: */
162: public static int size(final Collection collection) {
163: int size = 0;
164: if (collection != null) {
165: size = collection.size();
166: }
167: return size;
168: }
169:
170: /**
171: * Returns the sum of all the element in the collection. Every element must extend java.lang.Number or this method
172: * will throw an exception.
173: *
174: * @param collection a collection containing only classes extending java.lang.Number
175: * @return the sum of all the elements in the collection
176: */
177: public static double sum(final Object collection) {
178: double sum = 0;
179: if (collection != null) {
180: if (collection instanceof Collection) {
181: sum = sum(collection);
182: } else if (collection.getClass().isArray()) {
183: sum = sum(Arrays.asList((Object[]) collection));
184: }
185: }
186: return sum;
187: }
188:
189: /**
190: * Returns the sum of all the element in the collection. Every element must extend java.lang.Number or this method
191: * will throw an exception.
192: *
193: * @param collection a collection containing only classes extending java.lang.Number
194: * @return the sum of all the elements in the collection
195: */
196: public static double sum(final Collection collection) {
197: double sum = 0;
198: if (collection != null && !collection.isEmpty()) {
199: for (final Iterator iterator = collection.iterator(); iterator
200: .hasNext();) {
201: Object object = iterator.next();
202: if (object instanceof Number) {
203: sum += ((Number) object).doubleValue();
204: } else {
205: throw new UnsupportedOperationException(
206: "In order to calculate the sum of a collection\'s elements "
207: + "all of them must extend java.lang.Number, found: "
208: + object.getClass().getName());
209: }
210: }
211: }
212: return sum;
213: }
214:
215: /**
216: * Appends the item to the list.
217: *
218: * @return true if the operation was a success
219: */
220: public static boolean append(final List list, final Object item) {
221: return list == null ? false : list.add(item);
222: }
223:
224: /**
225: * Insert the item into the first position of the list.
226: *
227: * @return the element previously at the first position
228: */
229: public static Object prepend(final List list, final Object item) {
230: return list.set(0, item);
231: }
232:
233: /**
234: * Appends the item to the bag.
235: *
236: * @return true if the operation was a success
237: */
238: public static boolean append(final Bag collection, final Object item) {
239: return collection == null ? false : collection.add(item);
240: }
241:
242: /**
243: * Returns the argument as a bag.
244: */
245: public static Bag asBag(final Collection collection) {
246: return collection == null ? new HashBag() : new HashBag(
247: collection);
248: }
249:
250: /**
251: * Returns the argument as an ordered set.
252: */
253: public static Set asOrderedSet(final Collection collection) {
254: return collection == null ? Collections.EMPTY_SET : SetUtils
255: .orderedSet(new TreeSet(collection));
256: }
257:
258: /**
259: * Returns the argument as a list.
260: */
261: public static List asSequence(final Collection collection) {
262: return collection == null ? Collections.EMPTY_LIST
263: : new ArrayList(collection);
264: }
265:
266: /**
267: * Returns the argument as a set.
268: */
269: public static Set asSet(final Collection collection) {
270: return collection == null ? Collections.EMPTY_SET
271: : new HashSet(collection);
272: }
273:
274: /**
275: * Returns the element at the specified index in the argument list.
276: */
277: public static Object at(final List list, final int index) {
278: return list == null ? null : list.get(index);
279: }
280:
281: /**
282: * Removes all occurrences of the item in the source collection.
283: *
284: * @return true if one or more elements were removed
285: */
286: public static boolean excluding(final Collection collection,
287: final Object item) {
288: return collection == null ? false : collection.remove(item);
289: }
290:
291: /**
292: * Adds the item to the list
293: *
294: * @return true if the element was added
295: */
296: public static boolean including(final Collection collection,
297: final Object item) {
298: return collection == null ? false : collection.add(item);
299: }
300:
301: /**
302: * Recursively flattens this collection, this method returns a Collection containing no nested Collection
303: * instances.
304: */
305: public static Collection flatten(final Collection collection) {
306: final Collection flattenedCollection = new ArrayList();
307: for (final Iterator iterator = collection.iterator(); iterator
308: .hasNext();) {
309: final Object object = iterator.next();
310: if (object instanceof Collection) {
311: flattenedCollection
312: .addAll(flatten((Collection) object));
313: } else {
314: flattenedCollection.add(object);
315: }
316: }
317:
318: return flattenedCollection;
319: }
320:
321: /**
322: * Returns the index in this list of the first occurrence of the specified element, or -1 if this list does not
323: * contain this element. More formally, returns the lowest index i such that (o == null ? get(i) = =null :
324: * o.equals(get(i))), or -1 if there is no such index.
325: */
326: public static int indexOf(final List collection, final Object item) {
327: return collection == null ? -1 : collection.indexOf(item);
328: }
329:
330: /**
331: * Insert the item at the specified index into the collection.
332: */
333: public static void insertAt(final List collection, int index,
334: Object item) {
335: collection.add(index, item);
336: }
337:
338: /**
339: * Returns the collection of elements common in both argument collections.
340: */
341: public static Collection intersection(final Collection first,
342: final Collection second) {
343: return CollectionUtils.intersection(first, second);
344: }
345:
346: /**
347: * Returns the union of both collections into a single collection.
348: */
349: public static Collection union(final Collection first,
350: final Collection second) {
351: return CollectionUtils.union(first, second);
352: }
353:
354: /**
355: * Returns the last element in the collection.
356: *
357: * @param object the collection or single instance which will be converted to a collection.
358: * @return the last object of the collection or the object itself if the object is not a collection instance (or
359: * null if the object is null or an empty collection).
360: */
361: public static Object last(final Object object) {
362: Object last = null;
363: final List list = objectToList(object);
364: if (!list.isEmpty()) {
365: last = list.get(list.size() - 1);
366: }
367: return last;
368: }
369:
370: /**
371: * Returns the first element in the collection.
372: *
373: * @param object the collection or single instance which will be converted to a collection.
374: * @return the first object of the collection or the object itself if the object is not a collection instance (or
375: * null if the object is null or an empty collection).
376: */
377: public static Object first(final Object object) {
378: Object first = null;
379: final List list = objectToList(object);
380: if (!list.isEmpty()) {
381: first = list.get(0);
382: }
383: return first;
384: }
385:
386: /**
387: * Returns those element that are contained in only one of both collections.
388: */
389: public static Collection symmetricDifference(
390: final Collection first, final Collection second) {
391: return CollectionUtils.disjunction(first, second);
392: }
393:
394: /**
395: * @todo: implement
396: */
397: public static Set subOrderedSet(final Set collection) {
398: throw new UnsupportedOperationException(OCLCollections.class
399: .getName()
400: + ".subOrderedSet");
401: }
402:
403: /**
404: * @todo: implement
405: */
406: public static List subSequence(final List collection) {
407: throw new UnsupportedOperationException(OCLCollections.class
408: .getName()
409: + ".subSequence");
410: }
411:
412: /**
413: * Returns a random element from the collection for which the argument expression evaluates true.
414: */
415: public static Object any(final Collection collection,
416: final Predicate predicate) {
417: final List selectedElements = new ArrayList(select(collection,
418: predicate));
419: final Random random = new Random(System.currentTimeMillis());
420: return selectedElements.isEmpty() ? null : selectedElements
421: .get(random.nextInt(selectedElements.size()));
422: }
423:
424: /**
425: * Returns the collection of Objects that results from executing the transformer on each individual element in the
426: * source collection.
427: */
428: public static Collection collect(final Collection collection,
429: final Transformer transformer) {
430: return CollectionUtils.collect(collection, transformer);
431: }
432:
433: /**
434: * @todo: implement
435: */
436: public static Collection collectNested(final Collection collection) {
437: throw new UnsupportedOperationException(OCLCollections.class
438: .getName()
439: + ".collectNested");
440: }
441:
442: /**
443: * Returns true if a predicate is true for at least one element of a collection. <p/>A null collection or predicate
444: * returns false.
445: */
446: public static boolean exists(final Collection collection,
447: final Predicate predicate) {
448: return CollectionUtils.exists(collection, predicate);
449: }
450:
451: /**
452: * Returns true if a predicate is true for at least one element of a collection. <p/>A null collection or predicate
453: * returns false.
454: */
455: public static boolean exists(final Object collection,
456: final Predicate predicate) {
457: return collection instanceof Collection ? exists(
458: (Collection) collection, predicate) : false;
459: }
460:
461: /**
462: * <p/>
463: * Executes every <code>predicate</code> for the given collectoin, if one evaluates to <code>false</code> this
464: * operation returns <code>false</code>, otherwise <code>true</code> is returned. </p> If the input collection or
465: * closure is null <code>false</code> is returned.
466: *
467: * @return true if every evaluated predicate returns true, false otherwise.
468: */
469: public static boolean forAll(final Collection collection,
470: final Predicate predicate) {
471: boolean valid = collection != null;
472: if (valid) {
473: for (final Iterator iterator = collection.iterator(); iterator
474: .hasNext();) {
475: final Object object = iterator.next();
476: valid = predicate.evaluate(object);
477: if (!valid) {
478: break;
479: }
480: }
481: }
482: return valid;
483: }
484:
485: /**
486: * <p/>
487: * Executes every <code>predicate</code> for the given collection, if one evaluates to <code>false</code> this
488: * operation returns <code>false</code>, otherwise <code>true</code> is returned. </p> If the input collection or
489: * closure is null <code>false</code> is returned.
490: *
491: * @return true if every evaluated predicate returns true, false otherwise.
492: */
493: public static boolean forAll(final Object collection,
494: final Predicate predicate) {
495: boolean valid = false;
496: if (collection instanceof Collection) {
497: valid = forAll((Collection) collection, predicate);
498: }
499: return valid;
500: }
501:
502: /**
503: * Returns <code>true</code> if the result of executing the <code>transformer</code> has a unique value for each
504: * element in the source collection.
505: */
506: public static boolean isUnique(final Collection collection,
507: final Transformer transformer) {
508: boolean unique = true;
509: final Set collected = new HashSet();
510: for (final Iterator iterator = collection.iterator(); iterator
511: .hasNext()
512: && unique;) {
513: final Object result = transformer
514: .transform(iterator.next());
515: if (collected.contains(result)) {
516: unique = false;
517: } else {
518: collected.add(result);
519: }
520: }
521: return unique;
522: }
523:
524: /**
525: * Returns <code>true</code> if the result of executing the <code>transformer</code> has a unique value for each
526: * element in the source collection.
527: */
528: public static boolean isUnique(final Object collection,
529: final Transformer transformer) {
530: boolean unique = collection != null;
531: if (unique
532: && Collection.class.isAssignableFrom(collection
533: .getClass())) {
534: unique = isUnique((Collection) collection, transformer);
535: }
536: return unique;
537: }
538:
539: /**
540: * @todo: implement
541: */
542: public static Collection iterate(final Collection collection) {
543: throw new UnsupportedOperationException(OCLCollections.class
544: .getName()
545: + ".iterate");
546: }
547:
548: /**
549: * Returns <code>true</true> when the argument expression evaluates true for one and only one element in the
550: * collection. Returns <code>false</code> otherwise.
551: */
552: public static boolean one(final Collection collection,
553: final Predicate predicate) {
554: boolean found = false;
555:
556: if (collection != null) {
557: for (final Iterator iterator = collection.iterator(); iterator
558: .hasNext();) {
559: if (predicate.evaluate(iterator.next())) {
560: if (found) {
561: found = false;
562: break;
563: }
564: found = true;
565: }
566: }
567: }
568: return found;
569: }
570:
571: /**
572: * <p/>
573: * Returns <code>true</true> if <code>collection</code> is actually a Collection instance and if the
574: * <code>predicate</code> expression evaluates true for one and only one element in the collection. Returns
575: * <code>false</code> otherwise. </p>
576: */
577: public static boolean one(final Object collection,
578: final Predicate predicate) {
579: return collection != null
580: && Collection.class.isAssignableFrom(collection
581: .getClass())
582: && one((Collection) collection, predicate);
583: }
584:
585: /**
586: * Returns a subcollection of the source collection containing all elements for which the expression evaluates
587: * <code>false</code>.
588: */
589: public static Collection reject(final Collection collection,
590: final Predicate predicate) {
591: return CollectionUtils.selectRejected(collection, predicate);
592: }
593:
594: /**
595: * Returns a subcollection of the source collection containing all elements for which the expression evaluates
596: * <code>true</code>.
597: */
598: public static Collection select(final Collection collection,
599: final Predicate predicate) {
600: return CollectionUtils.select(collection, predicate);
601: }
602:
603: /**
604: * Returns a subcollection of the source collection containing all elements for which the expression evaluates
605: * <code>true</code>.
606: */
607: public static Collection select(final Object collection,
608: final Predicate predicate) {
609: return CollectionUtils.select((Collection) collection,
610: predicate);
611: }
612:
613: /**
614: * @todo: implement
615: */
616: public static Collection sortedBy(final Collection collection) {
617: throw new UnsupportedOperationException(OCLCollections.class
618: .getName()
619: + ".sortedBy");
620: }
621:
622: /**
623: * Converts the given object to a java.util.List implementation. If the object is not a collection type, then the
624: * object is placed within a collection as the only element.
625: *
626: * @param object the object to convert.
627: * @return the new List.
628: */
629: private static List objectToList(Object object) {
630: List list = null;
631: if (object instanceof Collection) {
632: final Collection collection = (Collection) object;
633: if (!(object instanceof List)) {
634: object = new ArrayList(collection);
635: }
636: list = (List) object;
637: } else {
638: list = new ArrayList();
639: if (object != null) {
640: list.add(object);
641: }
642: }
643: return list;
644: }
645: }
|