1 22 package org.jboss.dependency.plugins; 23 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.Set ; 29 import java.util.concurrent.locks.ReentrantReadWriteLock ; 30 31 import org.jboss.dependency.spi.Controller; 32 import org.jboss.dependency.spi.ControllerContext; 33 import org.jboss.dependency.spi.ControllerMode; 34 import org.jboss.dependency.spi.ControllerState; 35 import org.jboss.dependency.spi.DependencyInfo; 36 import org.jboss.dependency.spi.DependencyItem; 37 import org.jboss.util.JBossObject; 38 import org.jboss.util.collection.CollectionsFactory; 39 40 46 public class AbstractController extends JBossObject implements Controller 47 { 48 49 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock (); 50 51 52 protected List <ControllerState> states = CollectionsFactory.createCopyOnWriteList(); 53 54 55 protected Map <Object , ControllerContext> allContexts = CollectionsFactory.createConcurrentReaderMap(); 56 57 58 protected Map <ControllerState, Set <ControllerContext>> contextsByState = CollectionsFactory.createConcurrentReaderMap(); 59 60 61 protected Map <Object , ControllerContext> errorContexts = CollectionsFactory.createConcurrentReaderMap(); 62 63 64 protected Set <ControllerContext> installing = CollectionsFactory.createCopyOnWriteSet(); 65 66 67 protected boolean onDemandEnabled = true; 68 69 74 public AbstractController() throws Exception 75 { 76 addState(ControllerState.NOT_INSTALLED, null); 77 addState(ControllerState.DESCRIBED, null); 78 addState(ControllerState.INSTANTIATED, null); 79 addState(ControllerState.CONFIGURED, null); 80 addState(ControllerState.CREATE, null); 81 addState(ControllerState.START, null); 82 addState(ControllerState.INSTALLED, null); 83 } 84 85 public void addState(ControllerState state, ControllerState before) 86 { 87 lockWrite(); 88 try 89 { 90 if (before == null) 91 { 92 states.add(state); 93 } 94 else 95 { 96 int index = states.indexOf(before); 97 if (index == -1) 98 throw new IllegalStateException (before + " is not a state in the controller."); 99 states.add(index, state); 100 } 101 102 Set <ControllerContext> contexts = CollectionsFactory.createCopyOnWriteSet(); 103 contextsByState.put(state, contexts); 104 } 105 finally 106 { 107 unlockWrite(); 108 } 109 } 110 111 public ControllerContext getContext(Object name, ControllerState state) 112 { 113 if (name == null) 114 throw new IllegalArgumentException ("Null name"); 115 116 lockRead(); 117 try 118 { 119 ControllerContext result = allContexts.get(name); 120 if (result != null && state != null) 121 { 122 int required = states.indexOf(state); 123 if (required == -1) 124 throw new IllegalArgumentException ("Unknown state " + state + " states=" + states); 125 int current = states.indexOf(result.getState()); 126 if (current < required) 127 return null; 128 } 129 return result; 130 } 131 finally 132 { 133 unlockRead(); 134 } 135 } 136 137 public ControllerContext getInstalledContext(Object name) 138 { 139 return getContext(name, ControllerState.INSTALLED); 140 } 141 142 public Set <ControllerContext> getNotInstalled() 143 { 144 lockWrite(); 145 try 146 { 147 Set <ControllerContext> result = new HashSet <ControllerContext>(errorContexts.values()); 148 for (int i = 0; ControllerState.INSTALLED.equals(states.get(i)) == false; ++i) 149 { 150 Set <ControllerContext> stateContexts = contextsByState.get(states.get(i)); 151 result.addAll(stateContexts); 152 } 153 return result; 154 } 155 finally 156 { 157 unlockWrite(); 158 } 159 } 160 161 public List <ControllerState> getStates() 162 { 163 return states; 164 } 165 166 public void install(ControllerContext context) throws Throwable 167 { 168 boolean trace = log.isTraceEnabled(); 169 170 if (context == null) 171 throw new IllegalArgumentException ("Null context"); 172 173 Object name = context.getName(); 174 if (name == null) 175 throw new IllegalArgumentException ("Null name " + context.toShortString()); 176 177 install(context, trace); 178 } 179 180 public void change(ControllerContext context, ControllerState state) throws Throwable 181 { 182 boolean trace = log.isTraceEnabled(); 183 184 if (context == null) 185 throw new IllegalArgumentException ("Null context"); 186 187 if (state == null) 188 throw new IllegalArgumentException ("Null state"); 189 190 change(context, state, trace); 191 } 192 193 public void enableOnDemand(ControllerContext context) throws Throwable 194 { 195 boolean trace = log.isTraceEnabled(); 196 197 if (context == null) 198 throw new IllegalArgumentException ("Null context"); 199 200 enableOnDemand(context, trace); 201 } 202 203 public ControllerContext uninstall(Object name) 204 { 205 boolean trace = log.isTraceEnabled(); 206 207 if (name == null) 208 throw new IllegalArgumentException ("Null name"); 209 210 lockWrite(); 211 try 212 { 213 if (errorContexts.remove(name) != null && trace) 214 log.trace("Tidied up context in error state: " + name); 215 216 ControllerContext context = allContexts.get(name); 217 if (context == null) 218 throw new IllegalStateException ("Not installed: " + name); 219 220 if (trace) 221 log.trace("Uninstalling " + context.toShortString()); 222 223 uninstallContext(context, ControllerState.NOT_INSTALLED, trace); 224 225 allContexts.remove(name); 226 return context; 227 } 228 finally 229 { 230 unlockWrite(); 231 } 232 } 233 234 241 protected void install(ControllerContext context, boolean trace) throws Throwable 242 { 243 lockWrite(); 244 try 245 { 246 Object name = context.getName(); 247 248 if (allContexts.get(name) != null) 249 throw new IllegalStateException (name + " is already installed."); 250 251 if (ControllerMode.AUTOMATIC.equals(context.getMode())) 252 context.setRequiredState(ControllerState.INSTALLED); 253 254 if (trace) 255 log.trace("Installing " + context.toShortString()); 256 257 context.setController(this); 258 DependencyInfo dependencies = context.getDependencyInfo(); 259 if (trace) 260 { 261 String dependsOn = null; 262 if( dependencies != null ) 263 { 264 Set set = dependencies.getIDependOn(null); 265 if( set != null ) 266 dependsOn = set.toString(); 267 } 268 log.trace("Dependencies for " + name + ": " + dependsOn); 269 } 270 271 if (incrementState(context, trace)) 272 { 273 allContexts.put(context.getName(), context); 274 resolveContexts(trace); 275 } 276 else 277 { 278 errorContexts.remove(context); 279 throw context.getError(); 280 } 281 } 282 finally 283 { 284 unlockWrite(); 285 } 286 } 287 288 296 protected void change(ControllerContext context, ControllerState state, boolean trace) throws Throwable 297 { 298 lockWrite(); 299 try 300 { 301 ControllerState fromState = context.getState(); 302 int currentIndex = states.indexOf(fromState); 303 int requiredIndex = states.indexOf(state); 304 if (requiredIndex == -1) 305 throw new IllegalArgumentException ("Unknown state: " + state); 306 307 if (currentIndex == requiredIndex) 308 { 309 if (trace) 310 log.trace("No change required toState=" + state.getStateString() + " " + context.toShortString()); 311 return; 312 } 313 314 if (trace) 315 log.trace("Change toState=" + state.getStateString() + " " + context.toShortString()); 316 317 context.setRequiredState(state); 318 319 if (currentIndex < requiredIndex) 320 resolveContexts(trace); 321 else 322 { 323 while (currentIndex > requiredIndex) 324 { 325 uninstallContext(context, trace); 326 currentIndex = states.indexOf(context.getState()); 327 } 328 } 329 } 330 finally 331 { 332 unlockWrite(); 333 } 334 } 335 336 343 protected void enableOnDemand(ControllerContext context, boolean trace) throws Throwable 344 { 345 lockWrite(); 346 try 347 { 348 if (ControllerMode.ON_DEMAND.equals(context.getMode()) == false) 349 throw new IllegalStateException ("Context is not ON DEMAND: " + context.toShortString()); 350 351 if (allContexts.containsKey(context.getName()) == false) 352 throw new IllegalStateException ("Unknown context: " + context.toShortString()); 353 354 if (ControllerState.INSTALLED.equals(context.getRequiredState())) 356 return; 357 context.setRequiredState(ControllerState.INSTALLED); 358 359 if (trace) 360 log.trace("Enable onDemand: " + context.toShortString()); 361 362 onDemandEnabled = true; 363 } 364 finally 365 { 366 unlockWrite(); 367 } 368 } 369 370 379 protected boolean incrementState(ControllerContext context, boolean trace) 380 { 381 ControllerState fromState = context.getState(); 382 383 Set fromContexts = null; 384 385 int currentIndex = -1; 386 if (ControllerState.ERROR.equals(fromState)) 387 { 388 errorContexts.remove(context); 389 Throwable error = null; 390 unlockWrite(); 391 try 392 { 393 install(context, ControllerState.ERROR, ControllerState.NOT_INSTALLED); 394 } 395 catch (Throwable t) 396 { 397 error = t; 398 } 399 finally 400 { 401 lockWrite(); 402 if (error != null) 403 { 404 log.error("Error during initial installation: " + context.toShortString(), error); 405 context.setError(error); 406 errorContexts.put(context.getName(), context); 407 return false; 408 } 409 } 410 Set <ControllerContext> notInstalled = contextsByState.get(ControllerState.NOT_INSTALLED); 411 notInstalled.add(context); 412 } 413 else 414 { 415 currentIndex = states.indexOf(fromState); 416 fromContexts = contextsByState.get(fromState); 417 if (fromContexts.contains(context) == false) 418 throw new IllegalStateException ("Context not found in previous state: " + context.toShortString()); 419 } 420 421 int toIndex = currentIndex + 1; 422 ControllerState toState = states.get(toIndex); 423 Set <ControllerContext> toContexts = contextsByState.get(toState); 424 425 unlockWrite(); 426 Throwable error = null; 427 try 428 { 429 install(context, fromState, toState); 430 } 431 catch (Throwable t) 432 { 433 error = t; 434 } 435 finally 436 { 437 lockWrite(); 438 if (error != null) 439 { 440 log.error("Error installing to " + toState.getStateString() + ": " + context.toShortString(), error); 441 uninstallContext(context, ControllerState.NOT_INSTALLED, trace); 442 errorContexts.put(context.getName(), context); 443 context.setError(error); 444 return false; 445 } 446 } 447 448 if (fromContexts != null) 449 fromContexts.remove(context); 450 toContexts.add(context); 451 return true; 452 } 453 454 461 protected void resolveContexts(boolean trace) 462 { 463 boolean resolutions = true; 464 while (resolutions || onDemandEnabled) 465 { 466 onDemandEnabled = false; 467 resolutions = false; 468 for (int i = 0; i < states.size()-1; ++i) 469 { 470 ControllerState fromState = states.get(i); 471 ControllerState toState = states.get(i+1); 472 if (resolveContexts(fromState, toState, trace)) 473 { 474 resolutions = true; 475 break; 476 } 477 } 478 } 479 480 if (trace) 481 { 482 for (int i = 0; i < states.size()-1; ++i) 483 { 484 ControllerState state = states.get(i); 485 ControllerState nextState = states.get(i+1); 486 Set <ControllerContext> stillUnresolved = contextsByState.get(state); 487 if (stillUnresolved.isEmpty() == false) 488 { 489 for (Iterator j = stillUnresolved.iterator(); j.hasNext();) 490 { 491 ControllerContext ctx = (ControllerContext) j.next(); 492 if (advance(ctx)) 493 log.trace("Still unresolved " + nextState.getStateString() + ": " + ctx); 494 } 495 } 496 } 497 } 498 } 499 500 510 protected boolean resolveContexts(ControllerState fromState, ControllerState toState, boolean trace) 511 { 512 boolean resolutions = false; 513 Set <ControllerContext> unresolved = contextsByState.get(fromState); 514 Set <ControllerContext> resolved = resolveContexts(unresolved, toState, trace); 515 if (resolved.isEmpty() == false) 516 { 517 for (Iterator i = resolved.iterator(); i.hasNext();) 518 { 519 ControllerContext context = (ControllerContext) i.next(); 520 Object name = context.getName(); 521 if (fromState.equals(context.getState()) == false) 522 { 523 if (trace) 524 log.trace("Skipping already installed " + name + " for " + toState.getStateString()); 525 } 526 else if (installing.add(context) == false) 527 { 528 if (trace) 529 log.trace("Already installing " + name + " for " + toState.getStateString()); 530 } 531 else 532 { 533 try 534 { 535 if (trace) 536 log.trace("Dependencies resolved " + name + " for " + toState.getStateString()); 537 538 if (incrementState(context, trace)) 539 { 540 resolutions = true; 541 if (trace) 542 log.trace(name + " " + toState.getStateString()); 543 } 544 } 545 finally 546 { 547 installing.remove(context); 548 } 549 } 550 } 551 } 552 553 return resolutions; 554 } 555 556 566 protected Set <ControllerContext> resolveContexts(Set <ControllerContext> contexts, ControllerState state, boolean trace) 567 { 568 HashSet <ControllerContext> result = new HashSet <ControllerContext>(); 569 570 if (contexts.isEmpty() == false) 571 { 572 for (Iterator i = contexts.iterator(); i.hasNext();) 573 { 574 ControllerContext ctx = (ControllerContext) i.next(); 575 if (advance(ctx)) 576 { 577 DependencyInfo dependencies = ctx.getDependencyInfo(); 578 if (dependencies.resolveDependencies(this, state)) 579 result.add(ctx); 580 } 581 } 582 } 583 584 return result; 585 } 586 587 596 protected void uninstallContext(ControllerContext context, ControllerState toState, boolean trace) 597 { 598 int targetState = states.indexOf(toState); 599 if (targetState == -1) 600 log.error("INTERNAL ERROR: unknown state " + toState + " states=" + states, new Exception ("STACKTRACE")); 601 602 while (true) 603 { 604 ControllerState fromState = context.getState(); 605 if (ControllerState.ERROR.equals(fromState)) 606 return; 607 int currentState = states.indexOf(fromState); 608 if (currentState == -1) 609 log.error("INTERNAL ERROR: current state not found: " + context.toShortString(), new Exception ("STACKTRACE")); 610 if (targetState > currentState) 611 return; 612 else 613 uninstallContext(context, trace); 614 } 615 } 616 617 625 protected void uninstallContext(ControllerContext context, boolean trace) 626 { 627 Object name = context.getName(); 628 629 ControllerState fromState = context.getState(); 630 int currentIndex = states.indexOf(fromState); 631 632 if (trace) 633 log.trace("Uninstalling " + name + " from " + fromState.getStateString()); 634 635 Set <ControllerContext> fromContexts = contextsByState.get(fromState); 636 if (fromContexts == null || fromContexts.remove(context) == false) 637 { 638 log.error("INTERNAL ERROR: context not found in previous state " + fromState.getStateString() + " context=" + context.toShortString(), new Exception ("STACKTRACE")); 639 return; 640 } 641 642 DependencyInfo dependencies = context.getDependencyInfo(); 643 Set dependsOnMe = dependencies.getDependsOnMe(null); 644 if (dependsOnMe.isEmpty() == false) 645 { 646 for (Iterator i = dependsOnMe.iterator(); i.hasNext();) 647 { 648 DependencyItem item = (DependencyItem) i.next(); 649 if (item.isResolved()) 650 { 651 ControllerState dependentState = item.getDependentState(); 652 if (dependentState == null || dependentState.equals(fromState)) 653 { 654 item.unresolved(this); 655 ControllerContext dependent = getContext(item.getName(), null); 656 if (dependent != null) 657 { 658 ControllerState whenRequired = item.getWhenRequired(); 659 if (whenRequired == null) 660 whenRequired = ControllerState.NOT_INSTALLED; 661 int proposed = states.indexOf(whenRequired); 662 int actual = states.indexOf(dependent.getState()); 663 if (proposed <= actual) 664 uninstallContext(dependent, whenRequired, trace); 665 } 666 } 667 } 668 } 669 } 670 671 int toIndex = currentIndex-1; 672 if (toIndex == -1) 673 { 674 context.setError(new IllegalStateException ("Cannot uninstall from " + fromState)); 675 return; 676 } 677 678 ControllerState toState = states.get(toIndex); 679 Set <ControllerContext> toContexts = contextsByState.get(toState); 680 toContexts.add(context); 681 682 unlockWrite(); 683 try 684 { 685 uninstall(context, fromState, toState); 686 } 687 catch (Throwable t) 688 { 689 log.warn("Error uninstalling from " + fromState.getStateString() + ": " + context.toShortString(), t); 690 } 691 finally 692 { 693 lockWrite(); 694 } 695 } 696 697 707 protected void install(ControllerContext context, ControllerState fromState, ControllerState toState) throws Throwable 708 { 709 context.install(fromState, toState); 710 } 711 712 721 protected void uninstall(ControllerContext context, ControllerState fromState, ControllerState toState) 722 { 723 context.uninstall(fromState, toState); 724 } 725 726 734 protected boolean advance(ControllerContext context) 735 { 736 ControllerMode mode = context.getMode(); 737 738 if (ControllerMode.DISABLED.equals(mode)) 740 return false; 741 742 ControllerState fromState = context.getState(); 743 int fromIndex = states.indexOf(fromState); 744 ControllerState requiredState = context.getRequiredState(); 745 int requiredIndex = states.indexOf(requiredState); 746 747 return fromIndex < requiredIndex; 748 } 749 750 753 protected void lockRead() 754 { 755 lock.readLock().lock(); 756 } 757 758 761 protected void unlockRead() 762 { 763 lock.readLock().unlock(); 764 } 765 766 769 protected void lockWrite() 770 { 771 lock.writeLock().lock(); 772 } 773 774 777 protected void unlockWrite() 778 { 779 lock.writeLock().unlock(); 780 } 781 } 782 | Popular Tags |