1 19 20 package org.netbeans.modules.registry.mergedctx; 21 22 import org.netbeans.api.registry.AttributeEvent; 23 import org.netbeans.api.registry.BindingEvent; 24 import org.netbeans.api.registry.ContextException; 25 import org.netbeans.api.registry.SubcontextEvent; 26 import org.netbeans.spi.registry.BasicContext; 27 28 import java.util.*; 29 30 31 34 final class MergedDelegates { 35 private static final int ACTIVE_DELEGATE_INDEX = 0; 36 private final Resource resource; 37 private final RootContextImpl rootContext; 38 39 private MergedDelegates.ContextNames subcontextNameCache; 40 private MergedDelegates.BindingNames bindingNames; 41 42 private BasicContext[] delegates; 43 44 private MergedDelegates(final Resource resource, final RootContextImpl rootContext, final BasicContext[] delegates) { 45 this.delegates = delegates; 46 this.resource = resource; 47 this.rootContext = rootContext; 48 } 49 50 void init() { 51 initSubcontextNames(); 52 initBindingNames(); 53 initAttributeNames(null); 54 } 55 56 static MergedDelegates createRoot(final BasicContext[] rootDelegates, final RootContextImpl rootContext) { 57 return (checkValidity(rootDelegates)) ? new MergedDelegates(new Resource("/"), rootContext, rootDelegates) : null; 58 } 59 60 private void initSubcontextNames() { 61 if (subcontextNameCache == null) 62 subcontextNameCache = new ContextNames(); 63 } 64 65 private void initBindingNames() { 66 if (bindingNames == null) 67 bindingNames = new BindingNames(); 68 } 69 70 private void initAttributeNames(final String bindingName) { 71 MergedDelegates.AttributeNames attribNames = bindingNames.getAttributeNameCache(bindingName); 72 73 if (attribNames == null) { 74 bindingNames.createAttributeNameCache(bindingName); 75 } 76 } 77 78 79 void refreshSubcontextNames(final BasicContextImpl.EventDispatcher dispatcher) { 80 subcontextNameCache.refresh(dispatcher); 81 } 82 83 void refreshBindingNames(final BasicContextImpl.EventDispatcher dispatcher, final BindingEvent evt, final int layout) { 84 bindingNames.refresh(dispatcher, evt, layout); 85 86 } 87 88 void refreshAttributeNames(final BasicContextImpl.EventDispatcher dispatcher, final AttributeEvent evt, final int layout) { 89 if (evt != null) initAttributeNames(evt.getBindingName()); 90 final MergedDelegates.AttributeNames attNames = bindingNames.getAttributeNameCache((evt == null) ? null : evt.getBindingName()); 91 if (attNames != null) 92 attNames.refresh(dispatcher, bindingNames, evt, layout); 93 94 } 95 96 Collection getSubcontextNames() { 97 return subcontextNameCache.getNames(); 98 } 99 100 Collection getBindingNames() { 101 return bindingNames.getNames(); 102 } 103 104 Collection getAttributeNames(final String bindingName) { 105 initAttributeNames(bindingName); 106 final MergedDelegates.AttributeNames attribsNames = bindingNames.createAttributeNameCache(bindingName); 107 return attribsNames.getNames(); 108 } 109 110 111 MergedDelegates createChild(final String subCtxName) { 112 final BasicContext[] delegates = getSubcontexts(subCtxName, true); 113 final Resource resource = getAbsolutePath().getChild(subCtxName); 114 final MergedDelegates retVal = (checkValidity(delegates)) ? new MergedDelegates(resource, rootContext, delegates) : null; 115 return retVal; 116 } 117 118 MergedDelegates createParent() { 119 final Resource absolutePath = getAbsolutePath(); 120 return (absolutePath.isRoot()) ? null : createChild(rootContext.getContextDelegates(), absolutePath.getParent()); 121 } 122 123 static MergedDelegates createChild(final MergedDelegates relativeDelegates, final Resource absolutePath) { 124 if (!relativeDelegates.getAbsolutePath().isSuperior(absolutePath)) 125 throw new InternalError (); 126 127 final Enumeration en1 = relativeDelegates.getAbsolutePath().getElements(); 128 final Enumeration en = absolutePath.getElements(); 129 130 while (en1.hasMoreElements()) { 131 if (!en.hasMoreElements()) throw new InternalError (); 132 en.nextElement(); 133 } 134 135 136 MergedDelegates retVal = relativeDelegates; 137 138 while (en.hasMoreElements()) { 139 final String subCtxName = (String ) en.nextElement(); 140 retVal = retVal.createChild(subCtxName); 141 if (retVal == null) break; 142 } 143 144 return retVal; 145 } 146 147 void setDelegates(final BasicContextImpl.EventDispatcher dispatcher, final MergedDelegates ctxDelegates) { 148 this.delegates = ctxDelegates.delegates; 149 refreshSubcontextNames(dispatcher); 150 refreshBindingNames(dispatcher, null, -1); 151 } 152 153 Resource getAbsolutePath() { 154 return resource; 155 } 156 157 boolean hasDefault(final String bindingName, final BasicContext[] notMaskedDelegates) { 158 boolean retVal = false; 159 final Object [] bindingsOrContexts; 160 try { 161 if (bindingName == null) { 162 bindingsOrContexts = notMaskedDelegates; 163 } else { 164 bindingsOrContexts = getBindingNameLayout(bindingName, false); 165 } 166 167 if (bindingsOrContexts != null) { 168 for (int i = (ACTIVE_DELEGATE_INDEX + 1);retVal == false && i < bindingsOrContexts.length; i++) { 169 retVal = (bindingsOrContexts[i] != null); 170 } 171 } 172 } catch (ContextException e) { 173 retVal = false; 174 } 175 176 return retVal; 177 } 178 179 BasicContext getActiveDelegate(final boolean create) { 180 if (delegates[ACTIVE_DELEGATE_INDEX] == null && create) { 181 try { 182 BasicContext retVal = rootContext.getContextDelegates().getDelegates()[ACTIVE_DELEGATE_INDEX]; 183 final Enumeration elems = resource.getElements(); 184 185 BasicContext temp = retVal; 186 while (elems.hasMoreElements() && retVal != null) { 187 final String subCtxName = (String ) elems.nextElement(); 188 retVal = retVal.getSubcontext(subCtxName); 189 if (retVal == null) { 190 retVal = temp.createSubcontext(subCtxName); 191 } 192 if (retVal == null) break; 193 temp = retVal; 194 } 195 delegates[ACTIVE_DELEGATE_INDEX] = retVal; 196 } catch (ContextException e) { 197 delegates[ACTIVE_DELEGATE_INDEX] = null; 198 } 199 } 200 return delegates[ACTIVE_DELEGATE_INDEX]; 201 } 202 203 204 210 BasicContext[] getSubcontexts(final String subctxName, final boolean considerMask) { 211 final boolean isMasked = (considerMask && MaskUtils.existMaskForCtx(getActiveDelegate(false), subctxName)); 212 213 final int mergedCount = (isMasked) ? 1 : delegates.length; 214 215 final List subDelegates = new ArrayList(); 216 for (int layoutIndex = 0; layoutIndex < mergedCount; layoutIndex++) { 217 final BasicContext delegate = (delegates[layoutIndex] == null) ? null : delegates[layoutIndex].getSubcontext(subctxName); 218 subDelegates.add(delegate); 219 } 220 221 return (BasicContext[]) subDelegates.toArray(new BasicContext[delegates.length]); 222 } 223 224 228 String [] getBindingNameLayout (final String bindingName, final boolean considerMask) throws ContextException { 229 boolean exists = false; 230 final List subDelegates = new ArrayList(); 231 232 if (bindingName != null) { 233 final boolean isMasked = considerMask && MaskUtils.existMaskForBinding(getActiveDelegate(false), bindingName); 234 235 final int mergedCount = (isMasked) ? 1 : delegates.length; 236 237 for (int layoutIndex = ACTIVE_DELEGATE_INDEX;layoutIndex < mergedCount; layoutIndex++) { 238 final Collection bindingNames = (delegates[layoutIndex] == null) ? null : delegates[layoutIndex].getBindingNames(); 239 subDelegates.add(bindingNames != null && (bindingNames.contains(bindingName)) ? bindingName : null); 240 exists = true; 241 } 242 } 243 return (exists) ? (String []) subDelegates.toArray(new String [delegates.length]) : null; 244 } 245 246 boolean existsBinding (final String bindingName, final boolean considerMask) throws ContextException { 247 boolean exists = false; 248 249 if (bindingName != null) { 250 final boolean isMasked = considerMask && MaskUtils.existMaskForBinding(getActiveDelegate(false), bindingName); 251 252 final int mergedCount = (isMasked) ? 1 : delegates.length; 253 254 for (int layoutIndex = ACTIVE_DELEGATE_INDEX;layoutIndex < mergedCount; layoutIndex++) { 255 final Collection bindingNames = (delegates[layoutIndex] == null) ? null : delegates[layoutIndex].getBindingNames(); 256 if (bindingNames.contains(bindingName)) { 257 exists = true; 258 break; 259 } 260 } 261 } 262 return exists; 263 } 264 265 266 Object lookupObject(final String bindingName) throws ContextException { 267 final Object [] bindingLayout = getBindingNameLayout(bindingName, true); 269 Object retVal = null; 270 if (bindingLayout != null) { 271 for (int i = ACTIVE_DELEGATE_INDEX;i < bindingLayout.length; i++) { 272 if (bindingLayout[i] == null) continue; 273 retVal = delegates[i].lookupObject(bindingName); 274 break; 275 } 277 } 278 return retVal; 279 } 280 281 void bindObject(final String bindingName, final Object object) throws ContextException { 282 final Object [] bindingLayout = getBindingNameLayout(bindingName, true); 283 final boolean existOnActive = (bindingLayout != null && bindingLayout[ACTIVE_DELEGATE_INDEX] != null); 284 final BasicContext activeDelegate = getActiveDelegate(true); 285 if (object == null) { 286 287 MaskUtils.createMaskForBinding(activeDelegate, bindingName); 288 if (existOnActive) activeDelegate.bindObject(bindingName, null); 289 } else { 290 291 final BasicContext copyAttributesFrom = (!existOnActive) ? getContextAttributesAreCopiedFrom(bindingLayout) : null; 292 activeDelegate.bindObject(bindingName, object); 293 294 if (copyAttributesFrom != null) 295 copyAttributes(bindingName, activeDelegate, copyAttributesFrom); 296 297 } 298 } 299 300 301 String getAttribute(final String bindingName, final String attributeName) throws ContextException { 302 initAttributeNames(bindingName); 303 String retVal = null; 304 final boolean isBindingAttribute = (bindingName != null); 305 306 final Object [] bindingLayout = getBindingNameLayout(bindingName, true); 307 for (int i = ACTIVE_DELEGATE_INDEX;i < delegates.length; i++) { 308 final Object binding = (bindingLayout != null) ? bindingLayout[i] : null; 309 if (binding == null && isBindingAttribute) continue; 310 311 if (delegates[i] != null) { 312 retVal = delegates[i].getAttribute(bindingName, attributeName); 313 if (retVal != null || isBindingAttribute) break; 314 } 315 } 316 317 return retVal; 318 } 319 320 void setAttribute(final String bindingName, final Object binding, final String attributeName, final String value) throws ContextException { 321 initAttributeNames(bindingName); 322 if (binding == null && bindingName != null) return; 323 324 if (bindingName != null) { 325 final Object [] bindingLayout = getBindingNameLayout(bindingName, true); 326 final boolean existBindingOnActive = (bindingLayout != null && bindingLayout[ACTIVE_DELEGATE_INDEX] != null); 327 if (!existBindingOnActive) { 328 329 bindObject(bindingName, binding); 330 } 331 } 332 333 final BasicContext activeDelegate = getActiveDelegate(true); 334 if (value == null) { 335 MaskUtils.createMaskForAttributes(activeDelegate, bindingName, attributeName); 336 } 337 activeDelegate.setAttribute(bindingName, attributeName, value); 338 } 339 340 BasicContext createSubcontext(final String subcontextName) throws ContextException { 341 final BasicContext activeDelegate = getActiveDelegate(true); 343 final BasicContext parentOfActive = activeDelegate.getParentContext(); 344 345 if (MaskUtils.existMaskForCtx(parentOfActive, activeDelegate.getContextName())) { 346 347 MaskUtils.createMaskForCtx(activeDelegate, subcontextName); 348 } 349 return activeDelegate.createSubcontext(subcontextName); 350 } 351 352 static void destroyActiveDelegate(final BasicContext activeDelegate) throws ContextException { 353 if (activeDelegate != null) { 354 final BasicContext parentOfActiveDelegate = activeDelegate.getParentContext(); 355 final String subcontextName = activeDelegate.getContextName(); 356 357 if (parentOfActiveDelegate != null) { 358 359 MaskUtils.createMaskForCtx(parentOfActiveDelegate, subcontextName); 360 parentOfActiveDelegate.destroySubcontext(subcontextName); 361 } 362 } 363 } 364 365 private static boolean checkValidity(final BasicContext[] delegates) { 366 for (int i = ACTIVE_DELEGATE_INDEX;i < delegates.length; i++) { 367 final BasicContext delegate = delegates[i]; 368 if (delegate != null) return true; 369 } 370 return false; 371 } 372 373 374 private BasicContext getContextAttributesAreCopiedFrom(final Object [] bindingLayout) { 375 BasicContext copyAttributesFrom = null; 376 for (int i = 1; i < bindingLayout.length; i++) { 377 final Object binding = bindingLayout[i]; 378 if (binding != null && delegates[i] != null) { 379 copyAttributesFrom = delegates[i]; 380 break; 381 } 382 } 383 return copyAttributesFrom; 384 } 385 386 387 private static void copyAttributes(final String bindingName, final BasicContext to, final BasicContext from) throws ContextException { 388 final Collection names = from.getAttributeNames(bindingName); 389 for (Iterator iterator = names.iterator(); iterator.hasNext();) { 390 final String attrName = (String ) iterator.next(); 391 final String attrValue = from.getAttribute(bindingName, attrName); 392 to.setAttribute(bindingName, attrName, attrValue); 393 } 394 } 395 396 397 BasicContext[] getDelegates() { 398 return delegates; 399 } 400 401 RootContextImpl getRootContext() { 402 return rootContext; 403 } 404 405 final class ContextNames extends NameCache { 406 ContextNames() { 407 for (int layoutIndex = ACTIVE_DELEGATE_INDEX;layoutIndex < delegates.length; layoutIndex++) { 408 final BasicContext delegate = delegates[layoutIndex]; 409 if (delegate == null) continue; 410 411 final Collection unfilteredNames = delegate.getSubcontextNames(); 412 for (Iterator iterator = unfilteredNames.iterator(); iterator.hasNext();) { 413 final String name = (String ) iterator.next(); 414 if (layoutIndex == ACTIVE_DELEGATE_INDEX) { 415 if (!MaskUtils.isMaskForCtxName(name)) 416 add(layoutIndex, name); 417 } else { 418 final boolean existMask = (MaskUtils.existMaskForCtx(getActiveDelegate(false), name)); 419 if (!existMask) add(layoutIndex, name); 420 } 421 } 422 } 423 } 424 425 void refresh(final BasicContextImpl.EventDispatcher dispatcher) { 426 final List removed; 427 final List added; 428 429 synchronized (NameCache.class) { 430 final ContextNames contextNames = new ContextNames(); 431 432 final Collection originalNames = this.getNames(); 433 final Collection updatedNames = contextNames.getNames(); 434 435 removed = new ArrayList(originalNames); 436 removed.removeAll(updatedNames); 437 438 added = new ArrayList(updatedNames); 439 added.removeAll(originalNames); 440 441 this.content = contextNames.content; 442 } 443 444 for (int i = 0; i < removed.size(); i++) { 445 final String name = (String ) removed.get(i); 446 dispatcher.fireSubcontextEvent(name, SubcontextEvent.SUBCONTEXT_REMOVED); 447 } 448 449 for (int i = 0; i < added.size(); i++) { 450 final String name = (String ) added.get(i); 451 dispatcher.fireSubcontextEvent(name, SubcontextEvent.SUBCONTEXT_ADDED); 452 } 453 } 454 } 455 456 final class BindingNames extends NameCache { 457 private Map attribsImpl; 458 459 BindingNames() { 460 for (int layoutIndex = ACTIVE_DELEGATE_INDEX;layoutIndex < delegates.length; layoutIndex++) { 461 final BasicContext deleg = delegates[layoutIndex]; 462 if (deleg == null) continue; 463 464 final Collection unfilteredNames = deleg.getBindingNames(); 465 for (Iterator iterator = unfilteredNames.iterator(); iterator.hasNext();) { 466 final String name = (String ) iterator.next(); 467 if (layoutIndex == ACTIVE_DELEGATE_INDEX) { 468 if (!MaskUtils.isMaskForBindingName(name)) 469 add(layoutIndex, name); 470 } else { 471 final boolean existMask = (MaskUtils.existMaskForBinding(getActiveDelegate(false), name)); 472 if (!existMask) add(layoutIndex, name); 473 } 474 } 475 } 476 } 477 478 AttributeNames getAttributeNameCache(final String bindingName) { 479 return (attribsImpl == null) ? null : (AttributeNames) attribsImpl.get(bindingName); 480 } 481 482 AttributeNames createAttributeNameCache(final String bindingName) { 483 synchronized (NameCache.class) { 484 final AttributeNames retVal = new AttributeNames(bindingName); 485 if (attribsImpl == null) 486 attribsImpl = new HashMap(); 487 488 attribsImpl.put(bindingName, retVal); 489 return retVal; 490 } 491 } 492 493 synchronized void clear() { 494 synchronized (NameCache.class) { 495 super.clear(); 496 attribsImpl = null; 497 } 498 } 499 500 501 void refresh(final BasicContextImpl.EventDispatcher dispatcher, final BindingEvent evt, int layout) { 502 final String modifiedBindingName = (evt != null) ? evt.getBindingName() : null; 503 final List removed; 504 final List added; 505 final List modified = new ArrayList(); 506 final Collection originalNames; 507 final Collection updatedNames; 508 509 synchronized (NameCache.class) { 510 final BindingNames bindingNames = new BindingNames(); 512 originalNames = this.getNames(); 513 updatedNames = bindingNames.getNames(); 514 515 removed = new ArrayList(originalNames); 516 removed.removeAll(updatedNames); 517 518 added = new ArrayList(updatedNames); 519 added.removeAll(originalNames); 520 521 for (Iterator iterator = originalNames.iterator(); iterator.hasNext();) { 522 final String name = (String ) iterator.next(); 523 if (modifiedBindingName != null && !removed.contains(name) && modifiedBindingName.equals(name)) { 524 final Integer origLayout = (Integer ) this.content.get(name); 525 final Integer updLayout = (Integer ) bindingNames.content.get(name); 526 if (origLayout != null && updLayout != null) { 527 if (layout < 0) layout = updLayout.intValue(); 528 if (layout <= origLayout.intValue()) { 529 modified.add(name); 530 } 531 } 532 } 533 } 534 535 this.content = bindingNames.content; 536 } 537 538 if (removed.size() == 0 && added.size() == 0) { 539 if (evt != null) { 540 final AttributeNames attrs = getAttributeNameCache(evt.getBindingName()); 541 if (attrs != null) { 542 attrs.refresh(dispatcher, this, null, -1); 543 } 544 } 545 } 546 547 for (int i = 0; i < removed.size(); i++) { 548 final String name = (String ) removed.get(i); 549 dispatcher.fireBindingEvent(name, BindingEvent.BINDING_REMOVED); 550 } 551 552 for (int i = 0; i < added.size(); i++) { 553 final String name = (String ) added.get(i); 554 dispatcher.fireBindingEvent(name, BindingEvent.BINDING_ADDED); 555 } 556 for (int i = 0; i < modified.size(); i++) { 557 final String name = (String ) modified.get(i); 558 dispatcher.fireBindingEvent(name, BindingEvent.BINDING_MODIFIED); 559 } 560 } 561 } 562 563 final class AttributeNames extends NameCache { 564 private final String bindingName; 565 566 private AttributeNames(final String bindingName) { 567 this.bindingName = bindingName; 568 569 Object [] bindingLayout; 570 571 try { 572 bindingLayout = getBindingNameLayout(bindingName, true); 573 } catch (ContextException e) { 574 bindingLayout = null; 575 } 576 577 578 for (int layoutIndex = ACTIVE_DELEGATE_INDEX;layoutIndex < delegates.length; layoutIndex++) { 579 final Object binding = (bindingLayout != null) ? bindingLayout[layoutIndex] : null; 580 if (bindingName != null && binding == null) continue; 581 if (delegates[layoutIndex] != null) { 582 final Collection unfilteredNames = delegates[layoutIndex].getAttributeNames(bindingName); 583 584 for (Iterator iterator = unfilteredNames.iterator(); iterator.hasNext();) { 585 final String name = (String ) iterator.next(); 586 if (layoutIndex == ACTIVE_DELEGATE_INDEX) { 587 if (!MaskUtils.isMaskForAttributeName(name)) { 588 add(layoutIndex, name); 589 } 590 } else { 591 final boolean existMask = (MaskUtils.existMaskForAttributes(getActiveDelegate(false), bindingName, name)); 592 593 if (!existMask) { 594 add(layoutIndex, name); 595 } 596 } 597 } 598 if ((bindingName != null)) break; 599 } 600 } 601 602 } 603 604 void refresh(final BasicContextImpl.EventDispatcher dispatcher, final BindingNames bindings, final AttributeEvent evt, int layout) { 605 final String modifiedAttribName = (evt == null) ? null : evt.getAttributeName(); 606 final List removed; 607 final List added; 608 final List modified = new ArrayList(); 609 610 if (bindings == null) return; 611 612 synchronized (NameCache.class) { 613 final AttributeNames attribNames = bindings.createAttributeNameCache(bindingName); 614 final Collection originalNames = this.getNames(); 615 final Collection updatedNames = attribNames.getNames(); 616 617 removed = new ArrayList(originalNames); 618 removed.removeAll(updatedNames); 619 620 added = new ArrayList(updatedNames); 621 added.removeAll(originalNames); 622 623 for (Iterator iterator = originalNames.iterator(); iterator.hasNext();) { 624 final String name = (String ) iterator.next(); 625 if (modifiedAttribName != null && !removed.contains(name) && modifiedAttribName.equals(name)) { 626 final Integer origLayout = (Integer ) this.content.get(name); 627 final Integer updLayout = (Integer ) attribNames.content.get(name); 628 if (origLayout != null && updLayout != null) { 629 if (layout < 0) layout = updLayout.intValue(); 630 if (layout <= origLayout.intValue()) { 631 modified.add(name); 632 } 633 } 634 } 635 636 } 637 638 this.content = attribNames.content; 639 } 640 641 for (int i = 0; i < removed.size(); i++) { 642 final String name = (String ) removed.get(i); 643 dispatcher.fireAttributeEvent(bindingName, name, AttributeEvent.ATTRIBUTE_REMOVED); 644 } 645 646 for (int i = 0; i < added.size(); i++) { 647 final String name = (String ) added.get(i); 648 dispatcher.fireAttributeEvent(bindingName, name, AttributeEvent.ATTRIBUTE_ADDED); 649 } 650 651 for (int i = 0; i < modified.size(); i++) { 652 final String name = (String ) modified.get(i); 653 dispatcher.fireAttributeEvent(bindingName, name, AttributeEvent.ATTRIBUTE_MODIFIED); 654 } 655 656 } 657 } 658 } 659 | Popular Tags |