1 9 package org.jboss.portal.core.impl.tree; 10 11 import org.jboss.cache.Fqn; 12 import org.jboss.cache.TreeCacheListener; 13 import org.jboss.cache.TreeCache; 14 import org.jboss.cache.CacheException; 15 import org.jboss.cache.PropertyConfigurator; 16 import org.jboss.cache.DummyTransactionManagerLookup; 17 import org.jboss.cache.TransactionManagerLookup; 18 import org.jboss.cache.loader.CacheLoader; 19 import org.jboss.cache.interceptors.Interceptor; 20 import org.jboss.cache.lock.IsolationLevel; 21 import org.jboss.portal.server.util.Service; 22 import org.jboss.portal.common.transaction.TransactionManagerProvider; 23 import org.jboss.portal.common.FQN; 24 import org.jboss.portal.common.util.Tools; 25 import org.jboss.portal.common.tree.Tree; 26 import org.jboss.portal.common.tree.NodeChangeListener; 27 import org.jboss.portal.common.tree.Session; 28 import org.jboss.portal.common.tree.Node; 29 import org.jboss.portal.core.impl.tree.tm.TransactionManagerObserver; 30 import org.jboss.util.StringPropertyReplacer; 31 import org.jgroups.View; 32 import org.jgroups.blocks.MethodCall; 33 import org.apache.log4j.Logger; 34 35 import java.util.Map ; 36 import java.util.List ; 37 import java.util.ArrayList ; 38 import java.util.LinkedList ; 39 import java.util.HashMap ; 40 import java.util.Iterator ; 41 import java.util.Collections ; 42 import java.util.Set ; 43 import java.util.HashSet ; 44 import java.lang.reflect.Method ; 45 import java.io.ObjectOutputStream ; 46 import java.io.ByteArrayOutputStream ; 47 import java.io.IOException ; 48 import java.io.ByteArrayInputStream ; 49 import java.io.ObjectInputStream ; 50 import java.io.File ; 51 52 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 53 54 import javax.transaction.TransactionManager ; 55 import javax.transaction.Transaction ; 56 import javax.transaction.NotSupportedException ; 57 import javax.transaction.SystemException ; 58 59 67 public class TreeImpl 68 extends Service 69 implements Tree, 70 TreeCacheListener, 71 TransactionManagerProvider, 72 NodeStateEventListener 73 { 74 75 76 private Logger log = Logger.getLogger(TreeImpl.class); 77 78 79 private TreeCache cache; 80 81 82 private List listeners; 83 84 85 private Map nodeMap; 86 87 88 private NodeImpl root; 89 90 91 private TransactionManagerObserver observer; 92 93 94 private NodeStateEventAdapter eventAdapter; 95 96 97 private String cacheConfiguration; 98 99 public TreeImpl() 100 { 101 try 102 { 103 listeners = new LinkedList (); 104 nodeMap = new ConcurrentReaderHashMap(); 105 root = new NodeImpl(this, new Fqn()); 106 nodeMap.put(root.fqn, root); 107 } 108 catch (Exception e) 109 { 110 throw new Error (e); 111 } 112 } 113 114 116 public void handle(NodeStateEvent[] events) 117 { 118 try 119 { 120 for (int i = 0; i < events.length; i++) 122 { 123 NodeStateEvent nodeStateEvent = events[i]; 124 switch (nodeStateEvent.getStatus()) 125 { 126 case NodeStateEvent.STATUS_CREATED: 127 { 128 Fqn childFqn = nodeStateEvent.getFqn(); 129 Fqn parentFqn = getParentFqn(childFqn); 130 FQN parentID = toFQN(parentFqn); 131 NodeImpl child = (NodeImpl)nodeMap.get(childFqn); 132 String childName = child.getName(); 133 134 Map properties = ((org.jboss.cache.Node)cache.get(childFqn)).getData(); 136 for (Iterator j = properties.values().iterator(); j.hasNext();) 137 { 138 Property prop = (Property)j.next(); 139 140 String propName = prop.getName(); 142 String propID = prop.getID(); 143 144 child.ids.put(propName, propID); 146 } 147 148 for (Iterator j = listeners.iterator(); j.hasNext();) 150 { 151 NodeChangeListener listener = (NodeChangeListener)j.next(); 152 listener.childAdded(parentID, childName); 153 } 154 break; 155 } 156 case NodeStateEvent.STATUS_MODIFIED: 157 { 158 Fqn fqn = nodeStateEvent.getFqn(); 159 NodeImpl node = (NodeImpl)nodeMap.get(fqn); 160 161 Set addedProps = new HashSet (); 163 Set changedProps = new HashSet (); 164 Map tmp = new HashMap (node.ids); 165 Map properties = ((org.jboss.cache.Node)cache.get(fqn)).getData(); 166 for (Iterator j = properties.values().iterator(); j.hasNext();) 167 { 168 Property prop = (Property)j.next(); 169 String id = (String )tmp.remove(prop.getName()); 170 if (id == null) 171 { 172 addedProps.add(prop.getName()); 173 } 174 else if (!id.equals(prop.getID())) 175 { 176 changedProps.add(prop.getName()); 177 } 178 } 179 Set removedProps = tmp.keySet(); 180 181 for (Iterator j = addedProps.iterator(); j.hasNext();) 183 { 184 String key = (String )j.next(); 185 for (Iterator k = listeners.iterator(); k.hasNext();) 186 { 187 NodeChangeListener listener = (NodeChangeListener)k.next(); 188 listener.propertyAdded(node.getID(), key); 189 } 190 } 191 for (Iterator j = changedProps.iterator(); j.hasNext();) 192 { 193 String key = (String )j.next(); 194 for (Iterator k = listeners.iterator(); k.hasNext();) 195 { 196 NodeChangeListener listener = (NodeChangeListener)k.next(); 197 listener.propertyChanged(node.getID(), key); 198 } 199 } 200 for (Iterator j = removedProps.iterator(); j.hasNext();) 201 { 202 String key = (String )j.next(); 203 for (Iterator k = listeners.iterator(); k.hasNext();) 204 { 205 NodeChangeListener listener = (NodeChangeListener)k.next(); 206 listener.propertyRemoved(node.getID(), key); 207 } 208 } 209 210 node.ids.clear(); 212 for (Iterator j = properties.values().iterator(); j.hasNext();) 213 { 214 Property prop = (Property)j.next(); 215 node.ids.put(prop.getName(), prop.getID()); 216 } 217 218 break; 219 } 220 case NodeStateEvent.STATUS_REMOVED: 221 { 222 Fqn childFqn = nodeStateEvent.getFqn(); 223 Fqn parentFqn = getParentFqn(childFqn); 224 FQN parentID = toFQN(parentFqn); 225 String childName = (String )childFqn.get(childFqn.size() - 1); 226 227 for (Iterator j = listeners.iterator(); j.hasNext();) 229 { 230 NodeChangeListener listener = (NodeChangeListener)j.next(); 231 listener.childRemoved(parentID, childName); 232 } 233 break; 234 } 235 default: 236 throw new Error (); 237 } 238 } 239 } 240 catch (CacheException e) 241 { 242 log.error("", e); 243 } 244 } 245 246 248 protected void createService() throws Exception 249 { 250 cache = new FixedTreeCache(); 251 if (cacheConfiguration == null) 252 { 253 cache.setCacheMode(TreeCache.LOCAL); 255 cache.setIsolationLevel(IsolationLevel.REPEATABLE_READ); 256 cache.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName()); 257 } 258 else 259 { 260 String config = StringPropertyReplacer.replaceProperties(cacheConfiguration); 261 log.debug("Cache configuration " + config); 262 PropertyConfigurator configurator = new PropertyConfigurator(); 263 configurator.configure(cache, config); 264 } 265 266 Class lookupClass = Thread.currentThread().getContextClassLoader().loadClass(cache.getTransactionManagerLookupClass()); 268 TransactionManagerLookup lookup = (TransactionManagerLookup)lookupClass.newInstance(); 269 TransactionManagerProvider provider = new JBossCacheTransactionManagerAdapter(lookup); 270 observer = new TransactionManagerObserver(provider.getTransactionManager()); 271 272 cache.setTransactionManagerLookup(observer); 274 275 eventAdapter = new NodeStateEventAdapter(observer, this); 277 278 cache.create(); 280 281 cache.addTreeCacheListener(this); 283 } 284 285 protected void startService() throws Exception 286 { 287 cache.start(); 288 } 289 290 protected void stopService() 291 { 292 cache.stop(); 293 } 294 295 protected void destroyService() 296 { 297 cache.destroy(); 298 cache = null; 299 eventAdapter = null; 300 observer = null; 301 } 302 303 public TreeCache getCache() 304 { 305 return cache; 306 } 307 308 311 public String getCacheConfiguration() 312 { 313 return cacheConfiguration; 314 } 315 316 319 public void setCacheConfiguration(String cacheConfiguration) 320 { 321 this.cacheConfiguration = cacheConfiguration; 322 } 323 324 326 331 public Node getNode(FQN fqn) 332 { 333 return (Node)nodeMap.get(toFqn(fqn)); 334 } 335 336 340 public Session getSession() 341 { 342 try 343 { 344 TransactionManager tm = cache.getTransactionManager(); 345 tm.begin(); 346 Transaction tx = tm.getTransaction(); 347 return new SessionImpl(this, tx); 348 } 349 catch (NotSupportedException e) 350 { 351 log.error("", e); 352 return null; 353 } 354 catch (SystemException e) 355 { 356 log.error("", e); 357 return null; 358 } 359 } 360 361 365 public Node getRoot() 366 { 367 return root; 368 } 369 370 375 public void addNodeChangeListener(NodeChangeListener listener) 376 { 377 synchronized (listeners) 378 { 379 List listeners = new ArrayList (this.listeners); 380 listeners.add(listener); 381 this.listeners = listeners; 382 } 383 } 384 385 390 public void removeNodeChangeListener(NodeChangeListener listener) 391 { 392 synchronized (listeners) 393 { 394 List listeners = new ArrayList (this.listeners); 395 listeners.remove(listener); 396 this.listeners = listeners; 397 } 398 } 399 400 402 Object getProperty(NodeImpl node, String name) 403 { 404 try 405 { 406 Property prop = (Property)cache.get(node.fqn, name); 407 if (prop == null) 408 { 409 return null; 410 } 411 else 412 { 413 return prop.getValue(); 414 } 415 } 416 catch (CacheException e) 417 { 418 log.error("", e); 419 return null; 420 } 421 } 422 423 void setProperty(NodeImpl node, String key, Object value) 424 { 425 try 426 { 427 Property prop = new Property(key, value); 428 cache.put(node.fqn, key, prop); 429 } 430 catch (CacheException e) 431 { 432 log.error("", e); 433 } 434 } 435 436 void removeProperty(NodeImpl node, String key) 437 { 438 try 439 { 440 cache.remove(node.fqn, key); 441 } 442 catch (CacheException e) 443 { 444 log.error("", e); 445 } 446 } 447 448 NodeImpl getChild(NodeImpl node, String key) 449 { 450 return (NodeImpl)nodeMap.get(new Fqn(node.fqn, key)); 451 } 452 453 Map getChildren(NodeImpl node) 454 { 455 try 456 { 457 Map children = new HashMap (); 458 for (Iterator i = cache.getChildrenNames(node.fqn).iterator(); i.hasNext();) 459 { 460 String key = (String )i.next(); 461 Node child = (Node)nodeMap.get(new Fqn(node.fqn, key)); 462 children.put(key, child); 463 } 464 return children; 465 } 466 catch (CacheException e) 467 { 468 log.error("", e); 469 return Collections.EMPTY_MAP; 470 } 471 } 472 473 NodeImpl addChild(NodeImpl parent, String key, Map properties) 474 { 475 try 476 { 477 Fqn childFqn = new Fqn(parent.fqn, key); 479 480 properties = formatProperties(properties); 482 483 cache.put(childFqn, properties); 485 return (NodeImpl)nodeMap.get(childFqn); 486 } 487 catch (CacheException e) 488 { 489 log.error("", e); 490 return null; 491 } 492 } 493 494 void removeChild(NodeImpl parent, String key) 495 { 496 try 497 { 498 Fqn childFqn = new Fqn(parent.fqn, key); 499 cache.remove(childFqn); 500 } 501 catch (CacheException e) 502 { 503 log.error("", e); 504 } 505 } 506 507 NodeImpl addNode(FQN id, Map properties) 508 { 509 Fqn fqn = toFqn(id); 510 if (nodeMap.containsKey(fqn)) 511 { 512 throw new IllegalArgumentException ("Duplicate node"); 513 } 514 try 515 { 516 properties = formatProperties(properties); 517 cache.put(fqn, properties); 518 return (NodeImpl)nodeMap.get(fqn); 519 } 520 catch (Exception e) 521 { 522 log.error("", e); 523 return null; 524 } 525 } 526 527 529 public TransactionManager getTransactionManager() 530 { 531 return observer; 532 } 533 534 536 public void nodeCreated(Fqn fqn) 537 { 538 if (!fqn.equals(new Fqn())) 540 { 541 NodeImpl child = new NodeImpl(this, fqn); 543 nodeMap.put(fqn, child); 544 545 try 547 { 548 eventAdapter.created(fqn); 549 } 550 catch (IllegalStateException e) 551 { 552 log.error("An error occured during node created", e); 553 } 554 } 555 } 556 557 public void nodeRemoved(Fqn fqn) 558 { 559 if (!fqn.equals(new Fqn())) 561 { 562 nodeMap.remove(fqn); 564 565 try 567 { 568 eventAdapter.removed(fqn); 569 } 570 catch (Exception e) 571 { 572 log.error("An error occured during node removed", e); 573 } 574 } 575 } 576 577 public void nodeModified(Fqn fqn) 578 { 579 try 581 { 582 eventAdapter.modified(fqn); 583 } 584 catch (IllegalStateException e) 585 { 586 log.error("An error occured during node modified", e); 587 } 588 } 589 590 public void nodeLoaded(Fqn fqn) 591 { 592 nodeCreated(fqn); 593 } 594 595 public void nodeEvicted(Fqn fqn) 596 { 597 } 599 600 public void nodeVisited(Fqn fqn) 601 { 602 } 603 604 public void cacheStarted(TreeCache cache) 605 { 606 } 607 608 public void cacheStopped(TreeCache cache) 609 { 610 } 611 612 public void viewChange(View view) 613 { 614 } 615 616 619 public static Fqn getParentFqn(Fqn childFqn) 620 { 621 Object [] parentObjects = new Object [childFqn.size() - 1]; 622 for (int j = 0; j < parentObjects.length; j++) 623 { 624 Object parentObject = childFqn.get(j); 625 parentObjects[j] = parentObject; 626 } 627 Fqn parentFqn = new Fqn(parentObjects); 628 return parentFqn; 629 } 630 631 public static Fqn toFqn(FQN fqn) 632 { 633 return new Fqn(fqn.toArray()); 634 } 635 636 public static FQN toFQN(Fqn fqn) 637 { 638 String [] names = new String [fqn.size()]; 639 for (int i = 0; i < names.length; i++) 640 { 641 names[i] = (String )fqn.get(i); 642 } 643 return new FQN(names); 644 } 645 646 private Map formatProperties(Map properties) 647 { 648 properties = new HashMap (properties); 649 for (Iterator i = properties.entrySet().iterator(); i.hasNext();) 650 { 651 Map.Entry entry = (Map.Entry )i.next(); 652 String name = (String )entry.getKey(); 653 Object value = entry.getValue(); 654 entry.setValue(new Property(name, value)); 655 } 656 return properties; 657 } 658 659 661 664 protected class FixedTreeCache extends TreeCache 665 { 666 public FixedTreeCache() throws Exception 667 { 668 } 669 670 protected void createInterceptorChain() throws IllegalAccessException , InstantiationException , ClassNotFoundException 671 { 672 super.createInterceptorChain(); 673 674 Interceptor previous = null; 677 for (Interceptor current = interceptor_chain; current != null; current = current.getNext()) 678 { 679 log.debug("Iterating cache interceptors " + current.getClass().getName()); 680 if ("org.jboss.cache.interceptors.CacheLoaderInterceptor".equals(current.getClass().getName())) 681 { 682 log.debug("Replacing current cache loader interceptor with fixed version one"); 683 684 Interceptor interceptor = new FixedCacheLoaderInterceptor(); 686 interceptor.setCache(this); 687 688 interceptor.setNext(current.getNext()); 690 if (previous == null) 691 { 692 interceptor_chain = interceptor; 693 } 694 else 695 { 696 previous.setNext(interceptor); 697 } 698 break; 699 } 700 else 701 { 702 previous = current; 703 } 704 } 705 } 706 } 707 708 712 private static class FixedCacheLoaderInterceptor extends Interceptor 713 { 714 private CacheLoader loader = null; 715 private TreeCache cache = null; 716 private Logger log = null; 717 718 public FixedCacheLoaderInterceptor() 719 { 720 log = Logger.getLogger(FixedCacheLoaderInterceptor.class); 721 } 722 723 public void setCache(TreeCache cache) 724 { 725 super.setCache(cache); 726 this.cache = cache; 727 this.loader = cache.getCacheLoader(); 728 } 729 730 738 public Object invoke(MethodCall m) throws Throwable 739 { 740 Fqn fqn = null; 741 org.jboss.cache.Node n = null; 742 Method meth = m.getMethod(); 743 Object [] args = m.getArgs(); 744 boolean load_attributes = false; 746 747 749 synchronized (this) 750 { 751 752 if (meth.equals(TreeCache.putDataMethodLocal) || meth.equals(TreeCache.putDataEraseMethodLocal) || 753 meth.equals(TreeCache.putKeyValMethodLocal)) 754 { 755 fqn = (Fqn)args[1]; 756 load_attributes = true; 757 } 758 else if (meth.equals(TreeCache.removeNodeMethodLocal)) 759 { 760 } 762 else if (meth.equals(TreeCache.removeKeyMethodLocal) || meth.equals(TreeCache.removeDataMethodLocal)) 763 { 764 fqn = (Fqn)args[1]; 765 load_attributes = true; 766 } 767 else if (meth.equals(TreeCache.addChildMethodLocal)) 768 { 769 fqn = (Fqn)args[1]; 770 } 771 else if (meth.equals(TreeCache.getKeyValueMethodLocal)) 772 { 773 fqn = (Fqn)args[0]; 774 load_attributes = true; 775 } 776 else if (meth.equals(TreeCache.getNodeMethodLocal)) 777 { 778 fqn = (Fqn)args[0]; 779 } 780 else if (meth.equals(TreeCache.getKeysMethodLocal)) 781 { 782 fqn = (Fqn)args[0]; 783 load_attributes = true; 784 } 785 else if (meth.equals(TreeCache.getChildrenNamesMethodLocal) || meth.equals(TreeCache.releaseAllLocksMethodLocal) || 786 meth.equals(TreeCache.printMethodLocal)) 787 { 788 fqn = (Fqn)args[0]; 789 } 790 791 if (fqn != null) 792 { 793 n = loadNode(fqn, load_attributes); 794 if (load_attributes && n != null) 795 { 796 loadAttributesFromCacheLoader(n); 797 } 798 } 799 800 if (meth.equals(TreeCache.getChildrenNamesMethodLocal) && n != null && fqn != null) 803 { 804 Map children = n.getChildren(); 805 806 if (children == null) 807 { 808 Set children_names = null; 809 try 810 { 811 children_names = loader.getChildrenNames(fqn); 812 } 813 catch (Exception e) 814 { 815 log.error("failed getting the children names for " + fqn + " from the cache loader", e); 816 } 817 if (children_names != null) 818 { 819 for (Iterator it = children_names.iterator(); it.hasNext();) 821 { 822 String child_name = (String )it.next(); 823 Fqn child_fqn = new Fqn(n.getFqn(), child_name); 824 n.createChild(child_name, child_fqn, n, TreeCache.UNINITIALIZED, null); 825 } 826 } 827 } 828 } 829 } 830 831 return super.invoke(m); 832 } 833 834 835 private org.jboss.cache.Node loadNode(Fqn fqn, boolean willAttrsBeLoaded) 836 { 837 org.jboss.cache.Node n, child_node = null; 838 Object child_name; 839 Fqn tmp_fqn = new Fqn(); 840 841 if (fqn == null) 842 { 843 return null; 844 } 845 int treeNodeSize = fqn.size(); 846 847 n = cache.getRoot(); 848 for (int i = 0; i < treeNodeSize && n != null; i++) 849 { 850 child_name = fqn.get(i); 851 tmp_fqn = new Fqn(tmp_fqn, child_name); 852 child_node = n.getChild(child_name); 853 854 if (child_node == null) 856 { 857 try 858 { 859 if (loader.exists(fqn)) 860 { 861 child_node = n.createChild(child_name, tmp_fqn, n, TreeCache.UNINITIALIZED, null); 862 if (willAttrsBeLoaded == false) 863 { 864 cache.notifyNodeLoaded(tmp_fqn); 865 } 866 } 867 } 868 catch (Throwable t) 869 { 870 log.error("failure loading node " + fqn + " from CacheLoader", t); 871 } 872 } 873 n = child_node; 874 } 875 return n; 876 } 877 878 879 private void loadAttributesFromCacheLoader(org.jboss.cache.Node n) 880 { 881 if (n == null || !n.containsKey(TreeCache.UNINITIALIZED)) 882 { 883 return; 884 } 885 886 try 888 { 889 Map m = loader.get(n.getFqn()); 890 n.remove(TreeCache.UNINITIALIZED); n.put(m); 892 cache.notifyNodeLoaded(n.getFqn()); 893 } 894 catch (Throwable t) 895 { 896 log.error("failure when lazily loading attributes of " + n.getFqn(), t); 897 } 898 } 899 } 900 } 901 | Popular Tags |