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.metro.runtime; 020 021 import java.beans.Expression; 022 import java.beans.Statement; 023 import java.lang.reflect.InvocationTargetException; 024 import java.net.URI; 025 import java.util.ArrayList; 026 import java.util.Hashtable; 027 import java.util.List; 028 import java.util.WeakHashMap; 029 import java.util.EventObject; 030 import java.util.EventListener; 031 import java.rmi.RemoteException; 032 033 import net.dpml.state.State; 034 import net.dpml.state.Transition; 035 import net.dpml.state.Operation; 036 import net.dpml.state.Interface; 037 import net.dpml.state.Trigger; 038 import net.dpml.state.Trigger.TriggerEvent; 039 import net.dpml.state.Action; 040 import net.dpml.state.StateMachine; 041 import net.dpml.state.UnknownOperationException; 042 import net.dpml.state.UnknownTransitionException; 043 import net.dpml.state.IntegrityRuntimeException; 044 import net.dpml.state.StateListener; 045 import net.dpml.state.StateEvent; 046 import net.dpml.state.ExecAction; 047 import net.dpml.state.ApplyAction; 048 049 import net.dpml.util.Logger; 050 import net.dpml.util.EventQueue; 051 import net.dpml.util.EventHandler; 052 053 /** 054 * Default state-machine implementation. 055 * 056 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 057 * @version 1.0.4 058 */ 059 public class DefaultStateMachine implements StateMachine, EventHandler 060 { 061 /** 062 * Constant name used to reference a state change in a property event. 063 */ 064 public static final String PROPERTY_NAME = "state"; 065 066 /** 067 * Validate the state integrity. 068 * @param state the state to validate 069 */ 070 public static void validate( State state ) 071 { 072 validateState( state ); 073 } 074 075 //------------------------------------------------------------------------------- 076 // state 077 //------------------------------------------------------------------------------- 078 079 private State m_state; 080 private boolean m_active = false; 081 private boolean m_disposed = false; 082 083 private final Object m_lock = new Object(); 084 085 private final EventQueue m_queue; 086 087 private final WeakHashMap m_listeners = new WeakHashMap(); 088 089 private final Logger m_logger; 090 091 //------------------------------------------------------------------------------- 092 // constructor 093 //------------------------------------------------------------------------------- 094 095 /** 096 * Creation of a new state machine using a state graph. 097 * @param queue the event queue 098 * @param logger the logging channel 099 * @param state the state graph 100 * @exception RemoteException if RMI exception occurs 101 */ 102 public DefaultStateMachine( EventQueue queue, Logger logger, State state ) throws RemoteException 103 { 104 m_queue = queue; 105 m_logger = logger; 106 m_state = state; 107 } 108 109 //------------------------------------------------------------------------------- 110 // StateMachine 111 //------------------------------------------------------------------------------- 112 113 /** 114 * Add a state change listener to the state machine. 115 * @param listener the state listener 116 */ 117 public void addStateListener( final StateListener listener ) 118 { 119 if( null == listener ) 120 { 121 throw new NullPointerException( "listener" ); 122 } 123 checkDisposed(); 124 synchronized( m_lock ) 125 { 126 m_listeners.put( listener, null ); 127 } 128 } 129 130 /** 131 * Remove a state listener from the state machine. 132 * @param listener the state listener 133 */ 134 public void removeStateListener( final StateListener listener ) 135 { 136 if( null == listener ) 137 { 138 throw new NullPointerException( "listener" ); 139 } 140 checkDisposed(); 141 synchronized( m_lock ) 142 { 143 m_listeners.remove( listener ); 144 } 145 } 146 147 /** 148 * Return the assigned state event listeners. 149 * @return the event listeners 150 */ 151 public EventListener[] getEventListeners() 152 { 153 return getStateListeners(); 154 } 155 156 private StateListener[] getStateListeners() 157 { 158 synchronized( m_lock ) 159 { 160 return (StateListener[]) m_listeners.keySet().toArray( new StateListener[0] ); 161 } 162 } 163 164 /** 165 * Process the supplied event. 166 * @param event the event to process 167 */ 168 public void processEvent( EventObject event ) 169 { 170 StateListener[] listeners = getStateListeners(); 171 for( int i=0; i < listeners.length; i++ ) 172 { 173 StateListener listener = listeners[i]; 174 if( event instanceof StateEvent ) 175 { 176 try 177 { 178 StateEvent e = (StateEvent) event; 179 listener.stateChanged( e ); 180 } 181 catch( Throwable e ) 182 { 183 final String error = 184 "StateListener notification error."; 185 getLogger().error( error, e ); 186 } 187 } 188 } 189 } 190 191 /** 192 * Return the current state. 193 * @return the current state 194 */ 195 public State getState() 196 { 197 checkDisposed(); 198 synchronized( m_state ) 199 { 200 return m_state; 201 } 202 } 203 204 /** 205 * Locate and return the most immediate initialization action defined relative to 206 * the current state. If an action is located within the current state it will be 207 * return otherwise the search will continue up the state graph until either an 208 * action is located or no further parent state is available in which case a null 209 * value is returned. 210 * 211 * @return the initialization action or null if no action declared 212 */ 213 public Action getInitializationAction() 214 { 215 checkDisposed(); 216 try 217 { 218 return getAction( m_state, Trigger.INITIALIZATION ); 219 } 220 catch( Throwable e ) 221 { 222 final String error = 223 "Unexpected error during resolution of initialization actions."; 224 throw new IntegrityRuntimeException( error, e ); 225 } 226 } 227 228 /** 229 * Locate and return the most immediate termination action defined relative to 230 * the current state. If an action is located within the current state it will be 231 * return otherwise the search will continue up the state graph until either an 232 * action is located or no further parent state is available in which case a null 233 * value is returned. 234 * 235 * @return the termination action or null if no action declared 236 */ 237 public Action getTerminationAction() 238 { 239 checkDisposed(); 240 try 241 { 242 return getAction( m_state, Trigger.TERMINATION ); 243 } 244 catch( Throwable e ) 245 { 246 final String error = 247 "Unexpected error during resolution of termination actions."; 248 throw new IntegrityRuntimeException( error, e ); 249 } 250 } 251 252 /** 253 * Invoke initialization of the supplied object using the initialization action 254 * declared under the current state path. 255 * 256 * @param object the object to initialize 257 * @return the state established as a sidee effect of the initialization 258 * @exception InvocationTargetException if an invocation error occurs as a 259 * result of initialization 260 */ 261 public State initialize( Object object ) throws InvocationTargetException 262 { 263 checkDisposed(); 264 ArrayList visited = new ArrayList(); 265 try 266 { 267 State result = initialize( visited, object ); 268 m_active = true; 269 return result; 270 } 271 catch( UnknownTransitionException e ) 272 { 273 final String error = 274 "Internal state machine error raised due to an unresolved transition."; 275 throw new IntegrityRuntimeException( error, e ); 276 } 277 catch( UnknownOperationException e ) 278 { 279 final String error = 280 "Internal state machine error raised due to an unresolved operation."; 281 throw new IntegrityRuntimeException( error, e ); 282 } 283 catch( InvocationTargetException e ) 284 { 285 throw e; 286 } 287 catch( Throwable e ) 288 { 289 final String error = 290 "Unexpected error during state-machine initialization."; 291 throw new IntegrityRuntimeException( error, e ); 292 } 293 } 294 295 /** 296 * Execute a named operation on the supplied object. 297 * @param name an operation name 298 * @param object the target object 299 * @param args operation arguments 300 * @return the result of operation invocation 301 * @exception UnknownOperationException if the operation is unknown 302 * @exception InvocationTargetException if an invocation error occurs as a 303 * result of operation execution 304 */ 305 public Object execute( String name, Object object, Object[] args ) 306 throws UnknownOperationException, InvocationTargetException 307 { 308 checkDisposed(); 309 Operation operation = getOperation( getState(), name ); 310 return execute( operation, object, args ); 311 } 312 313 /** 314 * Invoke a management method on the supplied object. 315 * @param object the target object 316 * @param method the method name 317 * @param args method parameter arguments 318 * @return the return value 319 * @exception IllegalStateException if the method is recognized but not available 320 * @exception UnknownOperationException if the operation is unknown 321 * @exception InvocationTargetException if an invocation error occurs as a 322 * result of operation execution 323 */ 324 public Object invoke( Object object, String method, Object[] args ) 325 throws UnknownOperationException, InvocationTargetException, IllegalStateException 326 { 327 checkDisposed(); 328 329 // TODO: validate exposure of declaring interface 330 331 try 332 { 333 Expression expression = new Expression( object, method, args ); 334 return expression.getValue(); 335 } 336 catch( InvocationTargetException e ) 337 { 338 throw e; 339 } 340 catch( Exception e ) 341 { 342 throw new InvocationTargetException( e ); 343 } 344 } 345 346 /** 347 * Apply a named transition to the target object. 348 * @param name the transition name 349 * @param object the object against which any transition handler action are to be applied 350 * @return the state established by the application of the transition 351 * @exception UnknownTransitionException if the transition is unknown 352 * @exception InvocationTargetException if an invocation error occurs as a 353 * result of transition invocation 354 */ 355 public State apply( String name, Object object ) 356 throws UnknownTransitionException, InvocationTargetException 357 { 358 checkDisposed(); 359 synchronized( m_state ) 360 { 361 Transition transition = getTransition( m_state, name ); 362 return apply( transition, object ); 363 } 364 } 365 366 /** 367 * Return all of the available transitions relative to the current state. 368 * @return the available transitions 369 */ 370 public Transition[] getTransitions() 371 { 372 checkDisposed(); 373 Hashtable table = new Hashtable(); 374 State[] states = m_state.getStatePath(); 375 for( int i=( states.length-1 ); i>-1; i-- ) 376 { 377 State state = states[i]; 378 Transition[] transitions = state.getTransitions(); 379 for( int j=0; j<transitions.length; j++ ) 380 { 381 Transition transition = transitions[j]; 382 String name = transition.getName(); 383 if( null == table.get( name ) ) 384 { 385 table.put( name, transition ); 386 } 387 } 388 } 389 return (Transition[]) table.values().toArray( new Transition[0] ); 390 } 391 392 /** 393 * Return all of the available operations relative to the current state. 394 * @return the available operations 395 */ 396 public Operation[] getOperations() 397 { 398 checkDisposed(); 399 Hashtable table = new Hashtable(); 400 State[] states = m_state.getStatePath(); 401 for( int i=( states.length-1 ); i>-1; i-- ) 402 { 403 State state = states[i]; 404 Operation[] operations = state.getOperations(); 405 for( int j=0; j<operations.length; j++ ) 406 { 407 Operation operation = operations[j]; 408 String name = operation.getName(); 409 if( null == table.get( name ) ) 410 { 411 table.put( name, operation ); 412 } 413 } 414 } 415 return (Operation[]) table.values().toArray( new Operation[0] ); 416 } 417 418 /** 419 * Return all of the available interfaces relative to the current state. 420 * @return the available interface declarations 421 */ 422 public Interface[] getInterfaces() 423 { 424 checkDisposed(); 425 Hashtable table = new Hashtable(); 426 State[] states = m_state.getStatePath(); 427 for( int i=( states.length-1 ); i>-1; i-- ) 428 { 429 State state = states[i]; 430 Interface[] interfaces = state.getInterfaces(); 431 for( int j=0; j<interfaces.length; j++ ) 432 { 433 Interface data = interfaces[j]; 434 String name = data.getName(); 435 if( null == table.get( name ) ) 436 { 437 table.put( name, data ); 438 } 439 } 440 } 441 return (Interface[]) table.values().toArray( new Interface[0] ); 442 } 443 444 /** 445 * Invoke termination of the supplied object using the termination action 446 * declared under the current state path. 447 * 448 * @param object the object to terminate 449 * @return the state established as a side-effect of the termination 450 */ 451 public State terminate( Object object ) 452 { 453 checkDisposed(); 454 ArrayList visited = new ArrayList(); 455 try 456 { 457 State result = terminate( visited, object ); 458 m_active = false; 459 return result; 460 } 461 catch( Throwable e ) 462 { 463 e.printStackTrace(); 464 return getState(); 465 } 466 } 467 468 /** 469 * Returns the active status of the state machine. 470 * @return TRUE if the state machine has invoked initialization and 471 * termination has not been performed otherwise FALSE 472 */ 473 public boolean isActive() 474 { 475 return m_active; 476 } 477 478 /** 479 * Dispose of the state machine. 480 */ 481 public void dispose() 482 { 483 synchronized( m_lock ) 484 { 485 StateListener[] listeners = getStateListeners(); 486 for( int i=0; i<listeners.length; i++ ) 487 { 488 StateListener listener = listeners[i]; 489 removeStateListener( listener ); 490 } 491 } 492 m_disposed = true; 493 m_state = null; 494 } 495 496 //------------------------------------------------------------------------------- 497 // implementation 498 //------------------------------------------------------------------------------- 499 500 private String getTag( final Object object ) 501 { 502 return DefaultProvider.createTag( object ); 503 } 504 505 private State initialize( List list, Object object ) throws Exception 506 { 507 Action action = getInitializationAction(); 508 if( null == action ) 509 { 510 return m_state; 511 } 512 else if( list.contains( action ) ) 513 { 514 return m_state; 515 } 516 else 517 { 518 list.add( action ); 519 if( action instanceof Operation ) 520 { 521 Operation operation = (Operation) action; 522 execute( operation, object, new Object[0] ); 523 return m_state; 524 } 525 else if( action instanceof Transition ) 526 { 527 Transition transition = (Transition) action; 528 State current = getState(); 529 State result = apply( transition, object ); 530 if( !current.equals( result ) ) 531 { 532 return initialize( list, object ); 533 } 534 else 535 { 536 return getState(); 537 } 538 } 539 else 540 { 541 final String error = "Unrecognized action: " + action; 542 throw new IllegalStateException( error ); 543 } 544 } 545 } 546 547 private Object execute( Operation operation, Object object, Object[] args ) throws InvocationTargetException 548 { 549 if( null == object ) 550 { 551 return null; 552 } 553 554 String method = getMethodName( operation ); 555 556 try 557 { 558 Expression expression = new Expression( object, method, args ); 559 return expression.getValue(); 560 } 561 catch( InvocationTargetException e ) 562 { 563 throw e; 564 } 565 catch( Exception e ) 566 { 567 throw new InvocationTargetException( e ); 568 } 569 } 570 571 private State terminate( List list, Object object ) throws Exception 572 { 573 Action action = getTerminationAction(); 574 if( null == action ) 575 { 576 return m_state; 577 } 578 else if( list.contains( action ) ) 579 { 580 return m_state; 581 } 582 else 583 { 584 if( action instanceof Operation ) 585 { 586 Operation operation = (Operation) action; 587 execute( operation, object, new Object[0] ); 588 return m_state; 589 } 590 else if( action instanceof Transition ) 591 { 592 Transition transition = (Transition) action; 593 State current = getState(); 594 State result = apply( transition, object ); 595 if( !current.equals( result ) ) 596 { 597 return terminate( list, object ); 598 } 599 else 600 { 601 return getState(); 602 } 603 } 604 else 605 { 606 final String error = "Unrecognized action: " + action; 607 throw new IllegalStateException( error ); 608 } 609 } 610 } 611 612 private State apply( Transition transition, Object object ) throws InvocationTargetException 613 { 614 synchronized( m_state ) 615 { 616 State context = transition.getState(); 617 String target = transition.getTargetName(); 618 State state = getState( context, target ); 619 Operation operation = transition.getOperation(); 620 if( getLogger().isTraceEnabled() ) 621 { 622 String name = transition.getName(); 623 String tag = getTag( object ); 624 getLogger().trace( 625 "applying transition [" 626 + name 627 + "] to " 628 + tag ); 629 } 630 if( null != operation ) 631 { 632 execute( operation, object, new Object[0] ); // TODO: add resolved values as args 633 } 634 setState( object, state ); 635 return state; 636 } 637 } 638 639 private void execute( URI handler, Object object ) throws InvocationTargetException 640 { 641 if( null == object ) 642 { 643 return; 644 } 645 String scheme = handler.getScheme(); 646 if( "method".equals( scheme ) ) 647 { 648 String methodName = handler.getSchemeSpecificPart(); 649 if( getLogger().isTraceEnabled() ) 650 { 651 String tag = getTag( object ); 652 getLogger().trace( 653 "executing operation [" 654 + methodName 655 + "] on " 656 + tag ); 657 } 658 Statement statement = new Statement( object, methodName, new Object[0] ); 659 try 660 { 661 statement.execute(); 662 } 663 catch( InvocationTargetException e ) 664 { 665 throw e; 666 } 667 catch( Exception e ) 668 { 669 throw new InvocationTargetException( e ); 670 } 671 } 672 else 673 { 674 final String error = 675 "Operation scheme not recognized." 676 + "\nScheme: " + scheme 677 + "\nURI: " + handler; 678 throw new IllegalArgumentException( error ); 679 } 680 } 681 682 private void setState( final Object object, final State state ) 683 { 684 synchronized( m_state ) 685 { 686 if( m_state != state ) 687 { 688 final State oldState = m_state; 689 m_state = state; 690 691 if( getLogger().isTraceEnabled() ) 692 { 693 String tag = getTag( object ); 694 getLogger().trace( 695 "transitioning from [" 696 + oldState 697 + "] to [" 698 + state 699 + "] in " 700 + tag ); 701 } 702 703 final StateEvent event = new StateEvent( this, oldState, state ); 704 m_queue.enqueueEvent( event ); 705 } 706 } 707 } 708 709 private Action getAction( State state, TriggerEvent category ) 710 throws UnknownTransitionException, UnknownOperationException 711 { 712 Trigger[] triggers = state.getTriggers(); 713 for( int i=0; i<triggers.length; i++ ) 714 { 715 Trigger trigger = triggers[i]; 716 if( trigger.getEvent().equals( category ) ) 717 { 718 Action action = trigger.getAction(); 719 if( action instanceof ApplyAction ) 720 { 721 ApplyAction apply = (ApplyAction) action; 722 String id = apply.getID(); 723 return getTransition( state, id ); 724 } 725 else if( action instanceof ExecAction ) 726 { 727 ExecAction exec = (ExecAction) action; 728 String id = exec.getID(); 729 return getOperation( state, id ); 730 } 731 else 732 { 733 return action; 734 } 735 } 736 } 737 State parent = state.getParent(); 738 if( null != parent ) 739 { 740 return getAction( parent, category ); 741 } 742 else 743 { 744 return null; 745 } 746 } 747 748 private Transition getTransition( State state, String name ) throws UnknownTransitionException 749 { 750 Transition[] transitions = state.getTransitions(); 751 for( int i=0; i<transitions.length; i++ ) 752 { 753 Transition transition = transitions[i]; 754 if( name.equals( transition.getName() ) ) 755 { 756 return transition; 757 } 758 } 759 State parent = state.getParent(); 760 if( null == parent ) 761 { 762 final String error = 763 "Unable to resolve a transition named [" 764 + name 765 + "] relative to the state [" 766 + state.getName() 767 + "]."; 768 throw new UnknownTransitionException( error ); 769 } 770 else 771 { 772 try 773 { 774 return getTransition( parent, name ); 775 } 776 catch( UnknownTransitionException e ) 777 { 778 final String error = 779 "Unable to resolve a transition named [" 780 + name 781 + "] relative to the current state [" 782 + state 783 + "]."; 784 throw new UnknownTransitionException( error ); 785 } 786 } 787 } 788 789 private Operation getOperation( State state, String name ) throws UnknownOperationException 790 { 791 Operation[] operations = state.getOperations(); 792 for( int i=0; i<operations.length; i++ ) 793 { 794 Operation operation = operations[i]; 795 if( name.equals( operation.getName() ) ) 796 { 797 return operation; 798 } 799 } 800 State parent = state.getParent(); 801 if( null == parent ) 802 { 803 throw new UnknownOperationException( name ); 804 } 805 else 806 { 807 return getOperation( parent, name ); 808 } 809 } 810 811 //------------------------------------------------------------------------------- 812 // static internals used to validate the integrity of a state graph 813 //------------------------------------------------------------------------------- 814 815 private static void validateState( State state ) 816 { 817 Trigger[] triggers = state.getTriggers(); 818 validateTriggers( state, triggers ); 819 Transition[] transitions = state.getTransitions(); 820 validateTransitions( state, transitions ); 821 Operation[] operations = state.getOperations(); 822 validateOperations( state, operations ); 823 State[] states = state.getStates(); 824 validateStates( state, states ); 825 } 826 827 private static void validateTransitions( State state, Transition[] transitions ) 828 { 829 for( int i=0; i<transitions.length; i++ ) 830 { 831 Transition transition = transitions[i]; 832 validateTransition( state, transition ); 833 } 834 } 835 836 private static void validateOperations( State state, Operation[] operations ) 837 { 838 for( int i=0; i<operations.length; i++ ) 839 { 840 Operation operation = operations[i]; 841 validateOperation( state, operation ); 842 } 843 } 844 845 private static void validateTriggers( State state, Trigger[] triggers ) 846 { 847 for( int i=0; i<triggers.length; i++ ) 848 { 849 Trigger trigger = triggers[i]; 850 validateTrigger( state, trigger ); 851 } 852 } 853 854 private static void validateStates( State state, State[] states ) 855 { 856 for( int i=0; i<states.length; i++ ) 857 { 858 State s = states[i]; 859 validateState( s ); 860 } 861 } 862 863 private static void validateTrigger( State state, Trigger trigger ) 864 { 865 TriggerEvent event = trigger.getEvent(); 866 Action action = trigger.getAction(); 867 if( action instanceof Transition ) 868 { 869 Transition transition = (Transition) action; 870 validateTransition( state, transition ); 871 } 872 else if( action instanceof Operation ) 873 { 874 Operation operation = (Operation) action; 875 validateOperation( state, operation ); 876 } 877 else if( action instanceof ApplyAction ) 878 { 879 ApplyAction apply = (ApplyAction) action; 880 String id = apply.getID(); 881 validateTransition( state, id ); 882 } 883 else if( action instanceof ExecAction ) 884 { 885 ExecAction exec = (ExecAction) action; 886 String id = exec.getID(); 887 validateOperation( state, id ); 888 } 889 } 890 891 private static void validateTransition( State state, String id ) 892 { 893 //System.out.println( "# v/transition: " + id ); 894 } 895 896 private static void validateTransition( State state, Transition transition ) 897 { 898 String target = transition.getTargetName(); 899 State s = getState( state, target ); 900 if( null == state ) 901 { 902 final String error = 903 "Transition target [" 904 + target 905 + "] does not exist relative to state [" 906 + state; 907 throw new IllegalStateException( error ); 908 } 909 } 910 911 private static void validateOperation( State state, String id ) 912 { 913 //System.out.println( "# v/operation: " + operation ); 914 } 915 916 private static void validateOperation( State state, Operation operation ) 917 { 918 //System.out.println( "# v/operation: " + operation ); 919 } 920 921 private static State getState( State state, String target ) 922 { 923 if( target.startsWith( "/" ) ) 924 { 925 // 926 // its an absolute target 927 // 928 929 String spec = target.substring( 1 ); 930 State root = state.getStatePath()[0]; 931 return getState( root, spec ); 932 } 933 else if( target.startsWith( "../" ) ) 934 { 935 // 936 // its relative to the state's parent 937 // 938 939 String spec = target.substring( 3 ); 940 State parent = state.getParent(); 941 if( null != parent ) 942 { 943 return getState( parent, spec ); 944 } 945 else 946 { 947 final String error = 948 "Invalid relative reference [" 949 + spec 950 + "] passed to root state."; 951 throw new IllegalArgumentException( error ); 952 } 953 } 954 else if( target.indexOf( "/" ) > -1 ) 955 { 956 // 957 // its a composition address 958 // 959 960 int index = target.indexOf( "/" ); 961 String base = target.substring( 0, index ); 962 String remainder = target.substring( index + 1 ); 963 State s = getState( state, base ); 964 return getState( s, remainder ); 965 } 966 else 967 { 968 // 969 // its a name relative to the supplied state 970 // 971 972 State[] states = state.getStates(); 973 for( int i=0; i<states.length; i++ ) 974 { 975 State s = states[i]; 976 if( target.equals( s.getName() ) ) 977 { 978 return s; 979 } 980 } 981 final String error = 982 "Requested target state [" 983 + target 984 + "] does not exist within the state [" 985 + state.getName() 986 + "]."; 987 throw new IllegalArgumentException( error ); 988 } 989 } 990 991 private void checkDisposed() throws IllegalStateException 992 { 993 if( m_disposed ) 994 { 995 final String error = 996 "Instance has been disposed."; 997 throw new IllegalStateException( error ); 998 } 999 } 1000 1001 private String getMethodName( Operation operation ) 1002 { 1003 if( null != operation.getMethodName() ) 1004 { 1005 return operation.getMethodName(); 1006 } 1007 1008 // 1009 // otherwise resolve it using java beans style getXxxx 1010 // 1011 1012 String name = operation.getName(); 1013 int n = name.length(); 1014 if( n == 0 ) 1015 { 1016 throw new IllegalArgumentException( "Operation name is empty." ); 1017 } 1018 else if( n == 1 ) 1019 { 1020 return "get" + name.toUpperCase(); 1021 } 1022 else 1023 { 1024 return "get" 1025 + name.substring( 0, 1 ).toUpperCase() 1026 + name.substring( 1 ); 1027 } 1028 } 1029 1030 private static URI createURI( String path ) throws Exception 1031 { 1032 if( null == path ) 1033 { 1034 return null; 1035 } 1036 else 1037 { 1038 return new URI( path ); 1039 } 1040 } 1041 1042 private Logger getLogger() 1043 { 1044 return m_logger; 1045 } 1046 1047 }