001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.cli2.util; 018 019import java.util.Comparator; 020import java.util.List; 021 022import org.apache.commons.cli2.Group; 023import org.apache.commons.cli2.Option; 024import org.apache.commons.cli2.option.Command; 025import org.apache.commons.cli2.option.DefaultOption; 026import org.apache.commons.cli2.option.Switch; 027 028/** 029 * A collection of Comparators suitable for use with Option instances. 030 */ 031public class Comparators { 032 033 private Comparators(){ 034 // constructor hiden from potential users 035 } 036 037 038 /** 039 * Chains comparators together. 040 * 041 * @see #chain(Comparator[]) 042 * @param c0 043 * a comparator 044 * @param c1 045 * a comparator 046 * @return a chained comparator 047 */ 048 public static Comparator chain(final Comparator c0, final Comparator c1) { 049 return chain(new Comparator[] { c0, c1 }); 050 } 051 052 /** 053 * Chains comparators together. 054 * 055 * @see #chain(Comparator[]) 056 * @param c0 057 * a comparator 058 * @param c1 059 * a comparator 060 * @param c2 061 * a comparator 062 * @return a chained comparator 063 */ 064 public static Comparator chain( 065 final Comparator c0, 066 final Comparator c1, 067 final Comparator c2) { 068 return chain(new Comparator[] { c0, c1, c2 }); 069 } 070 071 /** 072 * Chains comparators together. 073 * 074 * @see #chain(Comparator[]) 075 * @param c0 076 * a comparator 077 * @param c1 078 * a comparator 079 * @param c2 080 * a comparator 081 * @param c3 082 * a comparator 083 * @return a chained comparator 084 */ 085 public static Comparator chain( 086 final Comparator c0, 087 final Comparator c1, 088 final Comparator c2, 089 final Comparator c3) { 090 return chain(new Comparator[] { c0, c1, c2, c3 }); 091 } 092 093 /** 094 * Chains comparators together. 095 * 096 * @see #chain(Comparator[]) 097 * @param c0 098 * a comparator 099 * @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}