001 /* 002 * Copyright 2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.station.console; 020 021 import java.io.IOException; 022 import java.io.InputStreamReader; 023 import java.io.BufferedReader; 024 import java.lang.reflect.InvocationTargetException; 025 import java.net.URI; 026 import java.net.URL; 027 import java.rmi.RemoteException; 028 import java.rmi.ConnectException; 029 import java.rmi.registry.LocateRegistry; 030 import java.rmi.registry.Registry; 031 import java.rmi.server.UnicastRemoteObject; 032 import java.util.ArrayList; 033 import java.util.List; 034 import java.util.Iterator; 035 import java.util.Set; 036 import java.util.HashSet; 037 import java.util.Properties; 038 039 import net.dpml.station.Application; 040 import net.dpml.station.Manager; 041 import net.dpml.station.Station; 042 import net.dpml.station.StationException; 043 import net.dpml.station.info.StartupPolicy; 044 import net.dpml.station.ApplicationRegistry; 045 import net.dpml.station.info.ApplicationDescriptor; 046 import net.dpml.station.server.RemoteApplicationRegistry; 047 import net.dpml.station.server.OutputStreamReader; 048 import net.dpml.station.server.ErrorStreamReader; 049 050 import net.dpml.component.Provider; 051 052 import net.dpml.state.State; 053 import net.dpml.state.Operation; 054 import net.dpml.state.Transition; 055 import net.dpml.state.Interface; 056 057 import net.dpml.transit.Artifact; 058 import net.dpml.util.Logger; 059 import net.dpml.lang.PID; 060 import net.dpml.transit.Disposable; 061 import net.dpml.lang.ValueDirective; 062 import net.dpml.util.ExceptionHelper; 063 import net.dpml.util.PropertyResolver; 064 065 import net.dpml.lang.UnknownKeyException; 066 import net.dpml.lang.DuplicateKeyException; 067 068 import net.dpml.cli.Option; 069 import net.dpml.cli.Group; 070 import net.dpml.cli.CommandLine; 071 import net.dpml.cli.commandline.Parser; 072 import net.dpml.cli.util.HelpFormatter; 073 import net.dpml.cli.OptionException; 074 import net.dpml.cli.DisplaySetting; 075 import net.dpml.cli.builder.ArgumentBuilder; 076 import net.dpml.cli.builder.GroupBuilder; 077 import net.dpml.cli.builder.DefaultOptionBuilder; 078 import net.dpml.cli.builder.CommandBuilder; 079 import net.dpml.cli.option.PropertyOption; 080 import net.dpml.cli.validation.EnumValidator; 081 import net.dpml.cli.validation.URIValidator; 082 import net.dpml.cli.validation.NumberValidator; 083 084 085 /** 086 * Plugin that handles station commands. 087 * 088 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 089 * @version 1.0.3 090 */ 091 public class StationPlugin implements Disposable 092 { 093 // ------------------------------------------------------------------------ 094 // state 095 // ------------------------------------------------------------------------ 096 097 private final Logger m_logger; 098 099 private boolean m_flag = false; // true if we have to take down the registry on exit 100 101 private ApplicationRegistry m_registry; // contains the ref to the registry used during disposal 102 103 // ------------------------------------------------------------------------ 104 // constructor 105 // ------------------------------------------------------------------------ 106 107 /** 108 * Creation of a new station plugin. The station plugin handles console 109 * based commmandline interaction with the application registry and a 110 * server station. 111 * 112 * @param logger the assigned logging channel 113 * @param args command line arguments 114 * @exception Exception if an error occurs during plugin establishment 115 */ 116 public StationPlugin( Logger logger, String[] args ) throws Exception 117 { 118 m_logger = logger; 119 120 ClassLoader context = Station.class.getClassLoader(); 121 Thread.currentThread().setContextClassLoader( context ); 122 123 // log the raw arguments 124 125 if( m_logger.isDebugEnabled() ) 126 { 127 logRawArguments( logger, args ); 128 } 129 130 // handle commands 131 132 Parser parser = new Parser(); 133 parser.setGroup( COMMAND_GROUP ); 134 135 try 136 { 137 CommandLine line = parser.parse( args ); 138 if( line.hasOption( HELP_COMMAND ) ) 139 { 140 processHelp(); 141 } 142 else if( line.hasOption( STARTUP_COMMAND ) ) 143 { 144 processStartup( line ); 145 } 146 else if( line.hasOption( SHUTDOWN_COMMAND ) ) 147 { 148 processShutdown( line ); 149 } 150 else if( line.hasOption( ADD_COMMAND ) ) 151 { 152 processAddCommand( line ); 153 } 154 else if( line.hasOption( SET_COMMAND ) ) 155 { 156 processSetCommand( line ); 157 } 158 else if( line.hasOption( INFO_COMMAND ) ) 159 { 160 processInfoCommand( line ); 161 } 162 else if( line.hasOption( START_COMMAND ) ) 163 { 164 processStartCommand( line ); 165 } 166 else if( line.hasOption( CONTROL_COMMAND ) ) 167 { 168 processControlCommand( line ); 169 } 170 else if( line.hasOption( STOP_COMMAND ) ) 171 { 172 processStopCommand( line ); 173 } 174 else if( line.hasOption( RESTART_COMMAND ) ) 175 { 176 processRestartCommand( line ); 177 } 178 else if( line.hasOption( REMOVE_COMMAND ) ) 179 { 180 processRemoveCommand( line ); 181 } 182 else 183 { 184 List options = line.getOptions(); 185 Iterator iterator = options.iterator(); 186 while( iterator.hasNext() ) 187 { 188 Option option = (Option) iterator.next(); 189 System.out.println( 190 "# UNPROCESSED OPTION: " 191 + option 192 + " [" 193 + option.getId() 194 + "]" ); 195 } 196 } 197 } 198 catch( OptionException e ) 199 { 200 m_logger.error( e.getMessage() ); 201 } 202 } 203 204 // ------------------------------------------------------------------------ 205 // Disposable 206 // ------------------------------------------------------------------------ 207 208 /** 209 * Initiate disposal of the station plugin. If the pugin has established 210 * the applications registry (occurs if the station is not running as a remote 211 * process and the implementation loads the application repository). 212 */ 213 public void dispose() 214 { 215 if( m_flag && ( null != m_registry ) ) 216 { 217 getLogger().debug( "retracting registry from rmi" ); 218 try 219 { 220 UnicastRemoteObject.unexportObject( m_registry, true ); 221 m_registry = null; 222 } 223 catch( Throwable e ) 224 { 225 e.printStackTrace(); 226 } 227 } 228 } 229 230 // ------------------------------------------------------------------------ 231 // commandline interegation 232 // ------------------------------------------------------------------------ 233 234 private Manager getManager( CommandLine line ) throws Exception 235 { 236 int port = getPortValue( line, Registry.REGISTRY_PORT ); 237 Registry registry = getLocalRegistry( port ); 238 if( null != registry ) 239 { 240 try 241 { 242 return (Manager) registry.lookup( Station.STATION_KEY ); 243 } 244 catch( ConnectException e ) 245 { 246 throw e; 247 } 248 catch( Exception e ) 249 { 250 System.out.println( "# ERROR: " + e ); 251 final String error = 252 "Unable to locate station."; 253 throw new StationException( error, e ); 254 } 255 } 256 else 257 { 258 final String error = 259 "Unable to locate station."; 260 throw new StationException( error ); 261 } 262 } 263 264 private URI getRegistryURI( CommandLine line ) 265 { 266 if( line.hasOption( REGISTRY_URI_OPTION ) ) 267 { 268 return null; 269 } 270 else 271 { 272 return (URI) line.getValue( REGISTRY_URI_OPTION, null ); 273 } 274 } 275 276 private URI getConfigurationURI( CommandLine line, URI fallback ) 277 { 278 if( line.hasOption( CONFIGURATION_URI_OPTION ) ) 279 { 280 return fallback; 281 } 282 else 283 { 284 return (URI) line.getValue( CONFIGURATION_URI_OPTION, fallback ); 285 } 286 } 287 288 /** 289 * Return a properties instance composed of the <tt>-D<key>=<value></tt> 290 * commandline arguments. 291 * @param line the commandline 292 * @return the resolved properties 293 */ 294 private Properties getCommandLineProperties( CommandLine line, Properties properties ) 295 { 296 Set propertyValue = line.getProperties(); 297 Iterator iterator = propertyValue.iterator(); 298 while( iterator.hasNext() ) 299 { 300 String name = (String) iterator.next(); 301 String value = line.getProperty( name ); 302 properties.setProperty( name, value ); 303 } 304 return properties; 305 } 306 307 /** 308 * Return the basedir option value. 309 * @param line the commandline 310 * @return the base path 311 */ 312 private String getBasedir( CommandLine line, String current ) 313 { 314 return (String) line.getValue( BASEDIR_OPTION, current ); 315 } 316 317 /** 318 * Get the application title. 319 * @param line the commandline 320 * @param title a default title if no title specified on the commandline 321 * @return the application title 322 */ 323 private String getTitle( CommandLine line, String title ) 324 { 325 return (String) line.getValue( TITLE_OPTION, title ); 326 } 327 328 /** 329 * Return the startup policy declared on the commandline. 330 * @param line the commandline 331 * @param policy the default policy to apply 332 */ 333 private StartupPolicy getStartupPolicy( CommandLine line, StartupPolicy policy ) 334 { 335 final String policyValue = (String) line.getValue( STARTUP_POLICY_OPTION, null ); 336 if( null == policyValue ) 337 { 338 return policy; 339 } 340 else 341 { 342 return StartupPolicy.parse( policyValue ); 343 } 344 } 345 346 private int getPortValue( CommandLine line, int defaultPort ) 347 { 348 if( line.hasOption( PORT_OPTION ) ) 349 { 350 Number number = (Number) line.getValue( PORT_OPTION, null ); 351 if( null != number ) 352 { 353 return number.intValue(); 354 } 355 } 356 return defaultPort; 357 } 358 359 private int getStartupTimeout( CommandLine line, int fallback ) 360 { 361 if( line.hasOption( STARTUP_TIMEOUT_OPTION ) ) 362 { 363 Number number = (Number) line.getValue( STARTUP_TIMEOUT_OPTION, null ); 364 if( null != number ) 365 { 366 return number.intValue(); 367 } 368 } 369 return fallback; 370 } 371 372 private int getShutdownTimeout( CommandLine line, int fallback ) 373 { 374 if( line.hasOption( SHUTDOWN_TIMEOUT_OPTION ) ) 375 { 376 Number number = (Number) line.getValue( SHUTDOWN_TIMEOUT_OPTION, null ); 377 if( null != number ) 378 { 379 return number.intValue(); 380 } 381 } 382 return fallback; 383 } 384 385 private ApplicationRegistry getApplicationRegistry( CommandLine line ) throws Exception 386 { 387 URI uri = getRegistryURI( line ); 388 if( null != uri ) 389 { 390 return getApplicationRegistry( uri ); 391 } 392 else 393 { 394 try 395 { 396 Manager manager = getManager( line ); 397 getLogger().debug( "using remote registry" ); 398 return manager.getApplicationRegistry(); 399 } 400 catch( Exception e ) 401 { 402 getLogger().debug( "using local registry" ); 403 return getApplicationRegistry( (URI) null ); 404 } 405 } 406 } 407 408 // ------------------------------------------------------------------------ 409 // command handling 410 // ------------------------------------------------------------------------ 411 412 /** 413 * List general command help to the console. 414 * @exception IOException if an I/O error occurs 415 */ 416 private void processHelp() throws IOException 417 { 418 HelpFormatter formatter = new HelpFormatter( 419 HelpFormatter.DEFAULT_GUTTER_LEFT, 420 HelpFormatter.DEFAULT_GUTTER_CENTER, 421 HelpFormatter.DEFAULT_GUTTER_RIGHT, 422 100, 50 ); 423 424 formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_GROUP_OUTER ); 425 formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION ); 426 formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED ); 427 428 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL ); 429 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_GROUP_OUTER ); 430 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION ); 431 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL ); 432 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED ); 433 formatter.getFullUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN ); 434 435 formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION ); 436 formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED ); 437 formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN ); 438 formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_GROUP_EXPANDED ); 439 440 formatter.setGroup( COMMAND_GROUP ); 441 formatter.setShellCommand( "station" ); 442 formatter.print(); 443 } 444 445 /** 446 * Startup the station. 447 */ 448 private void processStartup( CommandLine line ) throws Exception 449 { 450 getLogger().debug( "processing startup request" ); 451 int port = getPortValue( line, Registry.REGISTRY_PORT ); 452 if( null != getStation( port ) ) 453 { 454 final String message = 455 "Station already deployed on port: " + port; 456 getLogger().warn( message ); 457 return; 458 } 459 460 ArrayList list = new ArrayList(); 461 list.add( "station" ); 462 list.add( "-server" ); 463 list.add( "" + port ); 464 465 list.add( "-Ddpml.logging.config=local:properties:dpml/station/server" ); 466 list.add( "-Ddpml.subprocess=true" ); 467 if( "true".equals( System.getProperty( "dpml.trace" ) ) ) 468 { 469 list.add( "-trace" ); 470 } 471 else if( "true".equals( System.getProperty( "dpml.debug" ) ) ) 472 { 473 list.add( "-debug" ); 474 } 475 Set propertyValue = line.getProperties(); 476 Iterator iterator = propertyValue.iterator(); 477 while( iterator.hasNext() ) 478 { 479 String name = (String) iterator.next(); 480 String value = line.getProperty( name ); 481 list.add( "-D" + name + "=" + value ); 482 } 483 484 URI uri = getRegistryURI( line ); 485 if( null != uri ) 486 { 487 list.add( "-registry" ); 488 list.add( uri.toASCIIString() ); 489 } 490 String[] args = (String[]) list.toArray( new String[0] ); 491 492 String message = "server startup command:"; 493 String info = getRawArguments( message, args ); 494 getLogger().debug( info ); 495 496 Process process = Runtime.getRuntime().exec( args, null ); 497 getLogger().info( "waiting for server" ); 498 OutputStreamReader output = new OutputStreamReader( getLogger(), process.getInputStream() ); 499 ErrorStreamReader err = new ErrorStreamReader( getLogger(), process.getErrorStream() ); 500 output.setDaemon( true ); 501 err.setDaemon( true ); 502 output.start(); 503 err.start(); 504 505 int n = 0; 506 while( ( null == getStation( port ) && n < 20 ) ) 507 { 508 try 509 { 510 Thread.currentThread().sleep( 600 ); 511 } 512 catch( Exception e ) 513 { 514 } 515 n++; 516 } 517 518 if( null == getStation( port ) ) 519 { 520 getLogger().info( "server failed to start" ); 521 } 522 else 523 { 524 getLogger().info( "station started" ); 525 } 526 } 527 528 private void processShutdown( CommandLine line ) throws Exception 529 { 530 try 531 { 532 Manager manager = getManager( line ); 533 getLogger().info( "initiating station shutdown" ); 534 try 535 { 536 manager.shutdown(); 537 } 538 catch( Exception e ) 539 { 540 getLogger().warn( e.getClass().getName() ); 541 } 542 getLogger().info( "station shutdown complete" ); 543 } 544 catch( Exception e ) 545 { 546 getLogger().info( "station is not running" ); 547 } 548 } 549 550 /** 551 * List application registry information. 552 * @param line the commandline 553 */ 554 private void processInfoCommand( CommandLine line ) throws Exception 555 { 556 System.out.println( "" ); 557 Thread.currentThread().setContextClassLoader( Provider.class.getClassLoader() ); 558 Manager manager = null; 559 try 560 { 561 manager = getManager( line ); 562 System.out.println( " Server is operational." ); 563 try 564 { 565 String[] info = manager.getInfo(); 566 for( int i=0; i<info.length; i++ ) 567 { 568 String value = info[i]; 569 System.out.println( " " + value ); 570 } 571 } 572 catch( RemoteException e ) 573 { 574 getLogger().error( "Remote exception.", e ); 575 } 576 } 577 catch( Exception e ) 578 { 579 System.out.println( " Server is not running." ); 580 } 581 582 ApplicationRegistry registry = getApplicationRegistry( line ); 583 String key = (String) line.getValue( INFO_COMMAND, null ); 584 585 if( null == key ) 586 { 587 StringBuffer buffer = new StringBuffer( "\n" ); 588 try 589 { 590 String[] keys = registry.getKeys(); 591 buffer.append( "\nProfile count: " + keys.length + "\n" ); 592 for( int i=0; i<keys.length; i++ ) 593 { 594 String k = keys[i]; 595 ApplicationDescriptor profile = 596 registry.getApplicationDescriptor( k ); 597 buffer.append( 598 "\n (" 599 + ( i+1 ) 600 + ") " 601 + k 602 ); 603 if( null != manager ) 604 { 605 Application application = manager.getApplication( k ); 606 buffer.append( "\t" + application.getProcessState() ); 607 } 608 else 609 { 610 buffer.append( "\t" ); 611 } 612 buffer.append( "\t" + profile.getCodeBaseURI() ); 613 } 614 buffer.append( "\n" ); 615 System.out.println( buffer.toString() ); 616 } 617 catch( RemoteException e ) 618 { 619 getLogger().error( "Remote exception.", e ); 620 } 621 catch( UnknownKeyException e ) 622 { 623 // ignore 624 } 625 } 626 else 627 { 628 try 629 { 630 ApplicationDescriptor profile = registry.getApplicationDescriptor( key ); 631 listProfile( profile ); 632 if( null != manager ) 633 { 634 Application application = manager.getApplication( key ); 635 PID pid = application.getPID(); 636 if( null != pid ) 637 { 638 // 639 System.out.println( 640 " Process: " 641 + application.getPID() 642 + " (" 643 + application.getProcessState() 644 + ")" ); 645 } 646 else 647 { 648 System.out.println( 649 " Process: " 650 + application.getProcessState() ); 651 } 652 653 Provider instance = application.getProvider(); 654 if( null != instance ) 655 { 656 State state = instance.getState(); 657 System.out.println( " State: " + state ); 658 Operation[] operations = state.getOperations(); 659 if( operations.length > 0 ) 660 { 661 System.out.println( " Operations: (" + operations.length + ")" ); 662 for( int i=0; i<operations.length; i++ ) 663 { 664 System.out.println( " " + operations[i] ); 665 } 666 } 667 Interface[] interfaces = state.getInterfaces(); 668 if( interfaces.length > 0 ) 669 { 670 System.out.println( " Interfaces: (" + interfaces.length + ")" ); 671 for( int i=0; i<interfaces.length; i++ ) 672 { 673 System.out.println( " " + interfaces[i] ); 674 } 675 } 676 Transition[] transitions = state.getTransitions(); 677 if( transitions.length > 0 ) 678 { 679 System.out.println( " Transitions: (" + transitions.length + ")" ); 680 for( int i=0; i<transitions.length; i++ ) 681 { 682 System.out.println( " " + transitions[i] ); 683 } 684 } 685 } 686 } 687 } 688 catch( UnknownKeyException e ) 689 { 690 getLogger().warn( "Unknown application key [" + key + "]." ); 691 } 692 catch( RemoteException e ) 693 { 694 getLogger().error( "Remote exception.", e ); 695 } 696 } 697 } 698 699 /** 700 * Handle a request for the startup of an application process. 701 * @param line the commandline 702 */ 703 private void processStartCommand( CommandLine line ) throws Exception 704 { 705 try 706 { 707 Manager manager = getManager( line ); 708 String value = (String) line.getValue( START_COMMAND, null ); 709 processStartCommand( manager, value ); 710 } 711 catch( ConnectException ce ) 712 { 713 final String message = 714 "\nCannot start application because the station is not running. " 715 + "\nUse 'station startup' to start the station process."; 716 System.out.println( message ); 717 } 718 } 719 720 /** 721 * Handle a request for the startup of an application process. 722 * @param key the application key 723 */ 724 private void processStartCommand( Manager manager, String key ) throws Exception 725 { 726 getLogger().info( "starting application [" + key + "]" ); 727 Application application = manager.getApplication( key ); 728 application.start(); 729 } 730 731 /** 732 * Handle a request for control of an application process. 733 * @param line the commandline 734 */ 735 private void processControlCommand( CommandLine line ) throws Exception 736 { 737 try 738 { 739 Manager manager = getManager( line ); 740 String value = (String) line.getValue( CONTROL_COMMAND, null ); 741 processControlCommand( manager, value ); 742 } 743 catch( ConnectException ce ) 744 { 745 final String message = 746 "\nCannot start application because the station is not running. " 747 + "\nUse 'station startup' to start the station process."; 748 System.out.println( message ); 749 } 750 } 751 752 /** 753 * Handle a request for control of an application process. 754 * @param key the application key 755 */ 756 private void processControlCommand( Manager manager, String key ) throws Exception 757 { 758 Application application = manager.getApplication( key ); 759 InputStreamReader isr = new InputStreamReader( System.in ); 760 BufferedReader reader = new BufferedReader( isr ); 761 String line = null; 762 PID pid = application.getPID(); 763 String prompt = "> "; 764 if( null != pid ) 765 { 766 prompt = pid.toString() + "> "; 767 } 768 769 System.out.println( prompt + "Connected to application [" + key + "]" ); 770 System.out.print( prompt ); 771 Parser parser = new Parser(); 772 parser.setGroup( CONTROLLER_GROUP ); 773 while( ( line = reader.readLine() ) != null ) 774 { 775 if( "".equals( line ) ) 776 { 777 boolean ignoreLine = true; 778 } 779 else 780 { 781 try 782 { 783 String[] arguments = line.split( " " ); 784 String[] args = expandArgs( arguments ); 785 CommandLine commandline = parser.parse( args ); 786 if( commandline.hasOption( CONTROL_HELP_COMMAND ) ) 787 { 788 HelpFormatter formatter = new HelpFormatter(); 789 formatter.setGroup( CONTROLLER_GROUP ); 790 formatter.print(); 791 } 792 else if( commandline.hasOption( CONTROL_EXIT_COMMAND ) ) 793 { 794 System.exit( 0 ); 795 } 796 else if( commandline.hasOption( CONTROL_INFO_COMMAND ) ) 797 { 798 listInfo( application ); 799 } 800 else if( commandline.hasOption( CONTROL_APPLY_COMMAND ) ) 801 { 802 applyTransition( application, commandline ); 803 } 804 else if( commandline.hasOption( CONTROL_EXEC_COMMAND ) ) 805 { 806 execOperation( application, commandline ); 807 } 808 else if( commandline.hasOption( CONTROL_INVOKE_COMMAND ) ) 809 { 810 invokeOperation( application, commandline ); 811 } 812 } 813 catch( Exception e ) 814 { 815 System.out.println( e.getMessage() ); 816 } 817 } 818 System.out.print( prompt ); 819 } 820 } 821 822 private String[] expandArgs( String[] args ) 823 { 824 String[] result = new String[ args.length ]; 825 for( int i=0; i<args.length; i++ ) 826 { 827 String arg = args[i]; 828 String value = PropertyResolver.resolve( arg ); 829 result[i] = value; 830 } 831 return result; 832 } 833 834 private String[] getExecArgs( CommandLine line ) 835 { 836 return getArgs( CONTROL_EXEC_COMMAND, line ); 837 } 838 839 private String[] getInvokeArgs( CommandLine line ) 840 { 841 return getArgs( CONTROL_INVOKE_COMMAND, line ); 842 } 843 844 private String[] getArgs( Option option, CommandLine line ) 845 { 846 List args = line.getValues( option ); 847 String[] elements = (String[]) args.toArray( new String[0] ); 848 if( elements.length < 2 ) 849 { 850 return new String[0]; 851 } 852 String[] result = new String[ elements.length - 1 ]; 853 for( int i=1; i<elements.length; i++ ) 854 { 855 result[i-1] = elements[i]; 856 } 857 return result; 858 } 859 860 private void listInfo( Application application ) throws Exception 861 { 862 System.out.println( "" ); 863 Provider provider = application.getProvider(); 864 if( null == provider ) 865 { 866 System.out.println( "Provider unavailable." ); 867 } 868 else 869 { 870 System.out.println( "Application: " + application.getID() ); 871 State state = provider.getState(); 872 System.out.println( "Current State: " + state ); 873 Transition[] transitions = state.getTransitions(); 874 System.out.println( "Transitions: " + transitions.length ); 875 for( int i=0; i<transitions.length; i++ ) 876 { 877 Transition transition = transitions[i]; 878 System.out.println( " [" + ( i+1 ) + "] " + transition.getName() ); 879 } 880 Operation[] operations = state.getOperations(); 881 System.out.println( "Operations: " + operations.length ); 882 for( int i=0; i<operations.length; i++ ) 883 { 884 Operation operation = operations[i]; 885 System.out.println( " [" + ( i+1 ) + "] " + operation.getName() ); 886 } 887 Interface[] interfaces = state.getInterfaces(); 888 System.out.println( "Interfaces: " + interfaces.length ); 889 for( int i=0; i<interfaces.length; i++ ) 890 { 891 System.out.println( " [" + ( i+1 ) + "] " + interfaces[i] ); 892 } 893 } 894 System.out.println( "" ); 895 } 896 897 private void applyTransition( Application application, CommandLine commandline ) throws Exception 898 { 899 String id = (String) commandline.getValue( CONTROL_APPLY_COMMAND, null ); 900 System.out.println( "\napplying transition: " + id ); 901 State state = application.getProvider().apply( id ); 902 System.out.println( "current state: " + state ); 903 System.out.println( "" ); 904 } 905 906 private void invokeOperation( Application application, CommandLine commandline ) throws Exception 907 { 908 String method = (String) commandline.getValues( CONTROL_INVOKE_COMMAND ).get( 0 ); 909 System.out.println( "\ninvoking operation: " + method ); 910 try 911 { 912 String[] applyArgs = getInvokeArgs( commandline ); 913 Object result = application.getProvider().invoke( method, applyArgs ); 914 if( null != result ) 915 { 916 System.out.println( "listing return value\n" ); 917 if( result instanceof Object[] ) 918 { 919 Object[] values = (Object[]) result; 920 for( int i=0; i<values.length; i++ ) 921 { 922 System.out.println( values[i].toString() ); 923 } 924 } 925 else 926 { 927 System.out.println( result.toString() ); 928 } 929 System.out.println( "\ndone" ); 930 } 931 else 932 { 933 System.out.println( "done" ); 934 } 935 } 936 catch( InvocationTargetException e ) 937 { 938 Throwable cause = e.getCause(); 939 if( null != cause ) 940 { 941 String error = ExceptionHelper.packException( cause, true ); 942 System.out.println( error ); 943 } 944 else 945 { 946 String error = ExceptionHelper.packException( e, true ); 947 System.out.println( error ); 948 } 949 } 950 catch( Throwable e ) 951 { 952 System.out.println( e.toString() ); 953 } 954 } 955 956 private void execOperation( Application application, CommandLine commandline ) throws Exception 957 { 958 String id = (String) commandline.getValues( CONTROL_EXEC_COMMAND ).get( 0 ); 959 System.out.println( "\napplying operation: " + id ); 960 try 961 { 962 String[] applyArgs = getExecArgs( commandline ); 963 Object result = application.getProvider().exec( id, applyArgs ); 964 if( null != result ) 965 { 966 System.out.println( "listing return value\n" ); 967 if( result instanceof Object[] ) 968 { 969 Object[] values = (Object[]) result; 970 for( int i=0; i<values.length; i++ ) 971 { 972 System.out.println( values[i].toString() ); 973 } 974 } 975 else 976 { 977 System.out.println( result.toString() ); 978 } 979 System.out.println( "\ndone" ); 980 } 981 else 982 { 983 System.out.println( "done" ); 984 } 985 } 986 catch( InvocationTargetException e ) 987 { 988 Throwable cause = e.getCause(); 989 if( null != cause ) 990 { 991 String error = ExceptionHelper.packException( cause, true ); 992 System.out.println( error ); 993 } 994 else 995 { 996 String error = ExceptionHelper.packException( e, true ); 997 System.out.println( error ); 998 } 999 } 1000 catch( Throwable e ) 1001 { 1002 System.out.println( e.toString() ); 1003 } 1004 } 1005 1006 /** 1007 * Handle a request for the shutdown of an application process. 1008 * @param line the commandline 1009 */ 1010 private void processStopCommand( CommandLine line ) throws Exception 1011 { 1012 try 1013 { 1014 Manager manager = getManager( line ); 1015 String value = (String) line.getValue( STOP_COMMAND, null ); 1016 processStopCommand( manager, value ); 1017 } 1018 catch( ConnectException ce ) 1019 { 1020 final String message = 1021 "\nCannot stop application because the station is not running. " 1022 + "\nUse 'station startup' to start the station process."; 1023 System.out.println( message ); 1024 } 1025 } 1026 1027 /** 1028 * Handle a request for the shutdown of an application process. 1029 * @param key the application key 1030 */ 1031 private void processStopCommand( Manager manager, String key ) throws Exception 1032 { 1033 getLogger().info( "stopping application [" + key + "]" ); 1034 Application application = manager.getApplication( key ); 1035 application.stop(); 1036 } 1037 1038 /** 1039 * Handle a request for the restart of an application process. 1040 * @param line the commandline 1041 */ 1042 private void processRestartCommand( CommandLine line ) throws Exception 1043 { 1044 try 1045 { 1046 Manager manager = getManager( line ); 1047 String value = (String) line.getValue( RESTART_COMMAND, null ); 1048 processRestartCommand( manager, value ); 1049 } 1050 catch( ConnectException ce ) 1051 { 1052 final String message = 1053 "\nCannot restart application because the station is not running. " 1054 + "\nUse 'station startup' to start the station process."; 1055 System.out.println( message ); 1056 } 1057 } 1058 1059 /** 1060 * Handle a request for the restart of an application process. 1061 * @param key the application key 1062 */ 1063 private void processRestartCommand( Manager manager, String key ) throws Exception 1064 { 1065 getLogger().info( "restarting application [" + key + "]" ); 1066 Application application = manager.getApplication( key ); 1067 application.restart(); 1068 } 1069 1070 private void processAddCommand( CommandLine line ) throws Exception 1071 { 1072 ApplicationRegistry registry = getApplicationRegistry( line ); 1073 String key = (String) line.getValue( ADD_COMMAND, null ); 1074 URI uri = (URI) line.getValue( REQUIRED_URI_OPTION, null ); 1075 Properties properties = getCommandLineProperties( line, new Properties() ); 1076 String baseDir = getBasedir( line, null ); 1077 String title = getTitle( line, key ); 1078 StartupPolicy policy = getStartupPolicy( line, StartupPolicy.MANUAL ); 1079 int startup = getStartupTimeout( line, ApplicationDescriptor.DEFAULT_STARTUP_TIMEOUT ); 1080 int shutdown = getShutdownTimeout( line, ApplicationDescriptor.DEFAULT_SHUTDOWN_TIMEOUT ); 1081 URI config = getConfigurationURI( line, null ); 1082 processAddCommand( 1083 registry, key, title, uri, startup, shutdown, properties, baseDir, policy, config ); 1084 } 1085 1086 /** 1087 * Add a profile to the registry. 1088 * @param key the application key 1089 * @param title the application title 1090 * @param uri the codebase uri 1091 * @param properties system properties 1092 * @param base process base directory 1093 * @param policy application startup policy 1094 */ 1095 private void processAddCommand( 1096 ApplicationRegistry registry, String key, String title, URI uri, 1097 int startup, int shutdown, Properties properties, String base, StartupPolicy policy, 1098 URI config ) 1099 { 1100 try 1101 { 1102 ApplicationDescriptor descriptor = 1103 new ApplicationDescriptor( 1104 uri, 1105 title, 1106 new ValueDirective[0], 1107 base, 1108 policy, 1109 startup, 1110 shutdown, 1111 properties, 1112 config ); 1113 registry.addApplicationDescriptor( key, descriptor ); 1114 registry.flush(); 1115 System.out.println( "\nAdded new profile [" + key + "]" ); 1116 listProfile( descriptor ); 1117 } 1118 catch( DuplicateKeyException e ) 1119 { 1120 final String error = 1121 "Cannot add application profile because the key [" 1122 + key 1123 + "] is already assigned to another profile."; 1124 getLogger().error( error ); 1125 } 1126 catch( Throwable e ) 1127 { 1128 final String error = 1129 "Unexpected error while processing add request."; 1130 getLogger().error( error, e ); 1131 getLogger().error( Thread.currentThread().getContextClassLoader().toString() ); 1132 } 1133 } 1134 1135 private void processSetCommand( CommandLine line ) throws Exception 1136 { 1137 ApplicationRegistry registry = getApplicationRegistry( line ); 1138 String key = (String) line.getValue( SET_COMMAND, null ); 1139 ApplicationDescriptor descriptor = registry.getApplicationDescriptor( key ); 1140 URI uri = (URI) line.getValue( OPTIONAL_URI_OPTION, descriptor.getCodeBaseURI() ); 1141 Properties properties = getCommandLineProperties( line, descriptor.getSystemProperties() ); 1142 String baseDir = getBasedir( line, descriptor.getBasePath() ); 1143 String title = getTitle( line, descriptor.getTitle() ); 1144 StartupPolicy policy = getStartupPolicy( line, descriptor.getStartupPolicy() ); 1145 int startup = getStartupTimeout( line, descriptor.getStartupTimeout() ); 1146 int shutdown = getShutdownTimeout( line, descriptor.getShutdownTimeout() ); 1147 URI config = getConfigurationURI( line, descriptor.getConfigurationURI() ); 1148 processSetCommand( 1149 registry, descriptor, key, title, uri, startup, shutdown, properties, baseDir, policy, config ); 1150 } 1151 1152 /** 1153 * Update a profile. 1154 * @param key the application key 1155 * @param title the application title 1156 * @param uri the codebase uri 1157 * @param properties system properties 1158 * @param base process base directory 1159 * @param policy application startup policy 1160 */ 1161 private void processSetCommand( 1162 ApplicationRegistry registry, ApplicationDescriptor profile, String key, String title, URI uri, 1163 int startup, int shutdown, Properties properties, String base, 1164 StartupPolicy policy, URI config ) 1165 throws IOException, UnknownKeyException 1166 { 1167 if( null == registry ) 1168 { 1169 throw new NullPointerException( "registry" ); 1170 } 1171 if( null == key ) 1172 { 1173 throw new NullPointerException( "key" ); 1174 } 1175 if( null == uri ) 1176 { 1177 throw new NullPointerException( "uri" ); 1178 } 1179 if( null == title ) 1180 { 1181 throw new NullPointerException( "title" ); 1182 } 1183 if( null == policy ) 1184 { 1185 throw new NullPointerException( "policy" ); 1186 } 1187 if( null == properties ) 1188 { 1189 throw new NullPointerException( "properties" ); 1190 } 1191 try 1192 { 1193 ApplicationDescriptor descriptor = 1194 new ApplicationDescriptor( 1195 uri, 1196 title, 1197 new ValueDirective[0], 1198 base, 1199 policy, 1200 startup, 1201 shutdown, 1202 properties, 1203 config ); 1204 registry.updateApplicationDescriptor( key, descriptor ); 1205 registry.flush(); 1206 } 1207 catch( UnknownKeyException e ) 1208 { 1209 final String error = 1210 "Cannot update application profile because the key [" 1211 + key 1212 + "] is unknown."; 1213 getLogger().error( error ); 1214 } 1215 catch( Throwable e ) 1216 { 1217 final String error = 1218 "Unexpected error while processing set command."; 1219 getLogger().error( error, e ); 1220 getLogger().error( Thread.currentThread().getContextClassLoader().toString() ); 1221 registry.updateApplicationDescriptor( key, profile ); 1222 } 1223 1224 try 1225 { 1226 ApplicationDescriptor newProfile = registry.getApplicationDescriptor( key ); 1227 System.out.println( "\nUpdated profile [" + key + "]" ); 1228 listProfile( newProfile ); 1229 } 1230 catch( UnknownKeyException e ) 1231 { 1232 final String error = 1233 "Unexpected error - updated profile not found."; 1234 getLogger().error( error, e ); 1235 } 1236 } 1237 1238 private void processRemoveCommand( CommandLine line ) throws Exception 1239 { 1240 ApplicationRegistry registry = getApplicationRegistry( line ); 1241 String value = (String) line.getValue( REMOVE_COMMAND, null ); 1242 try 1243 { 1244 Manager manager = getManager( line ); 1245 Application application = manager.getApplication( value ); 1246 application.stop(); 1247 } 1248 catch( ConnectException ce ) 1249 { 1250 boolean ignorable = true; 1251 } 1252 catch( UnknownKeyException ce ) 1253 { 1254 boolean ignorable = true; 1255 } 1256 processRemoveCommand( registry, value ); 1257 } 1258 1259 private void processRemoveCommand( ApplicationRegistry registry, String key ) 1260 { 1261 try 1262 { 1263 registry.removeApplicationDescriptor( key ); 1264 registry.flush(); 1265 getLogger().info( "removed application [" + key + "]" ); 1266 } 1267 catch( UnknownKeyException e ) 1268 { 1269 final String error = 1270 "Cannot add application profile because the key [" 1271 + key 1272 + "] is unknown."; 1273 getLogger().error( error ); 1274 } 1275 catch( Exception e ) 1276 { 1277 final String error = 1278 "Unexpected error while processing remove request."; 1279 getLogger().error( error, e ); 1280 } 1281 } 1282 1283 // ------------------------------------------------------------------------ 1284 // internal utilities 1285 // ------------------------------------------------------------------------ 1286 1287 private Logger getLogger() 1288 { 1289 return m_logger; 1290 } 1291 1292 private void logRawArguments( Logger logger, String[] args ) 1293 { 1294 StringBuffer buffer = 1295 new StringBuffer( 1296 "Processing [" 1297 + args.length 1298 + "] args." ); 1299 for( int i=0; i<args.length; i++ ) 1300 { 1301 buffer.append( 1302 "\n " 1303 + ( i+1 ) 1304 + " " 1305 + args[i] ); 1306 } 1307 String message = buffer.toString(); 1308 logger.debug( message ); 1309 } 1310 1311 private String getRawArguments( String message, String[] args ) 1312 { 1313 StringBuffer buffer = new StringBuffer( message ); 1314 buffer.append( "\n command elements: " + args.length ); 1315 for( int i=0; i<args.length; i++ ) 1316 { 1317 buffer.append( 1318 "\n " 1319 + ( i+1 ) 1320 + " " 1321 + args[i] ); 1322 } 1323 return buffer.toString(); 1324 } 1325 1326 private Station getStation( int port ) throws Exception 1327 { 1328 Registry registry = getLocalRegistry( port ); 1329 if( null != registry ) 1330 { 1331 try 1332 { 1333 return (Station) registry.lookup( Station.STATION_KEY ); 1334 } 1335 catch( Throwable e ) 1336 { 1337 return null; 1338 } 1339 } 1340 else 1341 { 1342 return null; 1343 } 1344 } 1345 1346 private ApplicationRegistry getApplicationRegistry( int port ) throws Exception 1347 { 1348 Station station = getStation( port ); 1349 if( null != station ) 1350 { 1351 Manager manager = (Manager) station; 1352 return manager.getApplicationRegistry(); 1353 } 1354 else 1355 { 1356 return getApplicationRegistry( (URI) null ); 1357 } 1358 } 1359 1360 private Registry getLocalRegistry( int port ) 1361 { 1362 try 1363 { 1364 return LocateRegistry.getRegistry( port ); 1365 } 1366 catch( RemoteException e ) 1367 { 1368 return null; 1369 } 1370 } 1371 1372 private ApplicationRegistry getApplicationRegistry( URI uri ) throws IOException 1373 { 1374 if( null == uri ) 1375 { 1376 return getLocalApplicationRegistry( ApplicationRegistry.DEFAULT_STORAGE_URI ); 1377 } 1378 else if( uri.getScheme().startsWith( "registry:" ) ) 1379 { 1380 return (ApplicationRegistry) Artifact.createArtifact( uri ).toURL().getContent(); 1381 } 1382 else 1383 { 1384 return getLocalApplicationRegistry( uri ); 1385 } 1386 } 1387 1388 /** 1389 * Create a new local application registry using the supplied uri. 1390 * As a side effect the internal state of this class is updated to reflect 1391 * the fact that this class is responsible for RMI cleanup. 1392 * @param uri the registry stoarage uri 1393 * @return the aplication registry 1394 */ 1395 private ApplicationRegistry getLocalApplicationRegistry( URI uri ) 1396 { 1397 try 1398 { 1399 Logger logger = getLogger(); 1400 URL url = getStorageURL( uri ); 1401 m_flag = true; 1402 m_registry = new RemoteApplicationRegistry( logger, url ); 1403 return m_registry; 1404 } 1405 catch( Exception e ) 1406 { 1407 final String error = 1408 "Unexpected error while loading application registry from the uri [" 1409 + uri 1410 + "]."; 1411 getLogger().error( error, e ); 1412 throw new RuntimeException( error, e ); 1413 } 1414 } 1415 1416 /** 1417 * Return the storage uri as a url. 1418 * @param uri the uri 1419 * @return the url 1420 * @exception Exception if the uri could not be converted to a url 1421 */ 1422 public URL getStorageURL( URI uri ) throws Exception 1423 { 1424 if( Artifact.isRecognized( uri ) ) 1425 { 1426 return Artifact.createArtifact( uri ).toURL(); 1427 } 1428 else 1429 { 1430 return uri.toURL(); 1431 } 1432 } 1433 1434 /** 1435 * List infomation to console about the supplied profile. 1436 * @param profile the application profile 1437 */ 1438 private void listProfile( ApplicationDescriptor profile ) 1439 { 1440 StringBuffer buffer = new StringBuffer( "\n" ); 1441 buffer.append( "\n Codebase: " + profile.getCodeBaseURI() ); 1442 buffer.append( "\n Working Directory Path: " + profile.getBasePath() ); 1443 buffer.append( "\n Startup Timeout: " + profile.getStartupTimeout() ); 1444 buffer.append( "\n Shutdown Timeout: " + profile.getShutdownTimeout() ); 1445 buffer.append( "\n Startup Policy: " + profile.getStartupPolicy() ); 1446 Properties properties = profile.getSystemProperties(); 1447 buffer.append( "\n System Properties: " + properties.size() ); 1448 buffer.append( "\n" ); 1449 System.out.println( buffer.toString() ); 1450 } 1451 1452 // ------------------------------------------------------------------------ 1453 // static utilities 1454 // ------------------------------------------------------------------------ 1455 1456 private static final String DEPOT_STATION_PLUGIN_URI = "artifact:part:dpml/station/dpml-station-server#1.0.3"; 1457 private static final Set STARTUP_POLICY_SET = createStartupPolicySet(); 1458 private static final String[] SUPPORTED_URI_SCHEMES = 1459 new String[]{"link", "artifact", "local"}; 1460 1461 private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder(); 1462 private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder(); 1463 private static final CommandBuilder COMMAND_BUILDER = new CommandBuilder(); 1464 private static final GroupBuilder GROUP_BUILDER = new GroupBuilder(); 1465 1466 private static final Option STARTUP_POLICY_OPTION = 1467 OPTION_BUILDER 1468 .withShortName( "policy" ) 1469 .withDescription( "Startup policy." ) 1470 .withRequired( false ) 1471 .withArgument( 1472 ARGUMENT_BUILDER 1473 .withDescription( "disabled|manual|automatic" ) 1474 .withName( "policy" ) 1475 .withMinimum( 1 ) 1476 .withMaximum( 1 ) 1477 .withValidator( new EnumValidator( STARTUP_POLICY_SET ) ) 1478 .create() ) 1479 .create(); 1480 1481 private static final Option BASEDIR_OPTION = 1482 OPTION_BUILDER 1483 .withShortName( "dir" ) 1484 .withShortName( "basedir" ) 1485 .withDescription( "Base directory." ) 1486 .withRequired( false ) 1487 .withArgument( 1488 ARGUMENT_BUILDER 1489 .withDescription( "Directory path." ) 1490 .withName( "path" ) 1491 .withMinimum( 1 ) 1492 .withMaximum( 1 ) 1493 .create() ) 1494 .create(); 1495 1496 private static final Option TITLE_OPTION = 1497 OPTION_BUILDER 1498 .withShortName( "title" ) 1499 .withDescription( "Application title." ) 1500 .withRequired( false ) 1501 .withArgument( 1502 ARGUMENT_BUILDER 1503 .withDescription( "Description." ) 1504 .withName( "title" ) 1505 .withMinimum( 1 ) 1506 .withMaximum( 1 ) 1507 .create() ) 1508 .create(); 1509 1510 private static final PropertyOption PROPERTY_OPTION = new PropertyOption(); 1511 private static final Option REQUIRED_URI_OPTION = buildURIOption( true ); 1512 private static final Option OPTIONAL_URI_OPTION = buildURIOption( false ); 1513 private static final NumberValidator INTERGER_VALIDATOR = NumberValidator.getIntegerInstance(); 1514 1515 private static final Option REGISTRY_URI_OPTION = 1516 OPTION_BUILDER 1517 .withShortName( "registry" ) 1518 .withDescription( "Application registry store." ) 1519 .withRequired( false ) 1520 .withArgument( 1521 ARGUMENT_BUILDER 1522 .withDescription( "Local or remote artifact reference." ) 1523 .withName( "artifact" ) 1524 .withMinimum( 1 ) 1525 .withMaximum( 1 ) 1526 .withValidator( new URIValidator() ) 1527 .create() ) 1528 .create(); 1529 1530 private static final Option CONFIGURATION_URI_OPTION = 1531 OPTION_BUILDER 1532 .withShortName( "config" ) 1533 .withDescription( "Application configuration." ) 1534 .withRequired( false ) 1535 .withArgument( 1536 ARGUMENT_BUILDER 1537 .withDescription( "Configuration uri." ) 1538 .withName( "uri" ) 1539 .withMinimum( 1 ) 1540 .withMaximum( 1 ) 1541 .withValidator( new URIValidator() ) 1542 .create() ) 1543 .create(); 1544 1545 private static final Option PORT_OPTION = 1546 OPTION_BUILDER 1547 .withShortName( "port" ) 1548 .withDescription( "RMI Registry port." ) 1549 .withRequired( false ) 1550 .withArgument( 1551 ARGUMENT_BUILDER 1552 .withDescription( "Registry port." ) 1553 .withName( "port" ) 1554 .withMinimum( 0 ) 1555 .withMaximum( 1 ) 1556 .withValidator( INTERGER_VALIDATOR ) 1557 .create() ) 1558 .create(); 1559 1560 private static final Option STARTUP_TIMEOUT_OPTION = 1561 OPTION_BUILDER 1562 .withShortName( "startup" ) 1563 .withDescription( "Startup timeout." ) 1564 .withRequired( false ) 1565 .withArgument( 1566 ARGUMENT_BUILDER 1567 .withDescription( "Timeout in seconds." ) 1568 .withName( "seconds" ) 1569 .withMinimum( 1 ) 1570 .withMaximum( 1 ) 1571 .withValidator( INTERGER_VALIDATOR ) 1572 .create() ) 1573 .create(); 1574 1575 private static final Option SHUTDOWN_TIMEOUT_OPTION = 1576 OPTION_BUILDER 1577 .withShortName( "shutdown" ) 1578 .withDescription( "Shutdown timeout." ) 1579 .withRequired( false ) 1580 .withArgument( 1581 ARGUMENT_BUILDER 1582 .withDescription( "Timeout in seconds." ) 1583 .withName( "seconds" ) 1584 .withMinimum( 1 ) 1585 .withMaximum( 1 ) 1586 .withValidator( INTERGER_VALIDATOR ) 1587 .create() ) 1588 .create(); 1589 1590 private static final Group APPLICATION_REGISTRY_GROUP = 1591 GROUP_BUILDER 1592 .withMinimum( 0 ) 1593 .withMaximum( 1 ) 1594 .withOption( PORT_OPTION ) 1595 .withOption( REGISTRY_URI_OPTION ) 1596 .create(); 1597 1598 private static final Group STARTUP_GROUP = 1599 GROUP_BUILDER 1600 .withMinimum( 0 ) 1601 .withMaximum( 2 ) 1602 .withOption( PORT_OPTION ) 1603 .withOption( REGISTRY_URI_OPTION ) 1604 .withOption( PROPERTY_OPTION ) 1605 .create(); 1606 1607 private static final Option STARTUP_COMMAND = 1608 COMMAND_BUILDER 1609 .withName( "startup" ) 1610 .withDescription( "Startup the station." ) 1611 .withChildren( STARTUP_GROUP ) 1612 .create(); 1613 1614 private static final Option SHUTDOWN_COMMAND = 1615 COMMAND_BUILDER 1616 .withName( "shutdown" ) 1617 .withDescription( "Shutdown the station." ) 1618 .create(); 1619 1620 private static final Option HELP_COMMAND = 1621 COMMAND_BUILDER 1622 .withName( "help" ) 1623 .withDescription( "Print command help." ) 1624 .create(); 1625 1626 private static final Group ADD_OPTIONS_GROUP = 1627 GROUP_BUILDER 1628 .withMinimum( 1 ) 1629 .withOption( REQUIRED_URI_OPTION ) 1630 .withOption( STARTUP_POLICY_OPTION ) 1631 .withOption( PROPERTY_OPTION ) 1632 .withOption( BASEDIR_OPTION ) 1633 .withOption( TITLE_OPTION ) 1634 .withOption( REGISTRY_URI_OPTION ) 1635 .withOption( STARTUP_TIMEOUT_OPTION ) 1636 .withOption( SHUTDOWN_TIMEOUT_OPTION ) 1637 .withOption( CONFIGURATION_URI_OPTION ) 1638 .create(); 1639 1640 private static final Option ADD_COMMAND = 1641 COMMAND_BUILDER 1642 .withName( "add" ) 1643 .withDescription( "Add a profile." ) 1644 .withArgument( 1645 ARGUMENT_BUILDER 1646 .withDescription( "Unique application key." ) 1647 .withName( "key" ) 1648 .withMinimum( 1 ) 1649 .withMaximum( 1 ) 1650 .create() ) 1651 .withChildren( ADD_OPTIONS_GROUP ) 1652 .create(); 1653 1654 private static final Group SET_OPTIONS_GROUP = 1655 GROUP_BUILDER 1656 .withMinimum( 0 ) 1657 .withOption( OPTIONAL_URI_OPTION ) 1658 .withOption( STARTUP_POLICY_OPTION ) 1659 .withOption( PROPERTY_OPTION ) 1660 .withOption( BASEDIR_OPTION ) 1661 .withOption( TITLE_OPTION ) 1662 .withOption( REGISTRY_URI_OPTION ) 1663 .withOption( STARTUP_TIMEOUT_OPTION ) 1664 .withOption( SHUTDOWN_TIMEOUT_OPTION ) 1665 .withOption( CONFIGURATION_URI_OPTION ) 1666 .create(); 1667 1668 private static final Option SET_COMMAND = 1669 COMMAND_BUILDER 1670 .withName( "set" ) 1671 .withDescription( "Set an application feature." ) 1672 .withArgument( 1673 ARGUMENT_BUILDER 1674 .withDescription( "application key" ) 1675 .withName( "key" ) 1676 .withMinimum( 1 ) 1677 .withMaximum( 1 ) 1678 .create() ) 1679 .withChildren( SET_OPTIONS_GROUP ) 1680 .create(); 1681 1682 private static final Option CONTROL_COMMAND = 1683 COMMAND_BUILDER 1684 .withName( "control" ) 1685 .withDescription( "Interactive control of an application." ) 1686 .withArgument( 1687 ARGUMENT_BUILDER 1688 .withDescription( "application key" ) 1689 .withName( "key" ) 1690 .withMinimum( 1 ) 1691 .withMaximum( 1 ) 1692 .create() ) 1693 .create(); 1694 1695 private static final Option START_COMMAND = 1696 COMMAND_BUILDER 1697 .withName( "start" ) 1698 .withDescription( "Start application." ) 1699 .withArgument( 1700 ARGUMENT_BUILDER 1701 .withDescription( "Application key." ) 1702 .withName( "key" ) 1703 .withMinimum( 1 ) 1704 .withMaximum( 1 ) 1705 .create() ) 1706 .create(); 1707 1708 private static final Option STOP_COMMAND = 1709 COMMAND_BUILDER 1710 .withName( "stop" ) 1711 .withDescription( "Stop application." ) 1712 .withArgument( 1713 ARGUMENT_BUILDER 1714 .withDescription( "Application key." ) 1715 .withName( "key" ) 1716 .withMinimum( 1 ) 1717 .withMaximum( 1 ) 1718 .create() ) 1719 .create(); 1720 1721 private static final Option RESTART_COMMAND = 1722 COMMAND_BUILDER 1723 .withName( "restart" ) 1724 .withDescription( "Restart application." ) 1725 .withArgument( 1726 ARGUMENT_BUILDER 1727 .withDescription( "Application key." ) 1728 .withName( "key" ) 1729 .withMinimum( 1 ) 1730 .withMaximum( 1 ) 1731 .create() ) 1732 .create(); 1733 1734 private static final Option REMOVE_COMMAND = 1735 COMMAND_BUILDER 1736 .withName( "remove" ) 1737 .withDescription( "Remove profile." ) 1738 .withArgument( 1739 ARGUMENT_BUILDER 1740 .withDescription( "unique application key" ) 1741 .withName( "key" ) 1742 .withMinimum( 1 ) 1743 .withMaximum( 1 ) 1744 .create() ) 1745 .withChildren( APPLICATION_REGISTRY_GROUP ) 1746 .create(); 1747 1748 private static final Option INFO_COMMAND = 1749 COMMAND_BUILDER 1750 .withName( "info" ) 1751 .withDescription( "Station or profile info." ) 1752 .withArgument( 1753 ARGUMENT_BUILDER 1754 .withDescription( "Application key." ) 1755 .withName( "key" ) 1756 .withMinimum( 0 ) 1757 .withMaximum( 1 ) 1758 .create() ) 1759 .withChildren( APPLICATION_REGISTRY_GROUP ) 1760 .create(); 1761 1762 private static final Group COMMAND_GROUP = 1763 GROUP_BUILDER 1764 .withName( "options" ) 1765 .withOption( STARTUP_COMMAND ) 1766 .withOption( ADD_COMMAND ) 1767 .withOption( SET_COMMAND ) 1768 .withOption( START_COMMAND ) 1769 .withOption( CONTROL_COMMAND ) 1770 .withOption( STOP_COMMAND ) 1771 .withOption( RESTART_COMMAND ) 1772 .withOption( INFO_COMMAND ) 1773 .withOption( REMOVE_COMMAND ) 1774 .withOption( SHUTDOWN_COMMAND ) 1775 .withOption( HELP_COMMAND ) 1776 .withMinimum( 1 ) 1777 .withMaximum( 1 ) 1778 .create(); 1779 1780 // micro control cli spec 1781 1782 private static final Option CONTROL_INFO_COMMAND = 1783 COMMAND_BUILDER 1784 .withName( "info" ) 1785 .withDescription( "List state info." ) 1786 .create(); 1787 1788 private static final Option CONTROL_EXIT_COMMAND = 1789 COMMAND_BUILDER 1790 .withName( "exit" ) 1791 .withDescription( "Exit the console." ) 1792 .create(); 1793 1794 private static final Option CONTROL_APPLY_COMMAND = 1795 COMMAND_BUILDER 1796 .withName( "apply" ) 1797 .withDescription( "Apply a state transition." ) 1798 .withArgument( 1799 ARGUMENT_BUILDER 1800 .withDescription( "Transition name." ) 1801 .withName( "id" ) 1802 .withMinimum( 1 ) 1803 .withMaximum( 1 ) 1804 .create() ) 1805 .create(); 1806 1807 private static final Option CONTROL_EXEC_COMMAND = 1808 COMMAND_BUILDER 1809 .withName( "exec" ) 1810 .withDescription( "Execute a management operation." ) 1811 .withArgument( 1812 ARGUMENT_BUILDER 1813 .withDescription( "Operation name." ) 1814 .withName( "id" ) 1815 .withMinimum( 1 ) 1816 .create() ) 1817 .create(); 1818 1819 private static final Option CONTROL_INVOKE_COMMAND = 1820 COMMAND_BUILDER 1821 .withName( "invoke" ) 1822 .withDescription( "Invoke a management operation." ) 1823 .withArgument( 1824 ARGUMENT_BUILDER 1825 .withDescription( "Operation name." ) 1826 .withName( "method" ) 1827 .withMinimum( 1 ) 1828 .create() ) 1829 .create(); 1830 1831 private static final Option CONTROL_HELP_COMMAND = 1832 COMMAND_BUILDER 1833 .withName( "help" ) 1834 .withDescription( "List controller help info." ) 1835 .create(); 1836 1837 private static final Group CONTROLLER_GROUP = 1838 GROUP_BUILDER 1839 .withName( "options" ) 1840 .withOption( CONTROL_INFO_COMMAND ) 1841 .withOption( CONTROL_APPLY_COMMAND ) 1842 .withOption( CONTROL_INVOKE_COMMAND ) 1843 .withOption( CONTROL_EXEC_COMMAND ) 1844 .withOption( CONTROL_EXIT_COMMAND ) 1845 .withOption( CONTROL_HELP_COMMAND ) 1846 .withMinimum( 1 ) 1847 .withMaximum( 1 ) 1848 .create(); 1849 1850 private static Option buildURIOption( boolean required ) 1851 { 1852 return OPTION_BUILDER 1853 .withShortName( "uri" ) 1854 .withDescription( "Codebase uri." ) 1855 .withRequired( required ) 1856 .withArgument( 1857 ARGUMENT_BUILDER 1858 .withDescription( "Codebase uri." ) 1859 .withName( "artifact" ) 1860 .withMinimum( 1 ) 1861 .withMaximum( 1 ) 1862 .withValidator( new URIValidator() ) 1863 .create() ) 1864 .create(); 1865 } 1866 1867 private static Set createStartupPolicySet() 1868 { 1869 Set set = new HashSet(); 1870 StartupPolicy[] values = StartupPolicy.values(); 1871 for( int i=0; i<values.length; i++ ) 1872 { 1873 StartupPolicy policy = values[i]; 1874 set.add( policy.getName() ); 1875 } 1876 return set; 1877 } 1878 } 1879