View Javadoc
1   package org.andromda.translation.ocl.validation;
2   
3   import java.util.ArrayList;
4   import java.util.Arrays;
5   import java.util.Collection;
6   import java.util.Collections;
7   import java.util.HashSet;
8   import java.util.Iterator;
9   import java.util.List;
10  import java.util.Random;
11  import java.util.Set;
12  import java.util.TreeSet;
13  import org.apache.commons.collections.Bag;
14  import org.apache.commons.collections.CollectionUtils;
15  import org.apache.commons.collections.Predicate;
16  import org.apache.commons.collections.SetUtils;
17  import org.apache.commons.collections.Transformer;
18  import org.apache.commons.collections.bag.HashBag;
19  import org.apache.commons.lang.StringUtils;
20  
21  /**
22   * Used to translated OCL collection expressions to their corresponding Java collection expressions.
23   */
24  public final class OCLCollections
25  {
26      /**
27       * Counts the number of occurrences of the argument item in the source collection.
28       * @param collection
29       * @param item
30       * @return CollectionUtils.cardinality(item, collection)
31       */
32      public static int count(
33              final Collection collection,
34              Object item)
35      {
36          return collection == null ? 0 : CollectionUtils.cardinality(item, collection);
37      }
38  
39      /**
40       * Return true if the object is not an element of the collection, false otherwise.
41       * @param collection
42       * @param item
43       * @return !collection.contains(item
44       */
45      public static boolean excludes(
46              final Collection collection,
47              final Object item)
48      {
49          return collection == null || !collection.contains(item);
50      }
51  
52      /**
53       * Returns true if all elements of the parameter collection are not present in the current collection, false
54       * otherwise.
55       * @param collection
56       * @param items
57       * @return excludesAll
58       */
59      public static boolean excludesAll(
60              final Collection collection,
61              final Collection items)
62      {
63          boolean excludesAll = true;
64          for (final Iterator iterator = items.iterator(); iterator.hasNext();)
65          {
66              final Object object = iterator.next();
67              if (!excludes(collection, object))
68              {
69                  excludesAll = false;
70                  break;
71              }
72          }
73          return excludesAll;
74      }
75  
76      /**
77       * Returns true if the object is an element of the collection, false otherwise.
78       * @param collection
79       * @param item
80       * @return collection.contains(item)
81       */
82      public static boolean includes(
83              final Collection collection,
84              final Object item)
85      {
86          return collection != null && collection.contains(item);
87      }
88  
89      /**
90       * Returns true if all elements of the parameter collection are present in the current collection, false otherwise.
91       * @param collection
92       * @param items
93       * @return collection.containsAll(items)
94       */
95      public static boolean includesAll(
96              final Collection collection,
97              final Collection items)
98      {
99          return collection != null && collection.containsAll(items);
100     }
101 
102     /**
103      * Returns true if the collection contains no elements, false otherwise.
104      * @param collection
105      * @return collection.isEmpty()
106      */
107     public static boolean isEmpty(final Collection collection)
108     {
109         return (collection == null) || (collection.isEmpty());
110     }
111 
112     /**
113      * Returns true if the argument is <code>null</code>, false otherwise.
114      * @param object
115      * @return isEmpty
116      */
117     public static boolean isEmpty(final Object object)
118     {
119         boolean isEmpty = object == null;
120         if (!isEmpty)
121         {
122             if (object instanceof Collection)
123             {
124                 isEmpty = ((Collection) object).isEmpty();
125             }
126             else if (object instanceof String)
127             {
128                 isEmpty = isEmpty((String) object);
129             }
130             else if (object != null && object.getClass().isArray())
131             {
132                 isEmpty = ((Object[]) object).length == 0;
133             }
134         }
135         return isEmpty;
136     }
137 
138     /**
139      * Returns true if the argument is either <code>null</code> or only contains whitespace characters, false
140      * otherwise.
141      * @param string
142      * @return isBlank(string)
143      */
144     public static boolean isEmpty(final String string)
145     {
146         return StringUtils.isBlank(string);
147     }
148 
149     /**
150      * Returns true if the collection contains one or more elements, false otherwise.
151      * @param collection
152      * @return isEmpty(collection)
153      */
154     public static boolean notEmpty(final Collection collection)
155     {
156         return (collection != null) && !isEmpty(collection);
157     }
158 
159     /**
160      * Returns true if the argument is not <code>null</code>, false otherwise.
161      * @param object
162      * @return notEmpty
163      */
164     public static boolean notEmpty(final Object object)
165     {
166         boolean notEmpty = object != null;
167         if (notEmpty)
168         {
169             if (object instanceof Collection)
170             {
171                 notEmpty = !((Collection) object).isEmpty();
172             }
173             else if (object instanceof String)
174             {
175                 notEmpty = notEmpty((String) object);
176             }
177             else if (object != null && object.getClass().isArray())
178             {
179                 notEmpty = ((Object[]) object).length > 0;
180             }
181         }
182         return notEmpty;
183     }
184 
185     /**
186      * Returns true if the argument is neither <code>null</code> nor only contains whitespace characters, false
187      * otherwise.
188      * @param string
189      * @return isNotBlank(string)
190      */
191     public static boolean notEmpty(final String string)
192     {
193         return StringUtils.isNotBlank(string);
194     }
195 
196     /**
197      * Checks the instance of the <code>object</code> and makes sure its a Collection, if the object is a collection the
198      * size is checked and returned, if its NOT a collection, 0 is returned.
199      *
200      * @param object the object to check.
201      * @return the size of the collection
202      */
203     public static int size(final Object object)
204     {
205         int size = 0;
206         if (object != null)
207         {
208             if (object instanceof Collection)
209             {
210                 size = size((Collection) object);
211             } else if (object.getClass().isArray())
212             {
213                 size = ((Object[]) object).length;
214             }
215         }
216         return size;
217     }
218 
219     /**
220      * Returns the number of elements in the collection.
221      * @param collection
222      * @return collection.size()
223      */
224     public static int size(final Collection collection)
225     {
226         int size = 0;
227         if (collection != null)
228         {
229             size = collection.size();
230         }
231         return size;
232     }
233 
234     /**
235      * Returns the sum of all the elements in the collection. Every element must extend Number or this method
236      * will throw an exception.
237      *
238      * @param collection a collection containing only classes extending Number
239      * @return the sum of all the elements in the collection
240      */
241     public static double sum(final Object collection)
242     {
243         double sum = 0;
244         if (collection != null)
245         {
246             if (collection instanceof Collection)
247             {
248                 // TODO Fix infinite loop
249                 sum = sum(collection);
250             }
251             else if (collection.getClass().isArray())
252             {
253                 sum = sum(Arrays.asList((Object[]) collection));
254             }
255         }
256         return sum;
257     }
258 
259     /**
260      * Returns the sum of all the element in the collection. Every element must extend Number or this method
261      * will throw an exception.
262      *
263      * @param collection a collection containing only classes extending Number
264      * @return the sum of all the elements in the collection
265      */
266     public static double sum(final Collection collection)
267     {
268         double sum = 0;
269         if (collection != null && !collection.isEmpty())
270         {
271             for (final Iterator iterator = collection.iterator(); iterator.hasNext();)
272             {
273                 Object object = iterator.next();
274                 if (object instanceof Number)
275                 {
276                     sum += ((Number) object).doubleValue();
277                 } else
278                 {
279                     throw new UnsupportedOperationException(
280                             "In order to calculate the sum of a collection\'s elements " +
281                                     "all of them must extend Number, found: " + object.getClass().getName());
282                 }
283             }
284         }
285         return sum;
286     }
287 
288     /**
289      * Appends the item to the list.
290      * @param list
291      * @param item
292      * @return true if the operation was a success
293      */
294     public static boolean append(
295             final List list,
296             final Object item)
297     {
298         return list == null ? false : list.add(item);
299     }
300 
301     /**
302      * Insert the item into the first position of the list.
303      * @param list
304      * @param item
305      * @return the element previously at the first position
306      */
307     public static Object prepend(
308             final List list,
309             final Object item)
310     {
311         return list.set(0, item);
312     }
313 
314     /**
315      * Appends the item to the bag.
316      * @param collection
317      * @param item
318      * @return true if the operation was a success
319      */
320     public static boolean append(
321             final Bag collection,
322             final Object item)
323     {
324         return collection == null ? false : collection.add(item);
325     }
326 
327     /**
328      * Returns the argument as a bag.
329      * @param collection
330      * @return new HashBag(collection)
331      */
332     public static Bag asBag(final Collection collection)
333     {
334         return collection == null ? new HashBag() : new HashBag(collection);
335     }
336 
337     /**
338      * Returns the argument as an ordered set.
339      * @param collection
340      * @return SetUtils.orderedSet(new TreeSet(collection))
341      */
342     public static Set asOrderedSet(final Collection collection)
343     {
344         return collection == null ? Collections.emptySet() : SetUtils.orderedSet(new TreeSet(collection));
345     }
346 
347     /**
348      * Returns the argument as a list.
349      * @param collection
350      * @return new ArrayList(collection)
351      */
352     public static List asSequence(final Collection collection)
353     {
354         return collection == null ? Collections.emptyList() : new ArrayList(collection);
355     }
356 
357     /**
358      * Returns the argument as a set.
359      * @param collection
360      * @return new HashSet(collection)
361      */
362     public static Set asSet(final Collection collection)
363     {
364         return collection == null ? Collections.emptySet() : new HashSet(collection);
365     }
366 
367     /**
368      * Returns the element at the specified index in the argument list.
369      * @param list
370      * @param index
371      * @return list.get(index)
372      */
373     public static Object at(
374             final List list,
375             final int index)
376     {
377         return list == null ? null : list.get(index);
378     }
379 
380     /**
381      * Removes all occurrences of the item in the source collection.
382      * @param collection
383      * @param item
384      * @return true if one or more elements were removed
385      */
386     public static boolean excluding(
387             final Collection collection,
388             final Object item)
389     {
390         return collection == null ? false : collection.remove(item);
391     }
392 
393     /**
394      * Adds the item to the list
395      * @param collection
396      * @param item
397      * @return true if the element was added
398      */
399     public static boolean including(
400             final Collection collection,
401             final Object item)
402     {
403         return collection == null ? false : collection.add(item);
404     }
405 
406     /**
407      * Recursively flattens this collection, this method returns a Collection containing no nested Collection
408      * instances.
409      * @param collection
410      * @return flattenedCollection.addAll(flatten((Collection) object))
411      */
412     public static Collection flatten(final Collection collection)
413     {
414         final Collection flattenedCollection = new ArrayList();
415         for (final Iterator iterator = collection.iterator(); iterator.hasNext();)
416         {
417             final Object object = iterator.next();
418             if (object instanceof Collection)
419             {
420                 flattenedCollection.addAll(flatten((Collection) object));
421             }
422             else
423             {
424                 flattenedCollection.add(object);
425             }
426         }
427 
428         return flattenedCollection;
429     }
430 
431     /**
432      * Returns the index in this list of the first occurrence of the specified element, or -1 if this list does not
433      * contain this element. More formally, returns the lowest index i such that (o == null ? get(i) = =null :
434      * o.equals(get(i))), or -1 if there is no such index.
435      * @param collection
436      * @param item
437      * @return collection.indexOf(item)
438      */
439     public static int indexOf(
440             final List collection,
441             final Object item)
442     {
443         return collection == null ? -1 : collection.indexOf(item);
444     }
445 
446     /**
447      * Insert the item at the specified index into the collection.
448      * @param collection
449      * @param index
450      * @param item
451      */
452     public static void insertAt(
453             final List collection,
454             int index,
455             Object item)
456     {
457         collection.add(index, item);
458     }
459 
460     /**
461      * Returns the collection of elements common in both argument collections.
462      * @param first
463      * @param second
464      * @return CollectionUtils.intersection(first, second)
465      */
466     public static Collection intersection(
467             final Collection first,
468             final Collection second)
469     {
470         return CollectionUtils.intersection(first, second);
471     }
472 
473     /**
474      * Returns the union of both collections into a single collection.
475      * @param first
476      * @param second
477      * @return CollectionUtils.union(first, second)
478      */
479     public static Collection union(
480             final Collection first,
481             final Collection second)
482     {
483         return CollectionUtils.union(first, second);
484     }
485 
486     /**
487      * Returns the last element in the collection.
488      *
489      * @param object the collection or single instance which will be converted to a collection.
490      * @return the last object of the collection or the object itself if the object is not a collection instance (or
491      *         null if the object is null or an empty collection).
492      */
493     public static Object last(final Object object)
494     {
495         Object last = null;
496         final List list = objectToList(object);
497         if (!list.isEmpty())
498         {
499             last = list.get(list.size() - 1);
500         }
501         return last;
502     }
503 
504     /**
505      * Returns the first element in the collection.
506      *
507      * @param object the collection or single instance which will be converted to a collection.
508      * @return the first object of the collection or the object itself if the object is not a collection instance (or
509      *         null if the object is null or an empty collection).
510      */
511     public static Object first(final Object object)
512     {
513         Object first = null;
514         final List list = objectToList(object);
515         if (!list.isEmpty())
516         {
517             first = list.get(0);
518         }
519         return first;
520     }
521 
522     /**
523      * Returns those element that are contained in only one of both collections.
524      * @param first
525      * @param second
526      * @return CollectionUtils.disjunction(first, second)
527      */
528     public static Collection symmetricDifference(
529             final Collection first,
530             final Collection second)
531     {
532         return CollectionUtils.disjunction(first, second);
533     }
534 
535     /**
536      * TODO: implement
537      * @param collection
538      * @return UnsupportedOperationException
539      */
540     public static Set subOrderedSet(final Set collection)
541     {
542         throw new UnsupportedOperationException(OCLCollections.class.getName() + ".subOrderedSet");
543     }
544 
545     /**
546      * TODO: implement
547      * @param collection
548      * @return UnsupportedOperationException
549      */
550     public static List subSequence(final List collection)
551     {
552         throw new UnsupportedOperationException(OCLCollections.class.getName() + ".subSequence");
553     }
554 
555     /**
556      * Returns a random element from the collection for which the argument expression evaluates true.
557      * @param collection
558      * @param predicate
559      * @return selectedElements.get(random.nextInt(selectedElements.size())
560      */
561     public static Object any(
562             final Collection collection,
563             final Predicate predicate)
564     {
565         final List selectedElements = new ArrayList(select(collection, predicate));
566         final Random random = new Random(System.currentTimeMillis());
567         return selectedElements.isEmpty() ? null : selectedElements.get(random.nextInt(selectedElements.size()));
568     }
569 
570     /**
571      * Returns the collection of Objects that results from executing the transformer on each individual element in the
572      * source collection.
573      * @param collection
574      * @param transformer
575      * @return CollectionUtils.collect(collection, transformer)
576      */
577     public static Collection collect(
578             final Collection collection,
579             final Transformer transformer)
580     {
581         return CollectionUtils.collect(collection, transformer);
582     }
583 
584     /**
585      * TODO: implement
586      * @param collection
587      * @return UnsupportedOperationException
588      */
589     public static Collection collectNested(final Collection collection)
590     {
591         throw new UnsupportedOperationException(OCLCollections.class.getName() + ".collectNested");
592     }
593 
594     /**
595      * Returns true if a predicate is true for at least one element of a collection. <p/>A null collection or predicate
596      * returns false.
597      * @param collection
598      * @param predicate
599      * @return CollectionUtils.exists(collection, predicate)
600      */
601     public static boolean exists(
602             final Collection collection,
603             final Predicate predicate)
604     {
605         return CollectionUtils.exists(collection, predicate);
606     }
607 
608     /**
609      * Returns true if a predicate is true for at least one element of a collection. <p/>A null collection or predicate
610      * returns false.
611      * @param collection
612      * @param predicate
613      * @return exists((Collection) collection, predicate)
614      */
615     public static boolean exists(
616             final Object collection,
617             final Predicate predicate)
618     {
619         return collection instanceof Collection ? exists((Collection) collection, predicate) : false;
620     }
621 
622     /**
623      * <p/>
624      * Executes every <code>predicate</code> for the given collectoin, if one evaluates to <code>false</code> this
625      * operation returns <code>false</code>, otherwise <code>true</code> is returned. </p> If the input collection or
626      * closure is null <code>false</code> is returned.
627      * @param collection
628      * @param predicate
629      * @return true if every evaluated predicate returns true, false otherwise.
630      */
631     public static boolean forAll(
632             final Collection collection,
633             final Predicate predicate)
634     {
635         boolean valid = collection != null;
636         if (valid && collection != null)
637         {
638             for (final Iterator iterator = collection.iterator(); iterator.hasNext();)
639             {
640                 final Object object = iterator.next();
641                 valid = predicate.evaluate(object);
642                 if (!valid)
643                 {
644                     break;
645                 }
646             }
647         }
648         return valid;
649     }
650 
651     /**
652      * <p/>
653      * Executes every <code>predicate</code> for the given collection, if one evaluates to <code>false</code> this
654      * operation returns <code>false</code>, otherwise <code>true</code> is returned. </p> If the input collection or
655      * closure is null <code>false</code> is returned.
656      * @param collection
657      * @param predicate
658      *
659      * @return true if every evaluated predicate returns true, false otherwise.
660      */
661     public static boolean forAll(
662             final Object collection,
663             final Predicate predicate)
664     {
665         boolean valid = false;
666         if (collection instanceof Collection)
667         {
668             valid = forAll((Collection) collection, predicate);
669         }
670         return valid;
671     }
672 
673     /**
674      * Returns <code>true</code> if the result of executing the <code>transformer</code> has a unique value for each
675      * element in the source collection.
676      * @param collection
677      * @param transformer
678      * @return unique
679      */
680     public static boolean isUnique(
681             final Collection collection,
682             final Transformer transformer)
683     {
684         boolean unique = true;
685         final Set collected = new HashSet();
686         for (final Iterator iterator = collection.iterator(); iterator.hasNext() && unique;)
687         {
688             final Object result = transformer.transform(iterator.next());
689             if (collected.contains(result))
690             {
691                 unique = false;
692             }
693             else
694             {
695                 collected.add(result);
696             }
697         }
698         return unique;
699     }
700 
701     /**
702      * Returns <code>true</code> if the result of executing the <code>transformer</code> has a unique value for each
703      * element in the source collection.
704      * @param collection
705      * @param transformer
706      * @return isUnique
707      */
708     public static boolean isUnique(
709             final Object collection,
710             final Transformer transformer)
711     {
712         boolean unique = collection != null;
713         if (unique && collection != null && Collection.class.isAssignableFrom(collection.getClass()))
714         {
715             unique = isUnique((Collection) collection, transformer);
716         }
717         return unique;
718     }
719 
720     /**
721      * TODO: implement
722      * @param collection
723      * @return UnsupportedOperationException
724      */
725     public static Collection iterate(final Collection collection)
726     {
727         throw new UnsupportedOperationException(OCLCollections.class.getName() + ".iterate");
728     }
729 
730     /**
731      * Returns <code>true</true> when the argument expression evaluates true for one and only one element in the
732      * collection. Returns <code>false</code> otherwise.
733      * @param collection
734      * @param predicate
735      * @return found
736      */
737     public static boolean one(
738             final Collection collection,
739             final Predicate predicate)
740     {
741         boolean found = false;
742 
743         if (collection != null)
744         {
745             for (final Iterator iterator = collection.iterator(); iterator.hasNext();)
746             {
747                 if (predicate.evaluate(iterator.next()))
748                 {
749                     if (found)
750                     {
751                         found = false;
752                         break;
753                     }
754                     found = true;
755                 }
756             }
757         }
758         return found;
759     }
760 
761     /**
762      * <p/>
763      * Returns <code>true</true> if <code>collection</code> is actually a Collection instance and if the
764      * <code>predicate</code> expression evaluates true for one and only one element in the collection. Returns
765      * <code>false</code> otherwise. </p>
766      * @param collection
767      * @param predicate
768      * @return one((Collection) collection, predicate)
769      */
770     public static boolean one(
771             final Object collection,
772             final Predicate predicate)
773     {
774         return collection != null && Collection.class.isAssignableFrom(collection.getClass()) &&
775                 one((Collection) collection, predicate);
776     }
777 
778     /**
779      * Returns a subcollection of the source collection containing all elements for which the expression evaluates
780      * <code>false</code>.
781      * @param collection
782      * @param predicate
783      * @return CollectionUtils.selectRejected(collection, predicate)
784      */
785     public static Collection reject(
786             final Collection collection,
787             final Predicate predicate)
788     {
789         return CollectionUtils.selectRejected(collection, predicate);
790     }
791 
792     /**
793      * Returns a subcollection of the source collection containing all elements for which the expression evaluates
794      * <code>true</code>.
795      * @param collection
796      * @param predicate
797      * @return CollectionUtils.select(collection, predicate)
798      */
799     public static Collection select(
800             final Collection collection,
801             final Predicate predicate)
802     {
803         return CollectionUtils.select(collection, predicate);
804     }
805 
806     /**
807      * Returns a subcollection of the source collection containing all elements for which the expression evaluates
808      * <code>true</code>.
809      * @param collection
810      * @param predicate
811      * @return CollectionUtils.select((Collection) collection, predicate)
812      */
813     public static Collection select(
814             final Object collection,
815             final Predicate predicate)
816     {
817         return CollectionUtils.select((Collection) collection, predicate);
818     }
819 
820     /**
821      * TODO: implement
822      * @param collection
823      * @return UnsupportedOperationException
824      */
825     public static Collection sortedBy(final Collection collection)
826     {
827         throw new UnsupportedOperationException(OCLCollections.class.getName() + ".sortedBy");
828     }
829 
830     /**
831      * Converts the given object to a java.util.List implementation. If the object is not a collection type, then the
832      * object is placed within a collection as the only element.
833      *
834      * @param object the object to convert.
835      * @return the new List.
836      */
837     private static List objectToList(Object object)
838     {
839         List list = null;
840         if (object instanceof Collection)
841         {
842             final Collection collection = (Collection) object;
843             if (!(object instanceof List))
844             {
845                 object = new ArrayList(collection);
846             }
847             list = (List) object;
848         } else
849         {
850             list = new ArrayList();
851             if (object != null)
852             {
853                 list.add(object);
854             }
855         }
856         return list;
857     }
858 }