1 17 18 package org.sape.carbon.core.component.lifecycle; 19 20 import java.util.Collections ; 21 import java.util.HashSet ; 22 import java.util.Set ; 23 import java.lang.reflect.Proxy ; 24 import java.lang.reflect.InvocationHandler ; 25 import java.lang.reflect.Method ; 26 27 import org.sape.carbon.core.component.Component; 28 import org.sape.carbon.core.component.ComponentConfiguration; 29 import org.sape.carbon.core.component.FunctionalInterface; 30 import org.sape.carbon.core.component.event.ComponentEvent; 31 import org.sape.carbon.core.component.event.EventManager; 32 import org.sape.carbon.core.component.proxy.ComponentProxyInvocationHandler; 33 import org.sape.carbon.core.component.proxy.Interceptor; 34 import org.sape.carbon.core.component.proxy.Invocation; 35 import org.sape.carbon.core.component.proxy.MonitorAcquisitionException; 36 import org.sape.carbon.core.component.proxy.AbstractInterceptor; 37 import org.sape.carbon.core.exception.ExceptionUtility; 38 39 import org.apache.commons.logging.Log; 40 import org.apache.commons.logging.LogFactory; 41 42 51 public class DefaultLifecycleInterceptor 52 extends AbstractInterceptor 53 implements LifecycleInterceptor, Interceptor { 54 55 56 protected static final Class [] EXPOSED_INTERFACES = 57 new Class [] {LifecycleInterceptor.class}; 58 59 60 private Log log = 61 LogFactory.getLog(this.getClass()); 62 63 64 public static final String LIFECYCLE_CHANGE_EVENT_NAME = 65 "Component.LifecycleChange"; 66 67 75 public Object invoke(Invocation invocation) throws Throwable { 76 77 if (invocation.isTargetFunctionalImplementation()) { 78 LifecycleStateEnum state = getLifecycleState(); 81 82 if (state != LifecycleStateEnum.RUNNING) { 83 if (state == LifecycleStateEnum.SUSPENDED 84 || state == LifecycleStateEnum.RESUMING) { 85 86 waitForResume(); 87 } else { 88 throw new ComponentUnavailableException( 89 this.getClass(), 90 "The component is not in a LifecycleStateEnum.RUNNING " 91 + "state, FunctionalInterface methods " 92 + "cannot be called. " 93 + "Component name [" + getComponentName() 94 + "], current state [" + state + "]"); 95 } 96 } 97 } 98 99 return callNextInterceptor(invocation); 100 } 101 102 110 public Class [] getExposedInterfaces() { 111 return DefaultLifecycleInterceptor.EXPOSED_INTERFACES; 112 } 113 114 119 private final FunctionalInterface functionalImplementation; 120 121 122 126 private LifecycleStateEnum currentState = LifecycleStateEnum.CREATING; 127 128 134 private final ComponentProxyInvocationHandler proxyInvocationHandler; 135 136 137 138 private Component componentProxy; 139 140 144 private final Object suspendedLock = new Object (); 145 146 147 private long blockedCallTimeout; 148 149 150 private long destroyerThreadTimeout; 151 152 163 public DefaultLifecycleInterceptor( 164 FunctionalInterface componentInstance, 165 ComponentProxyInvocationHandler proxyInvocationHandler, 166 DefaultLifecycleInterceptorConfiguration configuration) { 167 168 this.functionalImplementation = componentInstance; 169 170 this.proxyInvocationHandler = proxyInvocationHandler; 171 172 if (configuration == null) { 173 this.blockedCallTimeout = 174 DefaultLifecycleInterceptorConfiguration.BlockedCallTimeout; 175 this.destroyerThreadTimeout = 176 DefaultLifecycleInterceptorConfiguration.DestroyerThreadTimeout; 177 178 } else { 179 this.blockedCallTimeout = configuration.getBlockedCallTimeout(); 180 this.destroyerThreadTimeout = 181 configuration.getDestroyerThreadTimeout(); 182 } 183 } 184 185 186 187 193 public synchronized LifecycleStateEnum getLifecycleState() { 194 return this.currentState; 195 } 196 197 202 public String getLifecycleStateString() { 203 return getLifecycleState().toString(); 204 } 205 206 210 protected synchronized void setLifecycleState(LifecycleStateEnum state) { 211 212 if (log.isTraceEnabled()) { 213 log.trace( 214 "Changing [" 215 + getComponentName() 216 + "] component's state from [" 217 + this.currentState 218 + "] to [" 219 + state 220 + "]"); 221 } 222 223 if (this.componentProxy instanceof EventManager) { 226 ((EventManager) this.componentProxy). 227 sendEvent( 228 new ComponentEvent( 229 this.componentProxy, 230 LIFECYCLE_CHANGE_EVENT_NAME, 231 "Lifecycle state is changing from [" 232 + this.currentState.getName() + "] to [" 233 + state.getName() + "]")); 234 } 235 236 this.currentState = state; 237 } 238 239 256 public void initializeComponent(Component thisComponent) 257 throws InvalidStateException, 258 259 OperationNotSupportedException, StateTransitionException { 260 261 startLifecycleMethod(); 262 263 validateEntryState(getLifecycleState(), 264 DefaultLifecycleInterceptor.VALID_ENTRY_STATES_INITIALIZE); 265 266 try { 267 if (functionalImplementation instanceof Initializable) { 268 Initializable subject = null; 269 subject = (Initializable) functionalImplementation; 271 setLifecycleState(LifecycleStateEnum.INITIALIZING); 274 subject.initialize(thisComponent); 276 } else { 277 logNotSupported( 278 Initializable.class); 279 } 280 setLifecycleState(LifecycleStateEnum.STOPPED); 282 283 } catch (Exception e) { 284 throw new StateTransitionException( 285 this.getClass(), 286 "An Exception occurred while attempting to initialize", e); 287 288 } finally { 289 stopLifecycleMethod(); 290 } 291 } 292 293 306 public void startComponent() throws InvalidStateException, 307 OperationNotSupportedException, StateTransitionException { 308 309 startLifecycleMethod(); 310 311 validateEntryState(getLifecycleState(), 312 DefaultLifecycleInterceptor.VALID_ENTRY_STATES_START); 313 314 try { 315 316 if (functionalImplementation instanceof Startable) { 317 callComponentStart(); 318 } else { 319 logNotSupported( 320 Startable.class); 321 } 322 323 setLifecycleState(LifecycleStateEnum.RUNNING); 325 326 } finally { 327 stopLifecycleMethod(); 328 if (getLifecycleState() == LifecycleStateEnum.STARTING) { 330 killInvalidComponent(); 331 } 332 } 333 } 334 335 350 public void stopComponent() throws InvalidStateException, 351 OperationNotSupportedException, StateTransitionException { 352 353 startLifecycleMethod(); 354 355 validateEntryState(getLifecycleState(), 356 DefaultLifecycleInterceptor.VALID_ENTRY_STATES_STOP); 357 358 try { 359 360 internalStopComponent(); 361 362 } finally { 363 stopLifecycleMethod(); 364 if (getLifecycleState() == LifecycleStateEnum.STOPPING) { 366 killInvalidComponent(); 367 } 368 } 369 } 370 371 385 public void suspendComponent() throws InvalidStateException, 386 OperationNotSupportedException, StateTransitionException { 387 388 startLifecycleMethod(); 389 390 validateEntryState(getLifecycleState(), 391 DefaultLifecycleInterceptor.VALID_ENTRY_STATES_SUSPEND); 392 393 try { 394 internalSuspendComponent(); 395 396 } finally { 397 stopLifecycleMethod(); 398 if (getLifecycleState() == LifecycleStateEnum.SUSPENDING) { 399 killInvalidComponent(); 400 } 401 } 402 } 403 404 418 public void resumeComponent() throws InvalidStateException, 419 OperationNotSupportedException, StateTransitionException { 420 421 startLifecycleMethod(); 422 423 validateEntryState(getLifecycleState(), 424 DefaultLifecycleInterceptor.VALID_ENTRY_STATES_RESUME); 425 426 try { 427 internalResumeComponent(); 428 429 synchronized (this.suspendedLock) { 431 this.suspendedLock.notifyAll(); 432 } 433 } finally { 434 stopLifecycleMethod(); 435 if (getLifecycleState() == LifecycleStateEnum.RESUMING) { 436 killInvalidComponent(); 437 } 438 } 439 } 440 441 458 public void configureComponent(ComponentConfiguration configuration) 459 throws InvalidStateException, 460 OperationNotSupportedException, StateTransitionException { 461 462 startLifecycleMethod(); 463 464 validateEntryState(getLifecycleState(), 465 DefaultLifecycleInterceptor.VALID_ENTRY_STATES_CONFIGURE); 466 467 try { 468 if (functionalImplementation instanceof Configurable) { 469 callComponentConfigure(configuration); 470 471 } else { 472 logNotSupported( 473 Configurable.class); 474 } 475 476 } finally { 477 stopLifecycleMethod(); 478 479 LifecycleStateEnum exitState = getLifecycleState(); 480 if (exitState != LifecycleStateEnum.RUNNING 481 && exitState != LifecycleStateEnum.SUSPENDED 482 && exitState != LifecycleStateEnum.STOPPED) { 483 484 killInvalidComponent(); 485 } 486 } 487 } 488 489 509 public void destroyComponent() 510 throws OperationNotSupportedException, StateTransitionException { 511 512 if (getLifecycleState() == LifecycleStateEnum.DESTROYED) { 513 return; 515 } 516 517 startLifecycleMethod(); 518 519 try { 520 if (functionalImplementation instanceof Destroyable 521 || (getLifecycleState() == LifecycleStateEnum.RUNNING 522 && functionalImplementation instanceof Startable)) { 523 524 525 Thread destroyer = new Thread (new Runnable () { 528 public void run() { 529 try { 530 if (getLifecycleState() 532 == LifecycleStateEnum.RUNNING) { 533 534 internalStopComponent(); 535 } 536 537 if (functionalImplementation 539 instanceof Destroyable) { 540 541 setLifecycleState( 544 LifecycleStateEnum.DESTROYING); 545 546 ((Destroyable) 547 functionalImplementation).destroy(); 548 } 549 } catch (Exception e) { 550 log.warn( 551 "Exception destroying component [" 552 + getComponentName() + "]: " + e + ": " 553 + ExceptionUtility.printStackTracesToString( 554 e)); 555 } 556 } 557 }, "Destroying component " + getComponentName()); 558 559 destroyer.setDaemon(true); 561 destroyer.start(); 562 563 destroyer.join(this.destroyerThreadTimeout); 565 566 if (destroyer.isAlive()) { 569 String message = "Destroy operation timed out after " 570 + this.destroyerThreadTimeout + " milliseconds"; 571 572 log.warn(message); 573 } 574 } else { 575 logNotSupported( 576 Destroyable.class); 577 } 578 579 setLifecycleState(LifecycleStateEnum.DESTROYED); 581 582 } catch (InterruptedException ie) { 583 String message = "Thread interrupted during attempt to destroy"; 584 throw new StateTransitionException( 585 this.getClass(), 586 message, ie); 587 588 } catch (Exception e) { 589 String message = "An error occurred while attempting to destroy"; 590 throw new StateTransitionException( 591 this.getClass(), 592 message, e); 593 594 } finally { 595 stopLifecycleMethod(); 596 } 597 } 598 599 605 public void setComponentReference(Component componentProxy) { 606 this.componentProxy = componentProxy; 607 } 608 609 610 628 protected void startLifecycleMethod() { 629 if (log.isTraceEnabled()) { 630 log.trace( 631 "Acquiring lock to start lifecycle method on component [" 632 + getComponentName() + "]"); 633 } 634 635 try { 636 this.proxyInvocationHandler.getMonitor().writeLock().attempt(1000); 637 } catch (InterruptedException ie) { 638 throw new StateTransitionException( 639 this.getClass(), 640 "Caught InterruptedException while trying to acquire the " 641 + "component's monitor", ie); 642 } 643 } 644 645 646 protected void stopLifecycleMethod() { 647 if (log.isTraceEnabled()) { 648 log.trace( 649 "Releasing lifecycle method write lock on component [" 650 + getComponentName() + "]"); 651 } 652 this.proxyInvocationHandler.getMonitor().writeLock().release(); 653 } 654 655 666 protected void internalSuspendComponent() 667 throws OperationNotSupportedException, StateTransitionException { 668 669 if (functionalImplementation instanceof Suspendable) { 670 callComponentSuspend(); 671 672 } else { 673 logNotSupported( 674 Suspendable.class); 675 } 676 677 setLifecycleState(LifecycleStateEnum.SUSPENDED); 679 } 680 681 692 protected void internalResumeComponent() 693 throws OperationNotSupportedException, StateTransitionException { 694 695 if (functionalImplementation instanceof Suspendable) { 696 callComponentResume(); 697 698 } else { 699 logNotSupported( 700 Suspendable.class); 701 } 702 703 setLifecycleState(LifecycleStateEnum.RUNNING); 705 } 706 707 718 protected void internalStopComponent() 719 throws OperationNotSupportedException, StateTransitionException { 720 721 if (functionalImplementation instanceof Startable) { 722 callComponentStop(); 723 724 } else { 725 logNotSupported( 726 Startable.class); 727 } 728 729 setLifecycleState(LifecycleStateEnum.STOPPED); 731 } 732 733 744 protected void waitForResume() 745 throws InvalidStateException, ComponentUnavailableException { 746 747 if (log.isTraceEnabled()) { 748 log.trace("Component [" 749 + this.getComponentName() 750 + "] suspended, waiting for it to resume"); 751 } 752 753 try { 754 this.proxyInvocationHandler.getMonitor().readLock().release(); 757 758 synchronized (suspendedLock) { 759 if (getLifecycleState() == LifecycleStateEnum.SUSPENDED) { 760 suspendedLock.wait(this.blockedCallTimeout); 761 } 762 } 763 764 } catch (InterruptedException ie) { 765 Thread.currentThread().interrupt(); 766 log.warn( 767 "Caught InterruptedException: " 768 + ExceptionUtility.printStackTracesToString(ie)); 769 770 } finally { 771 try { 773 this.proxyInvocationHandler.getMonitor().readLock().acquire(); 774 } catch (InterruptedException ie) { 775 Thread.currentThread().interrupt(); 776 throw new MonitorAcquisitionException(this.getClass(), 777 "Caught InterruptedException reaquiring the monitor", ie); 778 } 779 if (getLifecycleState() != LifecycleStateEnum.RUNNING) { 780 String message = 781 "Call to component timed out because it was in a " 782 + "transient lifecycle state, and did not return to " 783 + "RUNNING state soon enough to service the call " 784 + "or another thread changed the state before this one " 785 + "could execute the method call."; 786 throw new ComponentUnavailableException( 787 this.getClass(), message); 788 } 789 } 790 } 791 792 799 protected final void validateEntryState(LifecycleStateEnum entryState, 800 Set validStates) { 801 802 if (!validStates.contains(entryState)) { 803 final String message = 804 "The requested lifecycle operation can not be performed " 805 + "while in this state: [" 806 + entryState 807 + "]"; 808 809 throw new InvalidStateException(this.getClass(), message); 810 } 811 } 812 813 820 protected final void logNotSupported( 821 Class unImplementedInterface) { 822 823 if (log.isTraceEnabled()) { 824 log.trace( 825 "Cannot notify component of lifecycle operation. [" 826 + getComponentName() 827 + "] does not implement [" 828 + unImplementedInterface.getName() 829 + "]"); 830 } 831 } 832 833 838 protected final String getComponentName() { 839 if (this.componentProxy == null) { 840 return null; 841 } else { 842 return this.componentProxy.getComponentName(); 843 } 844 } 845 846 858 protected void killInvalidComponent() { 859 if (log.isInfoEnabled()) { 860 log.info( 861 "Destroying component [" 862 + getComponentName() 863 + "], it is in an unexpected state [" 864 + getLifecycleState() 865 + "]"); 866 } 867 destroyComponent(); 868 } 869 870 875 private void callComponentStart() { 876 LifecycleStateEnum entryState = getLifecycleState(); 877 try { 878 Startable subject = null; 879 subject = (Startable) functionalImplementation; 881 setLifecycleState(LifecycleStateEnum.STARTING); 883 subject.start(); 885 886 } catch (NonFatalStateTransitionException nfste) { 887 log.info( 888 "Caught NonFatalStateTransitionException, " 889 + "returning component to its original state. Component: [" 890 + getComponentName() 891 + "]"); 892 893 setLifecycleState(entryState); 894 throw nfste; 896 897 } catch (Exception e) { 898 String message = 899 "An Exception occurred while attempting to start [" 900 + getComponentName() + "]"; 901 throw new StateTransitionException( 902 this.getClass(), 903 message, e); 904 } 905 } 906 907 912 private void callComponentStop() { 913 LifecycleStateEnum entryState = getLifecycleState(); 914 try { 915 Startable subject = null; 916 subject = (Startable) functionalImplementation; 918 setLifecycleState(LifecycleStateEnum.STOPPING); 920 subject.stop(); 922 923 } catch (NonFatalStateTransitionException nfste) { 924 log.info( 925 "Caught NonFatalStateTransitionException, " 926 + "returning component to its original state. Component: [" 927 + getComponentName() 928 + "]"); 929 930 setLifecycleState(entryState); 931 throw nfste; 933 934 } catch (Exception e) { 935 String message = 936 "An Exception occurred while attempting to stop [" 937 + getComponentName() + "]"; 938 throw new StateTransitionException( 939 this.getClass(), 940 message, e); 941 } 942 } 943 944 954 private void callComponentConfigure(ComponentConfiguration configuration) { 955 LifecycleStateEnum entryState = getLifecycleState(); 956 LifecycleStateEnum lastGoodState = entryState; 957 try { 958 Configurable subject = (Configurable) functionalImplementation; 960 961 if (entryState == LifecycleStateEnum.RUNNING) { 963 internalSuspendComponent(); 964 lastGoodState = getLifecycleState(); 965 } 966 967 968 setLifecycleState(LifecycleStateEnum.CONFIGURING); 971 972 subject.configure(configuration); 974 975 if (entryState == LifecycleStateEnum.RUNNING) { 976 internalResumeComponent(); 978 } else { 979 this.setLifecycleState(entryState); 981 } 982 983 } catch (NonFatalStateTransitionException nfste) { 984 log.info( 985 "Caught NonFatalStateTransitionException, " 986 + "returning component to its original state. Component: [" 987 + getComponentName() 988 + "]"); 989 990 setLifecycleState(lastGoodState); 991 throw nfste; 993 994 } catch (Exception e) { 995 String message = 996 "An Exception occurred while attempting to configure [" 997 + getComponentName() + "]"; 998 throw new StateTransitionException( 999 this.getClass(), 1000 message, e); 1001 } 1002 } 1003 1004 1009 private void callComponentSuspend() { 1010 LifecycleStateEnum entryState = getLifecycleState(); 1011 try { 1012 Suspendable subject = null; 1013 subject = (Suspendable) functionalImplementation; 1015 setLifecycleState(LifecycleStateEnum.SUSPENDING); 1017 subject.suspend(); 1019 1020 } catch (NonFatalStateTransitionException nfste) { 1021 log.info( 1022 "Caught NonFatalStateTransitionException, " 1023 + "returning component to its original state. Component: [" 1024 + getComponentName() 1025 + "]"); 1026 1027 setLifecycleState(entryState); 1028 throw nfste; 1030 1031 } catch (Exception e) { 1032 String message = 1033 "An Exception occurred while attempting to suspend [" 1034 + getComponentName() + "]"; 1035 throw new StateTransitionException( 1036 getClass(), 1037 message, e); 1038 } 1039 } 1040 1041 1046 private void callComponentResume() { 1047 LifecycleStateEnum entryState = getLifecycleState(); 1048 try { 1049 Suspendable subject = null; 1050 subject = (Suspendable) functionalImplementation; 1052 setLifecycleState(LifecycleStateEnum.RESUMING); 1054 subject.resume(); 1056 1057 } catch (NonFatalStateTransitionException nfste) { 1058 log.info( 1059 "Caught NonFatalStateTransitionException, " 1060 + "returning component to its original state. Component: [" 1061 + getComponentName() 1062 + "]"); 1063 1064 setLifecycleState(entryState); 1065 throw nfste; 1067 1068 } catch (Exception e) { 1069 String message = 1070 "An Exception occurred while attempting to resume [" 1071 + getComponentName() + "]"; 1072 throw new StateTransitionException( 1073 this.getClass(), 1074 message, e); 1075 } 1076 } 1077 1078 1079 1080 1081 private static final Set VALID_ENTRY_STATES_INITIALIZE; 1082 1083 private static final Set VALID_ENTRY_STATES_START; 1084 1085 private static final Set VALID_ENTRY_STATES_STOP; 1086 1087 private static final Set VALID_ENTRY_STATES_SUSPEND; 1088 1089 private static final Set VALID_ENTRY_STATES_RESUME; 1090 1091 private static final Set VALID_ENTRY_STATES_CONFIGURE; 1092 1093 static { 1094 1095 1104 1105 1106 VALID_ENTRY_STATES_INITIALIZE = 1107 Collections.singleton(LifecycleStateEnum.CREATING); 1108 1109 1110 VALID_ENTRY_STATES_START = 1111 Collections.singleton(LifecycleStateEnum.STOPPED); 1112 1113 1114 HashSet validStates = new HashSet (); 1115 validStates.add(LifecycleStateEnum.RUNNING); 1116 validStates.add(LifecycleStateEnum.SUSPENDED); 1117 VALID_ENTRY_STATES_STOP = validStates; 1118 1119 1120 VALID_ENTRY_STATES_SUSPEND = 1121 Collections.singleton(LifecycleStateEnum.RUNNING); 1122 1123 1124 VALID_ENTRY_STATES_RESUME = 1125 Collections.singleton(LifecycleStateEnum.SUSPENDED); 1126 1127 1128 validStates = new HashSet (); 1129 validStates.add(LifecycleStateEnum.RUNNING); 1130 validStates.add(LifecycleStateEnum.SUSPENDED); 1131 validStates.add(LifecycleStateEnum.STOPPED); 1132 VALID_ENTRY_STATES_CONFIGURE = validStates; 1133 } 1134 1135} | Popular Tags |