View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.cli2.util;
18  
19  import java.util.Comparator;
20  import java.util.List;
21  
22  import org.apache.commons.cli2.Group;
23  import org.apache.commons.cli2.Option;
24  import org.apache.commons.cli2.option.Command;
25  import org.apache.commons.cli2.option.DefaultOption;
26  import org.apache.commons.cli2.option.Switch;
27  
28  /**
29   * A collection of Comparators suitable for use with Option instances.
30   */
31  public class Comparators {
32  
33      private Comparators(){
34          // constructor hiden from potential users
35      }
36  
37  
38      /**
39       * Chains comparators together.
40       *
41       * @see #chain(Comparator[])
42       * @param c0
43       *            a comparator
44       * @param c1
45       *            a comparator
46       * @return a chained comparator
47       */
48      public static Comparator chain(final Comparator c0, final Comparator c1) {
49          return chain(new Comparator[] { c0, c1 });
50      }
51  
52      /**
53       * Chains comparators together.
54       *
55       * @see #chain(Comparator[])
56       * @param c0
57       *            a comparator
58       * @param c1
59       *            a comparator
60       * @param c2
61       *            a comparator
62       * @return a chained comparator
63       */
64      public static Comparator chain(
65          final Comparator c0,
66          final Comparator c1,
67          final Comparator c2) {
68          return chain(new Comparator[] { c0, c1, c2 });
69      }
70  
71      /**
72       * Chains comparators together.
73       *
74       * @see #chain(Comparator[])
75       * @param c0
76       *            a comparator
77       * @param c1
78       *            a comparator
79       * @param c2
80       *            a comparator
81       * @param c3
82       *            a comparator
83       * @return a chained comparator
84       */
85      public static Comparator chain(
86          final Comparator c0,
87          final Comparator c1,
88          final Comparator c2,
89          final Comparator c3) {
90          return chain(new Comparator[] { c0, c1, c2, c3 });
91      }
92  
93      /**
94       * Chains comparators together.
95       *
96       * @see #chain(Comparator[])
97       * @param c0
98       *            a comparator
99       * @param c1
100      *            a comparator
101      * @param c2
102      *            a comparator
103      * @param c3
104      *            a comparator
105      * @param c4
106      *            a comparator
107      * @return a chained comparator
108      */
109     public static Comparator chain(
110         final Comparator c0,
111         final Comparator c1,
112         final Comparator c2,
113         final Comparator c3,
114         final Comparator c4) {
115         return chain(new Comparator[] { c0, c1, c2, c3, c4 });
116     }
117 
118     /**
119      * Chains comparators together.
120      *
121      * @see #chain(Comparator[])
122      * @param comparators
123      *            a List of comparators to chain together
124      * @return a chained comparator
125      */
126     public static Comparator chain(final List comparators) {
127         return new Chain(
128             (Comparator[])comparators.toArray(
129                 new Comparator[comparators.size()]));
130     }
131 
132     /**
133      * Chains an array of comparators together. Each Comparator will be called
134      * in turn until one of them return a non-zero value, this value will be
135      * returned.
136      *
137      * @param comparators
138      *            the array of comparators
139      * @return a chained comparator
140      */
141     public static Comparator chain(final Comparator[] comparators) {
142         return new Chain(comparators);
143     }
144 
145     /**
146      * Chains a series of Comparators together.
147      */
148     private static class Chain implements Comparator {
149 
150         final Comparator[] chain;
151 
152         /**
153          * Creates a Comparator chain using the specified array of Comparators
154          * @param chain the Comparators in the chain
155          */
156         public Chain(final Comparator[] chain) {
157             this.chain = new Comparator[chain.length];
158             System.arraycopy(chain, 0, this.chain, 0, chain.length);
159         }
160 
161         public int compare(final Object left, final Object right) {
162             int result = 0;
163             for (int i = 0; result == 0 && i < chain.length; ++i) {
164                 result = chain[i].compare(left, right);
165             }
166             return result;
167         }
168     }
169 
170     /**
171      * Reverses a comparator's logic.
172      *
173      * @param wrapped
174      *            the Comparator to reverse the logic of
175      * @return a comparator with reverse logic
176      */
177     private static Comparator reverse(final Comparator wrapped) {
178         return new Reverse(wrapped);
179     }
180 
181     private static class Reverse implements Comparator {
182         private final Comparator wrapped;
183 
184         /**
185          * Creates a Comparator with reverse logic
186          * @param wrapped the original logic
187          */
188         public Reverse(final Comparator wrapped) {
189             this.wrapped = wrapped;
190         }
191 
192         public int compare(final Object left, final Object right) {
193             return -wrapped.compare(left, right);
194         }
195     }
196 
197     /**
198      * Forces Group instances to appear at the beginning of lists
199      *
200      * @see Group
201      * @return a new comparator
202      */
203     public static Comparator groupFirst() {
204         return new GroupFirst();
205     }
206 
207     /**
208      * Forces Group instances to appear at the end of lists
209      *
210      * @see Group
211      * @return a new comparator
212      */
213     public static Comparator groupLast() {
214         return reverse(groupFirst());
215     }
216 
217     private static class GroupFirst implements Comparator {
218         public int compare(final Object left, final Object right) {
219             final boolean l = left instanceof Group;
220             final boolean r = right instanceof Group;
221 
222             if (l ^ r) {
223                 if (l) {
224                     return -1;
225                 }
226                 return 1;
227             }
228             return 0;
229         }
230     }
231 
232     /**
233      * Forces Switch instances to appear at the beginning of lists
234      *
235      * @see Switch
236      * @return a new comparator
237      */
238     public static Comparator switchFirst() {
239         return new SwitchFirst();
240     }
241 
242     /**
243      * Forces Switch instances to appear at the end of lists
244      *
245      * @see Switch
246      * @return a new comparator
247      */
248     public static Comparator switchLast() {
249         return reverse(switchFirst());
250     }
251 
252     private static class SwitchFirst implements Comparator {
253         public int compare(final Object left, final Object right) {
254             final boolean l = left instanceof Switch;
255             final boolean r = right instanceof Switch;
256 
257             if (l ^ r) {
258                 if (l) {
259                     return -1;
260                 }
261                 return 1;
262             }
263             return 0;
264         }
265     }
266 
267     /**
268      * Forces Command instances to appear at the beginning of lists
269      *
270      * @see Command
271      * @return a new comparator
272      */
273     public static Comparator commandFirst() {
274         return new CommandFirst();
275     }
276 
277     /**
278      * Forces Command instances to appear at the end of lists
279      *
280      * @see Command
281      * @return a new comparator
282      */
283     public static Comparator commandLast() {
284         return reverse(commandFirst());
285     }
286 
287     private static class CommandFirst implements Comparator {
288         public int compare(final Object left, final Object right) {
289             final boolean l = left instanceof Command;
290             final boolean r = right instanceof Command;
291 
292             if (l ^ r) {
293                 if (l) {
294                     return -1;
295                 }
296                 return 1;
297             }
298             return 0;
299         }
300     }
301 
302     /**
303      * Forces DefaultOption instances to appear at the beginning of lists
304      *
305      * @see DefaultOption
306      * @return a new comparator
307      */
308     public static Comparator defaultOptionFirst() {
309         return new DefaultOptionFirst();
310     }
311 
312     /**
313      * Forces DefaultOption instances to appear at the end of lists
314      *
315      * @see DefaultOption
316      * @return a new comparator
317      */
318     public static Comparator defaultOptionLast() {
319         return reverse(defaultOptionFirst());
320     }
321 
322     private static class DefaultOptionFirst implements Comparator {
323         public int compare(final Object left, final Object right) {
324             final boolean l = left instanceof DefaultOption;
325             final boolean r = right instanceof DefaultOption;
326 
327             if (l ^ r) {
328                 if (l) {
329                     return -1;
330                 }
331                 return 1;
332             }
333             return 0;
334         }
335     }
336 
337     /**
338      * Forces Comparators with a particular trigger to appear at the beginning
339      * of lists
340      *
341      * @param name
342      *            the trigger name to select
343      * @see Option#getTriggers()
344      * @return a new comparator
345      */
346     public static Comparator namedFirst(final String name) {
347         return new Named(name);
348     }
349 
350     /**
351      * Forces Comparators with a particular trigger to appear at the end of
352      * lists
353      *
354      * @param name
355      *            the trigger name to select
356      * @see Option#getTriggers()
357      * @return a new comparator
358      */
359     public static Comparator namedLast(final String name) {
360         return reverse(new Named(name));
361     }
362 
363     private static class Named implements Comparator {
364         private final String name;
365 
366         /**
367          * Creates a Comparator that sorts a particular name high in order
368          * @param name the trigger name to select
369          */
370         public Named(final String name) {
371             this.name = name;
372         }
373         public int compare(final Object oleft, final Object oright) {
374             final Option left = (Option)oleft;
375             final Option right = (Option)oright;
376 
377             final boolean l = left.getTriggers().contains(name);
378             final boolean r = right.getTriggers().contains(name);
379 
380             if (l ^ r) {
381                 if (l) {
382                     return -1;
383                 }
384                 return 1;
385             }
386             return 0;
387         }
388     }
389 
390     /**
391      * Orders Options by preferredName
392      *
393      * @see Option#getPreferredName()
394      * @return a new comparator
395      */
396     public static Comparator preferredNameFirst() {
397         return new PreferredName();
398     }
399 
400     /**
401      * Orders Options by preferredName, reversed
402      *
403      * @see Option#getPreferredName()
404      * @return a new comparator
405      */
406     public static Comparator preferredNameLast() {
407         return reverse(preferredNameFirst());
408     }
409 
410     private static class PreferredName implements Comparator {
411         public int compare(final Object oleft, final Object oright) {
412             final Option left = (Option)oleft;
413             final Option right = (Option)oright;
414 
415             return left.getPreferredName().compareTo(right.getPreferredName());
416         }
417     }
418 
419     /**
420      * Orders Options grouping required Options first
421      *
422      * @see Option#isRequired()
423      * @return a new comparator
424      */
425     public static Comparator requiredFirst() {
426         return new Required();
427     }
428 
429     /**
430      * Orders Options grouping required Options last
431      *
432      * @see Option#isRequired()
433      * @return a new comparator
434      */
435     public static Comparator requiredLast() {
436         return reverse(requiredFirst());
437     }
438 
439     private static class Required implements Comparator {
440         public int compare(final Object oleft, final Object oright) {
441             final Option left = (Option)oleft;
442             final Option right = (Option)oright;
443 
444             final boolean l = left.isRequired();
445             final boolean r = right.isRequired();
446 
447             if (l ^ r) {
448                 if (l) {
449                     return -1;
450                 }
451                 return 1;
452             }
453             return 0;
454         }
455     }
456 }