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 }