1 17 18 package org.sape.carbon.core.config.node; 19 20 import java.util.Collection ; 21 import java.util.Collections ; 22 import java.util.HashMap ; 23 import java.util.HashSet ; 24 import java.util.Iterator ; 25 import java.util.Map ; 26 import java.util.Set ; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 31 import org.sape.carbon.core.config.InvalidConfigurationException; 32 import org.sape.carbon.core.config.node.event.NodeEventListener; 33 import org.sape.carbon.core.exception.ExceptionUtility; 34 import org.sape.carbon.core.exception.InvalidParameterException; 35 36 46 public abstract class AbstractNode implements Node { 47 48 51 private Log log = LogFactory.getLog(this.getClass()); 52 53 54 private final String name; 55 56 57 private final Node parent; 58 59 60 private boolean removed = false; 61 62 71 private final Object addOrLoadChildLock; 72 73 81 private final Object readOrAlterNodeLock; 82 83 90 protected final Map childNodes = new HashMap (); 91 92 95 protected final Set nodeListeners = 96 Collections.synchronizedSet(new HashSet ()); 97 98 106 public AbstractNode(Node parent, String name) { 107 this(parent, name, new Object (), new Object ()); 108 } 109 110 121 public AbstractNode( 122 Node parent, 123 String name, 124 Object readOrAlterNodeLock, 125 Object addOrLoadChildLock) { 126 127 if (name == null) { 129 throw new InvalidParameterException( 130 this.getClass(), 131 "name parameter cannot be null"); 132 } 133 134 if (readOrAlterNodeLock == null) { 135 throw new InvalidParameterException( 136 this.getClass(), 137 "readOrAlterNodeLock parameter cannot be null"); 138 } 139 140 if (addOrLoadChildLock == null) { 141 throw new InvalidParameterException( 142 this.getClass(), 143 "addOrLoadChildLock parameter cannot be null"); 144 } 145 146 if (addOrLoadChildLock == readOrAlterNodeLock) { 147 throw new InvalidParameterException( 148 this.getClass(), 149 "readOrAlterNodeLock and addOrLoadChildLock cannot be the same object"); 150 } 151 152 this.parent = parent; 153 this.name = name; 154 this.readOrAlterNodeLock = readOrAlterNodeLock; 155 this.addOrLoadChildLock = addOrLoadChildLock; 156 } 157 158 161 public String getName() { 162 return this.name; 163 } 164 165 168 public Node getParent() { 169 return this.parent; 170 } 171 172 179 public String getAbsoluteName() { 180 181 if (getParent() == null) { 182 return this.name; 183 } else { 184 return getParent().getAbsoluteName() + Node.DELIMITER + this.name; 185 } 186 } 187 188 191 public boolean getAllowsChildren() { 192 return true; 193 } 194 195 201 public int remove() throws NodeRemovalException { 202 int removedNodes = 0; 203 204 if (!isRemoved()) { 205 Node[] children = fetchChildren(); 210 211 for (int i = 0; i < children.length; i++) { 212 removedNodes += children[i].remove(); 213 } 214 215 synchronized (getReadOrAlterNodeLock()) { 216 if (backingDataExists()) { 217 destroyBackingData(); 219 removedNodes++; 220 } 221 this.childNodes.clear(); 222 setRemoved(); 223 } 224 } 225 226 return removedNodes; 227 } 228 229 234 public String toString() { 235 return getName(); 236 } 237 238 241 public boolean isRemoved() { 242 synchronized (getReadOrAlterNodeLock()) { 243 return this.removed; 244 } 245 } 246 247 253 public void refresh() { 254 if (!isRemoved()) { 255 256 Map localChildNodesMap; 260 261 synchronized (getReadOrAlterNodeLock()) { 262 localChildNodesMap = new HashMap (this.childNodes); 263 264 if (!backingDataExists()) { 265 setRemoved(); 267 } 268 269 } 270 removeRemovedChildren(); 271 272 Iterator childIterator = localChildNodesMap.values().iterator(); 277 while (childIterator.hasNext()) { 278 ((Node) childIterator.next()).refresh(); 279 } 280 } 281 } 282 283 289 public Node fetchChild(String childName) 290 throws NodeNotFoundException { 291 292 if (isRemoved()) { 293 throw new NodeRemovedException( 294 this.getClass(), 295 this); 296 } 297 298 if (childName == null) { 299 throw new InvalidParameterException( 300 this.getClass(), 301 "childName cannot be null"); 302 } 303 304 Node child; 305 synchronized (getReadOrAlterNodeLock()) { 306 child = (Node) this.childNodes.get(childName); 307 } 308 309 while (child != null && child.isRemoved()) { 313 synchronized (getReadOrAlterNodeLock()) { 314 Node doubleCheckChild = (Node) this.childNodes.get(childName); 315 if (child == doubleCheckChild) { 316 this.childNodes.remove(childName); 321 child = null; 322 } else { 323 child = doubleCheckChild; 327 } 328 } 329 330 } 331 332 if (child == null) { 333 synchronized (getAddOrLoadChildLock()) { 339 synchronized (getReadOrAlterNodeLock()) { 340 child = (Node) this.childNodes.get(childName); 344 } 345 346 if (child == null) { 347 child = loadChild(childName); 350 351 synchronized (getReadOrAlterNodeLock()) { 353 this.childNodes.put(childName, child); 354 } 355 } 356 } 357 } 358 359 return child; 360 } 361 362 365 public Node[] fetchChildren() { 366 if (isRemoved()) { 367 throw new NodeRemovedException( 368 this.getClass(), 369 this); 370 } 371 372 removeRemovedChildren(); 373 Collection cachedChildNames; 374 synchronized (getReadOrAlterNodeLock()) { 375 cachedChildNames = this.childNodes.keySet(); 376 } 377 378 Set childNamesToLoad = getAllChildNames(); 380 childNamesToLoad.removeAll(cachedChildNames); 381 Iterator childNameIterator = childNamesToLoad.iterator(); 382 while (childNameIterator.hasNext()) { 383 try { 384 fetchChild((String ) childNameIterator.next()); 385 } catch (NodeNotFoundException nnfe) { 386 if (log.isInfoEnabled()) { 389 log.info("Caught NodeNotFoundException: " 390 + ExceptionUtility.printStackTracesToString(nnfe)); 391 } 392 } catch (InvalidConfigurationException ice) { 394 if (log.isInfoEnabled()) { 396 log.info("Caught InvalidConfigurationException: " 397 + ExceptionUtility.printStackTracesToString(ice)); 398 } 399 } 401 } 402 403 Collection children = new HashSet (this.childNodes.values()); 405 Iterator childrenIterator = children.iterator(); 406 407 while (childrenIterator.hasNext()) { 408 Node child = (Node) childrenIterator.next(); 409 if (child.isRemoved()) { 410 childrenIterator.remove(); 411 } 412 } 413 414 return (Node[]) children.toArray(new Node[children.size()]); 415 } 416 417 423 public boolean containsChild(String childName) { 424 if (isRemoved()) { 425 throw new NodeRemovedException( 426 this.getClass(), 427 this); 428 } 429 430 removeRemovedChildren(); 431 boolean containsChild; 432 synchronized (getReadOrAlterNodeLock()) { 433 containsChild = this.childNodes.containsKey(childName); 434 } 435 436 if (!containsChild) { 437 containsChild = getAllChildNames().contains(childName); 438 } 439 440 return containsChild; 441 } 442 443 446 public void addNodeListener(NodeEventListener listener) { 447 this.nodeListeners.add(listener); 448 } 449 450 457 protected abstract void destroyBackingData() throws NodeRemovalException; 458 459 467 protected abstract Set getAllChildNames(); 468 469 479 protected abstract Node loadChild(String nodeName) 480 throws NodeNotFoundException; 481 482 488 protected abstract boolean backingDataExists(); 489 490 493 protected void removeRemovedChildren() { 494 Map childNodesLocalCopy; 495 synchronized (getReadOrAlterNodeLock()) { 496 childNodesLocalCopy = new HashMap (this.childNodes); 497 } 498 499 Iterator childIterator = childNodesLocalCopy.values().iterator(); 500 while (childIterator.hasNext()) { 501 Node child = (Node) childIterator.next(); 502 if (child.isRemoved()) { 503 childIterator.remove(); 504 } 505 } 506 507 synchronized (getReadOrAlterNodeLock()) { 508 this.childNodes.keySet().retainAll(childNodesLocalCopy.keySet()); 509 } 510 } 511 512 517 protected void setRemoved() { 518 this.removed = true; 519 } 520 521 527 protected void issueNodeChangedEvent() { 528 NodeEventListener[] listeners = 532 (NodeEventListener[]) this.nodeListeners.toArray( 533 new NodeEventListener[0]); 534 535 for (int i = 0; i < listeners.length; i++) { 536 listeners[i].nodeChanged(this); 537 } 538 } 539 540 546 protected void issueNodeRemovedEvent() { 547 NodeEventListener[] listeners = 551 (NodeEventListener[]) this.nodeListeners.toArray( 552 new NodeEventListener[0]); 553 554 for (int i = 0; i < listeners.length; i++) { 555 listeners[i].nodeRemoved(getAbsoluteName()); 556 } 557 } 558 559 574 protected final Object getReadOrAlterNodeLock() { 575 return this.readOrAlterNodeLock; 576 } 577 578 594 protected final Object getAddOrLoadChildLock() { 595 return this.addOrLoadChildLock; 596 } 597 } | Popular Tags |