Source for net.dpml.cli.util.Comparators

   1: /**
   2:  * Copyright 2003-2004 The Apache Software Foundation
   3:  * Copyright 2005 Stephen McConnell
   4:  *
   5:  * Licensed under the Apache License, Version 2.0 (the "License");
   6:  * you may not use this file except in compliance with the License.
   7:  * 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 net.dpml.cli.util;
  18: 
  19: import java.util.Comparator;
  20: import java.util.List;
  21: 
  22: import net.dpml.cli.Group;
  23: import net.dpml.cli.Option;
  24: import net.dpml.cli.option.Command;
  25: import net.dpml.cli.option.DefaultOption;
  26: import net.dpml.cli.option.Switch;
  27: 
  28: /**
  29:  * A collection of Comparators suitable for use with Option instances.
  30:  * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
  31:  * @version @PROJECT-VERSION@
  32:  */
  33: public final class Comparators 
  34: {
  35:     private Comparators()
  36:     {
  37:         // static
  38:     }
  39:     
  40:     /**
  41:      * Chains comparators together.
  42:      * 
  43:      * @see #chain(Comparator[])
  44:      * @param c0 a comparator
  45:      * @param c1 a comparator
  46:      * @return a chained comparator
  47:      */
  48:     public static Comparator chain( final Comparator c0, final Comparator c1 )
  49:     {
  50:         return chain( new Comparator[]{c0, c1} );
  51:     }
  52: 
  53:     /**
  54:      * Chains comparators together.
  55:      * 
  56:      * @see #chain(Comparator[])
  57:      * @param c0 a comparator
  58:      * @param c1 a comparator
  59:      * @param c2 a comparator
  60:      * @return a chained comparator
  61:      */
  62:     public static Comparator chain( final Comparator c0, final Comparator c1, final Comparator c2 )
  63:     {
  64:         return chain( new Comparator[]{c0, c1, c2} );
  65:     }
  66: 
  67:     /**
  68:      * Chains comparators together.
  69:      * 
  70:      * @see #chain(Comparator[])
  71:      * @param c0 a comparator
  72:      * @param c1 a comparator
  73:      * @param c2 a comparator
  74:      * @param c3 a comparator
  75:      * @return a chained comparator
  76:      */
  77:     public static Comparator chain( 
  78:       final Comparator c0, final Comparator c1, final Comparator c2, final Comparator c3 )
  79:     {
  80:         return chain( new Comparator[]{c0, c1, c2, c3} );
  81:     }
  82: 
  83:     /**
  84:      * Chains comparators together.
  85:      * 
  86:      * @see #chain(Comparator[])
  87:      * @param c0 a comparator
  88:      * @param c1 a comparator
  89:      * @param c2 a comparator
  90:      * @param c3 a comparator
  91:      * @param c4 a comparator
  92:      * @return a chained comparator
  93:      */
  94:     public static Comparator chain(
  95:       final Comparator c0, final Comparator c1, final Comparator c2, 
  96:       final Comparator c3, final Comparator c4 )
  97:     {
  98:         return chain( new Comparator[]{c0, c1, c2, c3, c4} );
  99:     }
 100: 
 101:     /**
 102:      * Chains comparators together.
 103:      * 
 104:      * @see #chain(Comparator[])
 105:      * @param comparators a List of comparators to chain together
 106:      * @return a chained comparator
 107:      */
 108:     public static Comparator chain( final List comparators )
 109:     {
 110:         return new Chain(
 111:           (Comparator[]) comparators.toArray(
 112:             new Comparator[ comparators.size() ] ) );
 113:     }
 114: 
 115:     /**
 116:      * Chains an array of comparators together. Each Comparator will be called
 117:      * in turn until one of them return a non-zero value, this value will be
 118:      * returned.
 119:      * 
 120:      * @param comparators the array of comparators
 121:      * @return a chained comparator
 122:      */
 123:     public static Comparator chain( final Comparator[] comparators ) 
 124:     {
 125:         return new Chain( comparators );
 126:     }
 127: 
 128:     /**
 129:      * Chains a series of Comparators together.
 130:      */
 131:     private static class Chain implements Comparator
 132:     {
 133:         private final Comparator[] m_chain;
 134: 
 135:         /**
 136:          * Creates a Comparator chain using the specified array of Comparators
 137:          * @param chain the Comparators in the chain
 138:          */
 139:         public Chain( final Comparator[] chain )
 140:         {
 141:             m_chain = new Comparator[ chain.length ];
 142:             System.arraycopy( chain, 0, m_chain, 0, chain.length );
 143:         }
 144:         
 145:        /**
 146:         * Compare two values.
 147:         * @param left the first value
 148:         * @param right the second value
 149:         * @return the result
 150:         */
 151:         public int compare( final Object left, final Object right )
 152:         {
 153:             int result = 0;
 154:             for( int i = 0; result == 0 && i < m_chain.length; ++i )
 155:             {
 156:                 result = m_chain[i].compare( left, right );
 157:             }
 158:             return result;
 159:         }
 160:     }
 161: 
 162:     /**
 163:      * Reverses a comparator's logic.
 164:      * 
 165:      * @param wrapped
 166:      *            the Comparator to reverse the logic of
 167:      * @return a comparator with reverse logic
 168:      */
 169:     private static Comparator reverse( final Comparator wrapped )
 170:     {
 171:         return new Reverse( wrapped );
 172:     }
 173: 
 174:    /**
 175:     * A reverse comparator.
 176:     */
 177:     private static class Reverse implements Comparator 
 178:     {
 179:         private final Comparator m_wrapped;
 180: 
 181:         /**
 182:          * Creates a Comparator with reverse logic
 183:          * @param wrapped the original logic
 184:          */
 185:         public Reverse( final Comparator wrapped )
 186:         {
 187:             m_wrapped = wrapped;
 188:         }
 189: 
 190:        /**
 191:         * Compare two values.
 192:         * @param left the first value
 193:         * @param right the second value
 194:         * @return the result
 195:         */
 196:         public int compare( final Object left, final Object right )
 197:         {
 198:             return -m_wrapped.compare( left, right );
 199:         }
 200:     }
 201: 
 202:     /**
 203:      * Forces Group instances to appear at the beginning of lists
 204:      * 
 205:      * @see Group
 206:      * @return a new comparator
 207:      */
 208:     public static Comparator groupFirst()
 209:     {
 210:         return new GroupFirst();
 211:     }
 212: 
 213:     /**
 214:      * Forces Group instances to appear at the end of lists
 215:      * 
 216:      * @see Group
 217:      * @return a new comparator
 218:      */
 219:     public static Comparator groupLast()
 220:     {
 221:         return reverse( groupFirst() );
 222:     }
 223: 
 224:    /**
 225:     * A group first comparator.
 226:     */
 227:     private static class GroupFirst implements Comparator 
 228:     {
 229:        /**
 230:         * Compare two values.
 231:         * @param left the first value
 232:         * @param right the second value
 233:         * @return the result
 234:         */
 235:         public int compare( final Object left, final Object right )
 236:         {
 237:             final boolean l = left instanceof Group;
 238:             final boolean r = right instanceof Group;
 239: 
 240:             if( l ^ r )
 241:             {
 242:                 if( l )
 243:                 {
 244:                     return -1;
 245:                 }
 246:                 return 1;
 247:             }
 248:             return 0;
 249:         }
 250:     }
 251: 
 252:     /**
 253:      * Forces Switch instances to appear at the beginning of lists
 254:      * 
 255:      * @see Switch
 256:      * @return a new comparator
 257:      */
 258:     public static Comparator switchFirst() 
 259:     {
 260:         return new SwitchFirst();
 261:     }
 262: 
 263:     /**
 264:      * Forces Switch instances to appear at the end of lists
 265:      * 
 266:      * @see Switch
 267:      * @return a new comparator
 268:      */
 269:     public static Comparator switchLast()
 270:     {
 271:         return reverse( switchFirst() );
 272:     }
 273: 
 274:    /**
 275:     * A switch first comparator.
 276:     */
 277:     private static class SwitchFirst implements Comparator 
 278:     {
 279:        /**
 280:         * Compare two values.
 281:         * @param left the first value
 282:         * @param right the second value
 283:         * @return the result
 284:         */
 285:         public int compare( final Object left, final Object right )
 286:         {
 287:             final boolean l = left instanceof Switch;
 288:             final boolean r = right instanceof Switch;
 289: 
 290:             if( l ^ r )
 291:             {
 292:                 if( l ) 
 293:                 {
 294:                     return -1;
 295:                 }
 296:                 return 1;
 297:             }
 298:             return 0;
 299:         }
 300:     }
 301: 
 302:     /**
 303:      * Forces Command instances to appear at the beginning of lists
 304:      * 
 305:      * @see Command
 306:      * @return a new comparator
 307:      */
 308:     public static Comparator commandFirst()
 309:     {
 310:         return new CommandFirst();
 311:     }
 312: 
 313:     /**
 314:      * Forces Command instances to appear at the end of lists
 315:      * 
 316:      * @see Command
 317:      * @return a new comparator
 318:      */
 319:     public static Comparator commandLast()
 320:     {
 321:         return reverse( commandFirst() );
 322:     }
 323: 
 324:    /**
 325:     * A command first comparator.
 326:     */
 327:     private static class CommandFirst implements Comparator
 328:     {
 329:        /**
 330:         * Compare two values.
 331:         * @param left the first value
 332:         * @param right the second value
 333:         * @return the result
 334:         */
 335:         public int compare( final Object left, final Object right )
 336:         {
 337:             final boolean l = left instanceof Command;
 338:             final boolean r = right instanceof Command;
 339: 
 340:             if( l ^ r )
 341:             {
 342:                 if( l )
 343:                 {
 344:                     return -1;
 345:                 }
 346:                 return 1;
 347:             }
 348:             return 0;
 349:         }
 350:     }
 351: 
 352:     /**
 353:      * Forces DefaultOption instances to appear at the beginning of lists
 354:      * 
 355:      * @see DefaultOption
 356:      * @return a new comparator
 357:      */
 358:     public static Comparator defaultOptionFirst()
 359:     {
 360:         return new DefaultOptionFirst();
 361:     }
 362: 
 363:     /**
 364:      * Forces DefaultOption instances to appear at the end of lists
 365:      * 
 366:      * @see DefaultOption
 367:      * @return a new comparator
 368:      */
 369:     public static Comparator defaultOptionLast()
 370:     {
 371:         return reverse( defaultOptionFirst() );
 372:     }
 373: 
 374:    /**
 375:     * An option first comparator.
 376:     */
 377:     private static class DefaultOptionFirst implements Comparator 
 378:     {
 379:        /**
 380:         * Compare two values.
 381:         * @param left the first value
 382:         * @param right the second value
 383:         * @return the result
 384:         */
 385:         public int compare( final Object left, final Object right )
 386:         {
 387:             final boolean l = left instanceof DefaultOption;
 388:             final boolean r = right instanceof DefaultOption;
 389: 
 390:             if( l ^ r )
 391:             {
 392:                 if( l )
 393:                 {
 394:                     return -1;
 395:                 }
 396:                 return 1;
 397:             }
 398:             return 0;
 399:         }
 400:     }
 401: 
 402:     /**
 403:      * Forces Comparators with a particular trigger to appear at the beginning
 404:      * of lists
 405:      * 
 406:      * @param name
 407:      *            the trigger name to select
 408:      * @see Option#getTriggers()
 409:      * @return a new comparator
 410:      */
 411:     public static Comparator namedFirst( final String name )
 412:     {
 413:         return new Named( name );
 414:     }
 415: 
 416:     /**
 417:      * Forces Comparators with a particular trigger to appear at the end of
 418:      * lists
 419:      * 
 420:      * @param name
 421:      *            the trigger name to select
 422:      * @see Option#getTriggers()
 423:      * @return a new comparator
 424:      */
 425:     public static Comparator namedLast( final String name )
 426:     {
 427:         return reverse( new Named( name ) );
 428:     }
 429: 
 430:    /**
 431:     * A named comparator.
 432:     */
 433:     private static class Named implements Comparator 
 434:     {
 435:         private final String m_name;
 436:         
 437:         /**
 438:          * Creates a Comparator that sorts a particular name high in order
 439:          * @param name the trigger name to select
 440:          */
 441:         public Named( final String name )
 442:         {
 443:             m_name = name;
 444:         }
 445:         
 446:        /**
 447:         * Compare two values.
 448:         * @param primary the first value
 449:         * @param secondary the second value
 450:         * @return the result
 451:         */
 452:         public int compare( final Object primary, final Object secondary )
 453:         {
 454:             final Option left = (Option) primary;
 455:             final Option right = (Option) secondary;
 456: 
 457:             final boolean l = left.getTriggers().contains( m_name );
 458:             final boolean r = right.getTriggers().contains( m_name );
 459: 
 460:             if( l ^ r )
 461:             {
 462:                 if( l )  
 463:                 {
 464:                     return -1;
 465:                 }
 466:                 return 1;
 467:             }
 468:             return 0;
 469:         }
 470:     }
 471: 
 472:     /**
 473:      * Orders Options by preferredName
 474:      * 
 475:      * @see Option#getPreferredName()
 476:      * @return a new comparator
 477:      */
 478:     public static Comparator preferredNameFirst()
 479:     {
 480:         return new PreferredName();
 481:     }
 482: 
 483:     /**
 484:      * Orders Options by preferredName, reversed
 485:      * 
 486:      * @see Option#getPreferredName()
 487:      * @return a new comparator
 488:      */
 489:     public static Comparator preferredNameLast()
 490:     {
 491:         return reverse( preferredNameFirst() );
 492:     }
 493: 
 494:    /**
 495:     * A preferred name comparator.
 496:     */
 497:     private static class PreferredName implements Comparator
 498:     {
 499:        /**
 500:         * Compare two values.
 501:         * @param primary the first value
 502:         * @param secondary the second value
 503:         * @return the result
 504:         */
 505:         public int compare( final Object primary, final Object secondary )
 506:         {
 507:             final Option left = (Option) primary;
 508:             final Option right = (Option) secondary;
 509:             return left.getPreferredName().compareTo( right.getPreferredName() );
 510:         }
 511:     }
 512: 
 513:     /**
 514:      * Orders Options grouping required Options first
 515:      * 
 516:      * @see Option#isRequired()
 517:      * @return a new comparator
 518:      */
 519:     public static Comparator requiredFirst()
 520:     {
 521:         return new Required();
 522:     }
 523:     
 524:     /**
 525:      * Orders Options grouping required Options last
 526:      * 
 527:      * @see Option#isRequired()
 528:      * @return a new comparator
 529:      */
 530:     public static Comparator requiredLast()
 531:     {
 532:         return reverse( requiredFirst() );
 533:     }
 534:     
 535:    /**
 536:     * A required comparator.
 537:     */
 538:     private static class Required implements Comparator
 539:     {
 540:        /**
 541:         * Compare two values.
 542:         * @param primary the first value
 543:         * @param secondary the second value
 544:         * @return the result
 545:         */
 546:         public int compare( final Object primary, final Object secondary )
 547:         {
 548:             final Option left = (Option) primary;
 549:             final Option right = (Option) secondary;
 550:             
 551:             final boolean l = left.isRequired();
 552:             final boolean r = right.isRequired();
 553: 
 554:             if( l ^ r )
 555:             {
 556:                 if( l )
 557:                 {
 558:                     return -1;
 559:                 }
 560:                 return 1;
 561:             }
 562:             return 0;
 563:         }
 564:     }
 565: }