001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2015-2016 ForgeRock AS. 016 */ 017package org.forgerock.opendj.config.server; 018 019import static com.forgerock.opendj.ldap.config.ConfigMessages.*; 020 021import java.util.Collections; 022import java.util.LinkedList; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.SortedSet; 027 028import org.forgerock.i18n.LocalizableMessage; 029import org.forgerock.opendj.config.Configuration; 030import org.forgerock.opendj.config.Constraint; 031import org.forgerock.opendj.config.InstantiableRelationDefinition; 032import org.forgerock.opendj.config.ManagedObjectDefinition; 033import org.forgerock.opendj.config.ManagedObjectPath; 034import org.forgerock.opendj.config.OptionalRelationDefinition; 035import org.forgerock.opendj.config.PropertyDefinition; 036import org.forgerock.opendj.config.PropertyProvider; 037import org.forgerock.opendj.config.RelationDefinition; 038import org.forgerock.opendj.config.SetRelationDefinition; 039import org.forgerock.opendj.config.SingletonRelationDefinition; 040import org.forgerock.opendj.config.server.spi.ConfigAddListener; 041import org.forgerock.opendj.config.server.spi.ConfigChangeListener; 042import org.forgerock.opendj.config.server.spi.ConfigDeleteListener; 043import org.forgerock.opendj.config.server.spi.ConfigurationRepository; 044import org.forgerock.opendj.ldap.DN; 045import org.forgerock.util.Pair; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049/** 050 * A server-side managed object. 051 * 052 * @param <S> 053 * The type of server configuration represented by the server managed 054 * object. 055 */ 056public final class ServerManagedObject<S extends Configuration> implements PropertyProvider { 057 058 private static final Logger logger = LoggerFactory.getLogger(ServerManagedObject.class); 059 060 /** 061 * The DN of configuration entry associated with this server managed object, 062 * which is {@code null} for root. 063 */ 064 private DN configDN; 065 066 private final ServerManagementContext serverContext; 067 068 private final ConfigurationRepository configRepository; 069 070 private final ManagedObjectDefinition<?, S> definition; 071 072 /** The managed object path identifying this managed object's location. */ 073 private final ManagedObjectPath<?, S> path; 074 075 private final Map<PropertyDefinition<?>, SortedSet<?>> properties; 076 077 /** 078 * Creates an new server side managed object. 079 * 080 * @param path 081 * The managed object path. 082 * @param definition 083 * The managed object definition. 084 * @param properties 085 * The managed object's properties. 086 * @param configDN 087 * The configuration entry associated with the managed object. 088 * @param context 089 * The server management context. 090 */ 091 ServerManagedObject(final ManagedObjectPath<?, S> path, final ManagedObjectDefinition<?, S> definition, 092 final Map<PropertyDefinition<?>, SortedSet<?>> properties, final DN configDN, 093 final ServerManagementContext context) { 094 this.definition = definition; 095 this.path = path; 096 this.properties = properties; 097 this.configDN = configDN; 098 this.serverContext = context; 099 this.configRepository = context.getConfigRepository(); 100 } 101 102 /** 103 * Deregisters an existing configuration add listener. 104 * 105 * @param <M> 106 * The type of the child server configuration object. 107 * @param d 108 * The instantiable relation definition. 109 * @param listener 110 * The configuration add listener. 111 * @throws IllegalArgumentException 112 * If the instantiable relation definition is not associated 113 * with this managed object's definition. 114 */ 115 public <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d, 116 ConfigurationAddListener<M> listener) { 117 validateRelationDefinition(d); 118 DN baseDN = DNBuilder.create(path, d); 119 deregisterAddListener(baseDN, listener); 120 } 121 122 /** 123 * Deregisters an existing server managed object add listener. 124 * 125 * @param <M> 126 * The type of the child server configuration object. 127 * @param d 128 * The instantiable relation definition. 129 * @param listener 130 * The server managed object add listener. 131 * @throws IllegalArgumentException 132 * If the instantiable relation definition is not associated 133 * with this managed object's definition. 134 */ 135 public <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d, 136 ServerManagedObjectAddListener<M> listener) { 137 validateRelationDefinition(d); 138 DN baseDN = DNBuilder.create(path, d); 139 deregisterAddListener(baseDN, listener); 140 } 141 142 /** 143 * Deregisters an existing configuration add listener. 144 * 145 * @param <M> 146 * The type of the child server configuration object. 147 * @param d 148 * The optional relation definition. 149 * @param listener 150 * The configuration add listener. 151 * @throws IllegalArgumentException 152 * If the optional relation definition is not associated with 153 * this managed object's definition. 154 */ 155 public <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d, 156 ConfigurationAddListener<M> listener) { 157 validateRelationDefinition(d); 158 DN baseDN = DNBuilder.create(path, d).parent(); 159 deregisterAddListener(baseDN, listener); 160 } 161 162 /** 163 * Deregisters an existing server managed object add listener. 164 * 165 * @param <M> 166 * The type of the child server configuration object. 167 * @param d 168 * The optional relation definition. 169 * @param listener 170 * The server managed object add listener. 171 * @throws IllegalArgumentException 172 * If the optional relation definition is not associated with 173 * this managed object's definition. 174 */ 175 public <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d, 176 ServerManagedObjectAddListener<M> listener) { 177 validateRelationDefinition(d); 178 DN baseDN = DNBuilder.create(path, d).parent(); 179 deregisterAddListener(baseDN, listener); 180 } 181 182 /** 183 * Deregisters an existing configuration add listener. 184 * 185 * @param <M> 186 * The type of the child server configuration object. 187 * @param d 188 * The set relation definition. 189 * @param listener 190 * The configuration add listener. 191 * @throws IllegalArgumentException 192 * If the set relation definition is not associated with this 193 * managed object's definition. 194 */ 195 public <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d, 196 ConfigurationAddListener<M> listener) { 197 validateRelationDefinition(d); 198 DN baseDN = DNBuilder.create(path, d); 199 deregisterAddListener(baseDN, listener); 200 } 201 202 /** 203 * Deregisters an existing server managed object add listener. 204 * 205 * @param <M> 206 * The type of the child server configuration object. 207 * @param d 208 * The set relation definition. 209 * @param listener 210 * The server managed object add listener. 211 * @throws IllegalArgumentException 212 * If the set relation definition is not associated with this 213 * managed object's definition. 214 */ 215 public <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d, 216 ServerManagedObjectAddListener<M> listener) { 217 validateRelationDefinition(d); 218 DN baseDN = DNBuilder.create(path, d); 219 deregisterAddListener(baseDN, listener); 220 } 221 222 /** 223 * Deregisters an existing configuration change listener. 224 * 225 * @param listener 226 * The configuration change listener. 227 */ 228 public void deregisterChangeListener(ConfigurationChangeListener<? super S> listener) { 229 for (ConfigChangeListener l : configRepository.getChangeListeners(configDN)) { 230 if (l instanceof ConfigChangeListenerAdaptor) { 231 ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l; 232 ServerManagedObjectChangeListener<?> l2 = adaptor.getServerManagedObjectChangeListener(); 233 if (l2 instanceof ServerManagedObjectChangeListenerAdaptor<?>) { 234 ServerManagedObjectChangeListenerAdaptor<?> adaptor2 = 235 (ServerManagedObjectChangeListenerAdaptor<?>) l2; 236 if (adaptor2.getConfigurationChangeListener() == listener) { 237 adaptor.finalizeChangeListener(); 238 configRepository.deregisterChangeListener(configDN, adaptor); 239 } 240 } 241 } 242 } 243 } 244 245 /** 246 * Deregisters an existing server managed object change listener. 247 * 248 * @param listener 249 * The server managed object change listener. 250 */ 251 public void deregisterChangeListener(ServerManagedObjectChangeListener<? super S> listener) { 252 for (ConfigChangeListener l : configRepository.getChangeListeners(configDN)) { 253 if (l instanceof ConfigChangeListenerAdaptor) { 254 ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l; 255 if (adaptor.getServerManagedObjectChangeListener() == listener) { 256 adaptor.finalizeChangeListener(); 257 configRepository.deregisterChangeListener(configDN, adaptor); 258 } 259 } 260 } 261 } 262 263 /** 264 * Deregisters an existing configuration delete listener. 265 * 266 * @param <M> 267 * The type of the child server configuration object. 268 * @param d 269 * The instantiable relation definition. 270 * @param listener 271 * The configuration delete listener. 272 * @throws IllegalArgumentException 273 * If the instantiable relation definition is not associated 274 * with this managed object's definition. 275 */ 276 public <M extends Configuration> void deregisterDeleteListener(InstantiableRelationDefinition<?, M> d, 277 ConfigurationDeleteListener<M> listener) { 278 validateRelationDefinition(d); 279 280 DN baseDN = DNBuilder.create(path, d); 281 deregisterDeleteListener(baseDN, listener); 282 } 283 284 /** 285 * Deregisters an existing server managed object delete listener. 286 * 287 * @param <M> 288 * The type of the child server configuration object. 289 * @param d 290 * The instantiable relation definition. 291 * @param listener 292 * The server managed object delete listener. 293 * @throws IllegalArgumentException 294 * If the instantiable relation definition is not associated 295 * with this managed object's definition. 296 */ 297 public <M extends Configuration> void deregisterDeleteListener(InstantiableRelationDefinition<?, M> d, 298 ServerManagedObjectDeleteListener<M> listener) { 299 validateRelationDefinition(d); 300 301 DN baseDN = DNBuilder.create(path, d); 302 deregisterDeleteListener(baseDN, listener); 303 } 304 305 /** 306 * Deregisters an existing configuration delete listener. 307 * 308 * @param <M> 309 * The type of the child server configuration object. 310 * @param d 311 * The optional relation definition. 312 * @param listener 313 * The configuration delete listener. 314 * @throws IllegalArgumentException 315 * If the optional relation definition is not associated with 316 * this managed object's definition. 317 */ 318 public <M extends Configuration> void deregisterDeleteListener(OptionalRelationDefinition<?, M> d, 319 ConfigurationDeleteListener<M> listener) { 320 validateRelationDefinition(d); 321 322 DN baseDN = DNBuilder.create(path, d).parent(); 323 deregisterDeleteListener(baseDN, listener); 324 } 325 326 /** 327 * Deregisters an existing server managed object delete listener. 328 * 329 * @param <M> 330 * The type of the child server configuration object. 331 * @param d 332 * The optional relation definition. 333 * @param listener 334 * The server managed object delete listener. 335 * @throws IllegalArgumentException 336 * If the optional relation definition is not associated with 337 * this managed object's definition. 338 */ 339 public <M extends Configuration> void deregisterDeleteListener(OptionalRelationDefinition<?, M> d, 340 ServerManagedObjectDeleteListener<M> listener) { 341 validateRelationDefinition(d); 342 343 DN baseDN = DNBuilder.create(path, d).parent(); 344 deregisterDeleteListener(baseDN, listener); 345 } 346 347 /** 348 * Deregisters an existing configuration delete listener. 349 * 350 * @param <M> 351 * The type of the child server configuration object. 352 * @param d 353 * The set relation definition. 354 * @param listener 355 * The configuration delete listener. 356 * @throws IllegalArgumentException 357 * If the set relation definition is not associated with this 358 * managed object's definition. 359 */ 360 public <M extends Configuration> void deregisterDeleteListener(SetRelationDefinition<?, M> d, 361 ConfigurationDeleteListener<M> listener) { 362 validateRelationDefinition(d); 363 364 DN baseDN = DNBuilder.create(path, d); 365 deregisterDeleteListener(baseDN, listener); 366 } 367 368 /** 369 * Deregisters an existing server managed object delete listener. 370 * 371 * @param <M> 372 * The type of the child server configuration object. 373 * @param d 374 * The set relation definition. 375 * @param listener 376 * The server managed object delete listener. 377 * @throws IllegalArgumentException 378 * If the set relation definition is not associated with this 379 * managed object's definition. 380 */ 381 public <M extends Configuration> void deregisterDeleteListener(SetRelationDefinition<?, M> d, 382 ServerManagedObjectDeleteListener<M> listener) { 383 validateRelationDefinition(d); 384 385 DN baseDN = DNBuilder.create(path, d); 386 deregisterDeleteListener(baseDN, listener); 387 } 388 389 /** 390 * Retrieve an instantiable child managed object. 391 * 392 * @param <M> 393 * The requested type of the child server managed object 394 * configuration. 395 * @param d 396 * The instantiable relation definition. 397 * @param name 398 * The name of the child managed object. 399 * @return Returns the instantiable child managed object. 400 * @throws IllegalArgumentException 401 * If the relation definition is not associated with this 402 * managed object's definition. 403 * @throws ConfigException 404 * If the child managed object could not be found or if it could 405 * not be decoded. 406 */ 407 public <M extends Configuration> ServerManagedObject<? extends M> getChild(InstantiableRelationDefinition<?, M> d, 408 String name) throws ConfigException { 409 validateRelationDefinition(d); 410 return serverContext.getManagedObject(path.child(d, name)); 411 } 412 413 /** 414 * Retrieve an optional child managed object. 415 * 416 * @param <M> 417 * The requested type of the child server managed object 418 * configuration. 419 * @param d 420 * The optional relation definition. 421 * @return Returns the optional child managed object. 422 * @throws IllegalArgumentException 423 * If the optional relation definition is not associated with 424 * this managed object's definition. 425 * @throws ConfigException 426 * If the child managed object could not be found or if it could 427 * not be decoded. 428 */ 429 public <M extends Configuration> ServerManagedObject<? extends M> getChild(OptionalRelationDefinition<?, M> d) 430 throws ConfigException { 431 validateRelationDefinition(d); 432 return serverContext.getManagedObject(path.child(d)); 433 } 434 435 /** 436 * Retrieve a set child managed object. 437 * 438 * @param <M> 439 * The requested type of the child server managed object 440 * configuration. 441 * @param d 442 * The set relation definition. 443 * @param name 444 * The name of the child managed object. 445 * @return Returns the set child managed object. 446 * @throws IllegalArgumentException 447 * If the relation definition is not associated with this 448 * managed object's definition or if {@code name} specifies a 449 * managed object definition which is not a sub-type of the 450 * relation's child definition. 451 * @throws ConfigException 452 * If the child managed object could not be found or if it could 453 * not be decoded. 454 */ 455 public <M extends Configuration> ServerManagedObject<? extends M> getChild(SetRelationDefinition<?, M> d, 456 String name) throws ConfigException { 457 validateRelationDefinition(d); 458 459 return serverContext.getManagedObject(path.child(d, name)); 460 } 461 462 /** 463 * Retrieve a singleton child managed object. 464 * 465 * @param <M> 466 * The requested type of the child server managed object 467 * configuration. 468 * @param d 469 * The singleton relation definition. 470 * @return Returns the singleton child managed object. 471 * @throws IllegalArgumentException 472 * If the relation definition is not associated with this 473 * managed object's definition. 474 * @throws ConfigException 475 * If the child managed object could not be found or if it could 476 * not be decoded. 477 */ 478 public <M extends Configuration> ServerManagedObject<? extends M> getChild(SingletonRelationDefinition<?, M> d) 479 throws ConfigException { 480 validateRelationDefinition(d); 481 return serverContext.getManagedObject(path.child(d)); 482 } 483 484 /** 485 * Returns the server management context used by this object. 486 * 487 * @return the context 488 */ 489 public ServerManagementContext getServerContext() { 490 return serverContext; 491 } 492 493 /** 494 * Creates a server configuration view of this managed object. 495 * 496 * @return Returns the server configuration view of this managed object. 497 */ 498 public S getConfiguration() { 499 return definition.createServerConfiguration(this); 500 } 501 502 /** 503 * Get the DN of the LDAP entry associated with this server managed object. 504 * 505 * @return Returns the DN of the LDAP entry associated with this server 506 * managed object, or an null DN if this is the root managed object. 507 */ 508 public DN getDN() { 509 if (configDN != null) { 510 return configDN; 511 } 512 return DN.rootDN(); 513 } 514 515 /** 516 * Get the definition associated with this server managed object. 517 * 518 * @return Returns the definition associated with this server managed 519 * object. 520 */ 521 public ManagedObjectDefinition<?, S> getManagedObjectDefinition() { 522 return definition; 523 } 524 525 /** 526 * Get the path of this server managed object. 527 * 528 * @return Returns the path of this server managed object. 529 */ 530 public ManagedObjectPath<?, S> getManagedObjectPath() { 531 return path; 532 } 533 534 /** 535 * Get the effective value of the specified property. If the property is 536 * multi-valued then just the first value is returned. If the property does 537 * not have a value then its default value is returned if it has one, or 538 * <code>null</code> indicating that any default behavior is applicable. 539 * 540 * @param <T> 541 * The type of the property to be retrieved. 542 * @param d 543 * The property to be retrieved. 544 * @return Returns the property's effective value, or <code>null</code> 545 * indicating that any default behavior is applicable. 546 * @throws IllegalArgumentException 547 * If the property definition is not associated with this 548 * managed object's definition. 549 */ 550 public <T> T getPropertyValue(PropertyDefinition<T> d) { 551 Set<T> values = getPropertyValues(d); 552 if (!values.isEmpty()) { 553 return values.iterator().next(); 554 } 555 return null; 556 } 557 558 /** 559 * Get the effective values of the specified property. If the property does 560 * not have any values then its default values are returned if it has any, 561 * or an empty set indicating that any default behavior is applicable. 562 * 563 * @param <T> 564 * The type of the property to be retrieved. 565 * @param d 566 * The property to be retrieved. 567 * @return Returns an unmodifiable set containing the property's effective 568 * values. An empty set indicates that the property has no default 569 * values defined and any default behavior is applicable. 570 * @throws IllegalArgumentException 571 * If the property definition is not associated with this 572 * managed object's definition. 573 */ 574 @Override 575 @SuppressWarnings("unchecked") 576 public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d) { 577 if (!properties.containsKey(d)) { 578 throw new IllegalArgumentException("Unknown property " + d.getName()); 579 } 580 return Collections.unmodifiableSortedSet((SortedSet<T>) properties.get(d)); 581 } 582 583 /** 584 * Determines whether the optional managed object associated with the 585 * specified optional relations exists. 586 * 587 * @param d 588 * The optional relation definition. 589 * @return Returns <code>true</code> if the optional managed object exists, 590 * <code>false</code> otherwise. 591 * @throws IllegalArgumentException 592 * If the optional relation definition is not associated with 593 * this managed object's definition. 594 */ 595 public boolean hasChild(OptionalRelationDefinition<?, ?> d) { 596 validateRelationDefinition(d); 597 return serverContext.managedObjectExists(path.child(d)); 598 } 599 600 /** 601 * Lists the child managed objects associated with the specified 602 * instantiable relation. 603 * 604 * @param d 605 * The instantiable relation definition. 606 * @return Returns the names of the child managed objects. 607 * @throws IllegalArgumentException 608 * If the relation definition is not associated with this 609 * managed object's definition. 610 */ 611 public String[] listChildren(InstantiableRelationDefinition<?, ?> d) { 612 validateRelationDefinition(d); 613 return serverContext.listManagedObjects(path, d); 614 } 615 616 /** 617 * Lists the child managed objects associated with the specified set 618 * relation. 619 * 620 * @param d 621 * The set relation definition. 622 * @return Returns the names of the child managed objects. 623 * @throws IllegalArgumentException 624 * If the relation definition is not associated with this 625 * managed object's definition. 626 */ 627 public String[] listChildren(SetRelationDefinition<?, ?> d) { 628 validateRelationDefinition(d); 629 return serverContext.listManagedObjects(path, d); 630 } 631 632 /** 633 * Register to be notified when new child configurations are added beneath 634 * an instantiable relation. 635 * 636 * @param <M> 637 * The type of the child server configuration object. 638 * @param d 639 * The instantiable relation definition. 640 * @param listener 641 * The configuration add listener. 642 * @throws IllegalArgumentException 643 * If the instantiable relation definition is not associated 644 * with this managed object's definition. 645 * @throws ConfigException 646 * If the configuration entry associated with the instantiable 647 * relation could not be retrieved. 648 */ 649 public <M extends Configuration> void registerAddListener(InstantiableRelationDefinition<?, M> d, 650 ConfigurationAddListener<M> listener) throws ConfigException { 651 registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener)); 652 } 653 654 /** 655 * Register to be notified when new child server managed object are added 656 * beneath an instantiable relation. 657 * 658 * @param <M> 659 * The type of the child server configuration object. 660 * @param d 661 * The instantiable relation definition. 662 * @param listener 663 * The server managed object add listener. 664 * @throws IllegalArgumentException 665 * If the instantiable relation definition is not associated 666 * with this managed object's definition. 667 * @throws ConfigException 668 * If the configuration entry associated with the instantiable 669 * relation could not be retrieved. 670 */ 671 public <M extends Configuration> void registerAddListener(InstantiableRelationDefinition<?, M> d, 672 ServerManagedObjectAddListener<M> listener) throws ConfigException { 673 validateRelationDefinition(d); 674 DN baseDN = DNBuilder.create(path, d); 675 ConfigAddListener adaptor = new ConfigAddListenerAdaptor<>(serverContext, path, d, listener); 676 registerAddListener(baseDN, adaptor); 677 } 678 679 /** 680 * Register to be notified when a new child configurations is added beneath 681 * an optional relation. 682 * 683 * @param <M> 684 * The type of the child server configuration object. 685 * @param d 686 * The optional relation definition. 687 * @param listener 688 * The configuration add listener. 689 * @throws IllegalArgumentException 690 * If the optional relation definition is not associated with 691 * this managed object's definition. 692 * @throws ConfigException 693 * If the configuration entry associated with the optional 694 * relation could not be retrieved. 695 */ 696 public <M extends Configuration> void registerAddListener(OptionalRelationDefinition<?, M> d, 697 ConfigurationAddListener<M> listener) throws ConfigException { 698 registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener)); 699 } 700 701 /** 702 * Register to be notified when a new child server managed object is added 703 * beneath an optional relation. 704 * 705 * @param <M> 706 * The type of the child server configuration object. 707 * @param d 708 * The optional relation definition. 709 * @param listener 710 * The server managed object add listener. 711 * @throws IllegalArgumentException 712 * If the optional relation definition is not associated with 713 * this managed object's definition. 714 * @throws ConfigException 715 * If the configuration entry associated with the optional 716 * relation could not be retrieved. 717 */ 718 public <M extends Configuration> void registerAddListener(OptionalRelationDefinition<?, M> d, 719 ServerManagedObjectAddListener<M> listener) throws ConfigException { 720 validateRelationDefinition(d); 721 DN baseDN = DNBuilder.create(path, d).parent(); 722 ConfigAddListener adaptor = new ConfigAddListenerAdaptor<>(serverContext, path, d, listener); 723 registerAddListener(baseDN, adaptor); 724 } 725 726 /** 727 * Register to be notified when new child configurations are added beneath a 728 * set relation. 729 * 730 * @param <M> 731 * The type of the child server configuration object. 732 * @param d 733 * The set relation definition. 734 * @param listener 735 * The configuration add listener. 736 * @throws IllegalArgumentException 737 * If the set relation definition is not associated with this 738 * managed object's definition. 739 * @throws ConfigException 740 * If the configuration entry associated with the set relation 741 * could not be retrieved. 742 */ 743 public <M extends Configuration> void registerAddListener(SetRelationDefinition<?, M> d, 744 ConfigurationAddListener<M> listener) throws ConfigException { 745 registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener)); 746 } 747 748 /** 749 * Register to be notified when new child server managed object are added 750 * beneath a set relation. 751 * 752 * @param <M> 753 * The type of the child server configuration object. 754 * @param d 755 * The set relation definition. 756 * @param listener 757 * The server managed object add listener. 758 * @throws IllegalArgumentException 759 * If the set relation definition is not associated with this 760 * managed object's definition. 761 * @throws ConfigException 762 * If the configuration entry associated with the set relation 763 * could not be retrieved. 764 */ 765 public <M extends Configuration> void registerAddListener(SetRelationDefinition<?, M> d, 766 ServerManagedObjectAddListener<M> listener) throws ConfigException { 767 validateRelationDefinition(d); 768 DN baseDN = DNBuilder.create(path, d); 769 ConfigAddListener adaptor = new ConfigAddListenerAdaptor<>(serverContext, path, d, listener); 770 registerAddListener(baseDN, adaptor); 771 } 772 773 /** 774 * Register to be notified when this server managed object is changed. 775 * 776 * @param listener 777 * The configuration change listener. 778 */ 779 public void registerChangeListener(ConfigurationChangeListener<? super S> listener) { 780 registerChangeListener(new ServerManagedObjectChangeListenerAdaptor<S>(listener)); 781 } 782 783 /** 784 * Register to be notified when this server managed object is changed. 785 * 786 * @param listener 787 * The server managed object change listener. 788 */ 789 public void registerChangeListener(ServerManagedObjectChangeListener<? super S> listener) { 790 ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<>(serverContext, path, listener); 791 configRepository.registerChangeListener(configDN, adaptor); 792 793 // TODO : go toward this 794 // Entry entry; 795 // configBackend.registerChangeListener(entry.getName(), adapter)); 796 797 // Change listener registration usually signifies that a managed 798 // object has been accepted and added to the server configuration 799 // during initialization post-add. 800 801 // FIXME: we should prevent multiple invocations in the case where 802 // multiple change listeners are registered for the same object. 803 for (Constraint constraint : definition.getAllConstraints()) { 804 for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { 805 try { 806 handler.performPostAdd(this); 807 } catch (ConfigException e) { 808 logger.trace("Unable to perform post add", e); 809 } 810 } 811 } 812 } 813 814 /** 815 * Register to be notified when existing child configurations are deleted 816 * beneath an instantiable relation. 817 * 818 * @param <M> 819 * The type of the child server configuration object. 820 * @param d 821 * The instantiable relation definition. 822 * @param listener 823 * The configuration delete listener. 824 * @throws IllegalArgumentException 825 * If the instantiable relation definition is not associated 826 * with this managed object's definition. 827 * @throws ConfigException 828 * If the configuration entry associated with the instantiable 829 * relation could not be retrieved. 830 */ 831 public <M extends Configuration> void registerDeleteListener(InstantiableRelationDefinition<?, M> d, 832 ConfigurationDeleteListener<M> listener) throws ConfigException { 833 registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener)); 834 } 835 836 /** 837 * Register to be notified when existing child server managed objects are 838 * deleted beneath an instantiable relation. 839 * 840 * @param <M> 841 * The type of the child server configuration object. 842 * @param d 843 * The instantiable relation definition. 844 * @param listener 845 * The server managed objects delete listener. 846 * @throws IllegalArgumentException 847 * If the instantiable relation definition is not associated 848 * with this managed object's definition. 849 * @throws ConfigException 850 * If the configuration entry associated with the instantiable 851 * relation could not be retrieved. 852 */ 853 public <M extends Configuration> void registerDeleteListener(InstantiableRelationDefinition<?, M> d, 854 ServerManagedObjectDeleteListener<M> listener) throws ConfigException { 855 validateRelationDefinition(d); 856 DN baseDN = DNBuilder.create(path, d); 857 ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<>(serverContext, path, d, listener); 858 registerDeleteListener(baseDN, adaptor); 859 } 860 861 /** 862 * Register to be notified when an existing child configuration is deleted 863 * beneath an optional relation. 864 * 865 * @param <M> 866 * The type of the child server configuration object. 867 * @param d 868 * The optional relation definition. 869 * @param listener 870 * The configuration delete listener. 871 * @throws IllegalArgumentException 872 * If the optional relation definition is not associated with 873 * this managed object's definition. 874 * @throws ConfigException 875 * If the configuration entry associated with the optional 876 * relation could not be retrieved. 877 */ 878 public <M extends Configuration> void registerDeleteListener(OptionalRelationDefinition<?, M> d, 879 ConfigurationDeleteListener<M> listener) throws ConfigException { 880 registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener)); 881 } 882 883 /** 884 * Register to be notified when an existing child server managed object is 885 * deleted beneath an optional relation. 886 * 887 * @param <M> 888 * The type of the child server configuration object. 889 * @param d 890 * The optional relation definition. 891 * @param listener 892 * The server managed object delete listener. 893 * @throws IllegalArgumentException 894 * If the optional relation definition is not associated with 895 * this managed object's definition. 896 * @throws ConfigException 897 * If the configuration entry associated with the optional 898 * relation could not be retrieved. 899 */ 900 public <M extends Configuration> void registerDeleteListener(OptionalRelationDefinition<?, M> d, 901 ServerManagedObjectDeleteListener<M> listener) throws ConfigException { 902 validateRelationDefinition(d); 903 DN baseDN = DNBuilder.create(path, d).parent(); 904 ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<>(serverContext, path, d, listener); 905 registerDeleteListener(baseDN, adaptor); 906 } 907 908 /** 909 * Register to be notified when existing child configurations are deleted 910 * beneath a set relation. 911 * 912 * @param <M> 913 * The type of the child server configuration object. 914 * @param d 915 * The set relation definition. 916 * @param listener 917 * The configuration delete listener. 918 * @throws IllegalArgumentException 919 * If the set relation definition is not associated with this 920 * managed object's definition. 921 * @throws ConfigException 922 * If the configuration entry associated with the set relation 923 * could not be retrieved. 924 */ 925 public <M extends Configuration> void registerDeleteListener(SetRelationDefinition<?, M> d, 926 ConfigurationDeleteListener<M> listener) throws ConfigException { 927 registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener)); 928 } 929 930 /** 931 * Register to be notified when existing child server managed objects are 932 * deleted beneath a set relation. 933 * 934 * @param <M> 935 * The type of the child server configuration object. 936 * @param d 937 * The set relation definition. 938 * @param listener 939 * The server managed objects delete listener. 940 * @throws IllegalArgumentException 941 * If the set relation definition is not associated with this 942 * managed object's definition. 943 * @throws ConfigException 944 * If the configuration entry associated with the set relation 945 * could not be retrieved. 946 */ 947 public <M extends Configuration> void registerDeleteListener(SetRelationDefinition<?, M> d, 948 ServerManagedObjectDeleteListener<M> listener) throws ConfigException { 949 validateRelationDefinition(d); 950 DN baseDN = DNBuilder.create(path, d); 951 ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<>(serverContext, path, d, listener); 952 registerDeleteListener(baseDN, adaptor); 953 } 954 955 @Override 956 public String toString() { 957 StringBuilder builder = new StringBuilder(); 958 959 builder.append("{ TYPE="); 960 builder.append(definition.getName()); 961 builder.append(", DN=\""); 962 builder.append(getDN()); 963 builder.append('\"'); 964 for (Map.Entry<PropertyDefinition<?>, SortedSet<?>> value : properties.entrySet()) { 965 builder.append(", "); 966 builder.append(value.getKey().getName()); 967 builder.append('='); 968 builder.append(value.getValue()); 969 } 970 builder.append(" }"); 971 972 return builder.toString(); 973 } 974 975 /** 976 * Determines whether this managed object can be used by the server. 977 * 978 * @throws ConstraintViolationException 979 * If one or more constraints determined that this managed 980 * object cannot be used by the server. 981 */ 982 void ensureIsUsable() throws ConstraintViolationException { 983 // Enforce any constraints. 984 boolean isUsable = true; 985 List<LocalizableMessage> reasons = new LinkedList<>(); 986 for (Constraint constraint : definition.getAllConstraints()) { 987 for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) { 988 try { 989 if (!handler.isUsable(this, reasons)) { 990 isUsable = false; 991 } 992 } catch (ConfigException e) { 993 LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e.getMessageObject()); 994 reasons.add(message); 995 isUsable = false; 996 } 997 } 998 } 999 1000 if (!isUsable) { 1001 throw new ConstraintViolationException(this, reasons); 1002 } 1003 } 1004 1005 /** 1006 * Update the config DN associated with this server managed object. This 1007 * is only intended to be used by change listener call backs in order to 1008 * update the managed object with the correct config DN. 1009 * 1010 * @param configDN 1011 * The DN of the underlying configuration entry. 1012 */ 1013 void setConfigDN(DN configDN) { 1014 this.configDN = configDN; 1015 } 1016 1017 /** Deregister an add listener. */ 1018 private <M extends Configuration> void deregisterAddListener(DN baseDN, ConfigurationAddListener<M> listener) { 1019 try { 1020 if (configRepository.hasEntry(baseDN)) { 1021 for (ConfigAddListener configListener : configRepository.getAddListeners(baseDN)) { 1022 if (configListener instanceof ConfigAddListenerAdaptor) { 1023 ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) configListener; 1024 ServerManagedObjectAddListener<?> smoListener = adaptor.getServerManagedObjectAddListener(); 1025 if (smoListener instanceof ServerManagedObjectAddListenerAdaptor<?>) { 1026 ServerManagedObjectAddListenerAdaptor<?> adaptor2 = 1027 (ServerManagedObjectAddListenerAdaptor<?>) smoListener; 1028 if (adaptor2.getConfigurationAddListener() == listener) { 1029 configRepository.deregisterAddListener(baseDN, adaptor); 1030 } 1031 } 1032 } 1033 } 1034 } else { 1035 // The relation entry does not exist so check for and deregister 1036 // delayed add listener. 1037 deregisterDelayedAddListener(baseDN, listener); 1038 } 1039 } catch (ConfigException e) { 1040 // Ignore the exception since this implies deregistration. 1041 logger.trace("Unable to deregister add listener", e); 1042 } 1043 } 1044 1045 /** Deregister an add listener. */ 1046 private <M extends Configuration> void deregisterAddListener(DN baseDN, 1047 ServerManagedObjectAddListener<M> listener) { 1048 try { 1049 if (configRepository.hasEntry(baseDN)) { 1050 for (ConfigAddListener configListener : configRepository.getAddListeners(baseDN)) { 1051 if (configListener instanceof ConfigAddListenerAdaptor) { 1052 ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) configListener; 1053 if (adaptor.getServerManagedObjectAddListener() == listener) { 1054 configRepository.deregisterAddListener(baseDN, adaptor); 1055 } 1056 } 1057 } 1058 } else { 1059 // The relation entry does not exist so check for and deregister 1060 // delayed add listener. 1061 deregisterDelayedAddListener(baseDN, listener); 1062 } 1063 } catch (ConfigException e) { 1064 // Ignore the exception since this implies deregistration. 1065 logger.trace("Unable to deregister add listener", e); 1066 } 1067 } 1068 1069 /** 1070 * Convenience method to retrieve the initial listener and its intermediate 1071 * adaptor from the provided configListener. 1072 * 1073 * @param <T> 1074 * Type of the configuration. 1075 * @param configListener 1076 * Listener from wich to extract the initial listener. 1077 * @return a pair of (intermediate adaptor, intermediate listener) or 1078 * {@code Pair.EMPTY} if listener can't be extracted 1079 */ 1080 // @Checkstyle:off 1081 static <T extends Configuration> Pair<ConfigAddListenerAdaptor<T>, ConfigurationAddListener<T>> 1082 extractInitialListener(ConfigAddListener configListener) { 1083 // @Checkstyle:on 1084 Pair<ConfigAddListenerAdaptor<T>, ServerManagedObjectAddListener<T>> pair = 1085 extractIntermediateListener(configListener); 1086 if (!pair.equals(Pair.EMPTY) && pair.getSecond() instanceof ServerManagedObjectAddListenerAdaptor) { 1087 ServerManagedObjectAddListenerAdaptor<T> adaptor2 = (ServerManagedObjectAddListenerAdaptor<T>) 1088 pair.getSecond(); 1089 return Pair.of(pair.getFirst(), adaptor2.getConfigurationAddListener()); 1090 } 1091 return Pair.empty(); 1092 } 1093 1094 /** 1095 * Convenience method to retrieve the intermediate listener and its 1096 * intermediate adaptor from the provided configListener. 1097 * 1098 * @param <T> 1099 * Type of the configuration. 1100 * @param configListener 1101 * Listener from wich to extract the initial listener. 1102 * @return a pair of (intermediate adaptor, initial listener) or 1103 * {@code Pair.EMPTY} if listener can't be extracted 1104 */ 1105 @SuppressWarnings("unchecked") 1106 // @Checkstyle:off 1107 static <T extends Configuration> Pair<ConfigAddListenerAdaptor<T>, ServerManagedObjectAddListener<T>> 1108 extractIntermediateListener(ConfigAddListener configListener) { 1109 // @Checkstyle:on 1110 if (configListener instanceof ConfigAddListenerAdaptor) { 1111 ConfigAddListenerAdaptor<T> adaptor = (ConfigAddListenerAdaptor<T>) configListener; 1112 return Pair.of(adaptor, adaptor.getServerManagedObjectAddListener()); 1113 } 1114 return Pair.empty(); 1115 } 1116 1117 /** Deregister a delete listener. */ 1118 private <M extends Configuration> void deregisterDeleteListener(DN baseDN, 1119 ConfigurationDeleteListener<M> listener) { 1120 try { 1121 if (configRepository.hasEntry(baseDN)) { 1122 for (ConfigDeleteListener l : configRepository.getDeleteListeners(baseDN)) { 1123 if (l instanceof ConfigDeleteListenerAdaptor) { 1124 ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l; 1125 ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener(); 1126 if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { 1127 ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = 1128 (ServerManagedObjectDeleteListenerAdaptor<?>) l2; 1129 if (adaptor2.getConfigurationDeleteListener() == listener) { 1130 configRepository.deregisterDeleteListener(baseDN, adaptor); 1131 } 1132 } 1133 } 1134 } 1135 } else { 1136 // The relation entry does not exist so check for and deregister 1137 // delayed add listener. 1138 deregisterDelayedDeleteListener(baseDN, listener); 1139 } 1140 } catch (ConfigException e) { 1141 // Ignore the exception since this implies deregistration. 1142 logger.trace("Unable to deregister delete listener", e); 1143 } 1144 } 1145 1146 /** Deregister a delete listener. */ 1147 private <M extends Configuration> void deregisterDeleteListener(DN baseDN, 1148 ServerManagedObjectDeleteListener<M> listener) { 1149 try { 1150 if (configRepository.hasEntry(baseDN)) { 1151 for (ConfigDeleteListener l : configRepository.getDeleteListeners(baseDN)) { 1152 if (l instanceof ConfigDeleteListenerAdaptor) { 1153 ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l; 1154 if (adaptor.getServerManagedObjectDeleteListener() == listener) { 1155 configRepository.deregisterDeleteListener(baseDN, adaptor); 1156 } 1157 } 1158 } 1159 } else { 1160 // The relation entry does not exist so check for and deregister 1161 // delayed add listener. 1162 deregisterDelayedDeleteListener(baseDN, listener); 1163 } 1164 } catch (ConfigException e) { 1165 // Ignore the exception since this implies deregistration. 1166 logger.trace("Unable to deregister delete listener", e); 1167 } 1168 } 1169 1170 /** Register an instantiable or optional relation add listener. */ 1171 private void registerAddListener(DN baseDN, ConfigAddListener adaptor) throws 1172 ConfigException { 1173 if (configRepository.hasEntry(baseDN)) { 1174 configRepository.registerAddListener(baseDN, adaptor); 1175 } else { 1176 // The relation entry does not exist yet 1177 // so register a delayed add listener. 1178 ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor, configRepository); 1179 registerDelayedListener(baseDN, delayedListener); 1180 } 1181 } 1182 1183 /** Register a delayed listener with the nearest existing parent entry to the provided base DN. */ 1184 private void registerDelayedListener(DN baseDN, ConfigAddListener delayedListener) throws ConfigException { 1185 DN currentDN = baseDN.parent(); 1186 DN previousDN = currentDN; 1187 while (currentDN != null) { 1188 if (!configRepository.hasEntry(currentDN)) { 1189 delayedListener = new DelayedConfigAddListener(currentDN, delayedListener, configRepository); 1190 previousDN = currentDN; 1191 currentDN = currentDN.parent(); 1192 } else { 1193 configRepository.registerAddListener(previousDN, delayedListener); 1194 return; 1195 } 1196 } 1197 1198 // No parent entry could be found. 1199 throw new ConfigException(ERR_ADMIN_UNABLE_TO_REGISTER_LISTENER.get(baseDN)); 1200 } 1201 1202 /** 1203 * Deregister a delayed listener with the nearest existing parent 1204 * entry to the provided base DN. 1205 */ 1206 private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN, 1207 ConfigurationAddListener<M> listener) throws ConfigException { 1208 DN parentDN = baseDN.parent(); 1209 int delayWrappers = 0; 1210 while (parentDN != null) { 1211 if (!configRepository.hasEntry(parentDN)) { 1212 parentDN = parentDN.parent(); 1213 delayWrappers++; 1214 } else { 1215 for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) { 1216 if (configListener instanceof DelayedConfigAddListener) { 1217 DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener; 1218 ConfigAddListener wrappedListener; 1219 1220 int i = delayWrappers; 1221 for (; i > 0; i--) { 1222 wrappedListener = delayListener.getDelayedAddListener(); 1223 if (wrappedListener instanceof DelayedConfigAddListener) { 1224 delayListener = (DelayedConfigAddListener) configListener; 1225 } else { 1226 break; 1227 } 1228 } 1229 1230 if (i > 0) { 1231 // There are not enough level of wrapping 1232 // so this can't be the listener we are looking for. 1233 continue; 1234 } 1235 1236 ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); 1237 1238 if (delayedListener instanceof ConfigAddListenerAdaptor) { 1239 ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener; 1240 ServerManagedObjectAddListener<?> l2 = adaptor.getServerManagedObjectAddListener(); 1241 if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) { 1242 ServerManagedObjectAddListenerAdaptor<?> adaptor2 = 1243 (ServerManagedObjectAddListenerAdaptor<?>) l2; 1244 if (adaptor2.getConfigurationAddListener() == listener) { 1245 configRepository.deregisterAddListener(parentDN, configListener); 1246 } 1247 } 1248 } 1249 } 1250 } 1251 return; 1252 } 1253 } 1254 } 1255 1256 /** 1257 * Deregister a delayed listener with the nearest existing parent 1258 * entry to the provided base DN. 1259 */ 1260 private <M extends Configuration> void deregisterDelayedDeleteListener(DN baseDN, 1261 ConfigurationDeleteListener<M> listener) throws ConfigException { 1262 DN parentDN = baseDN.parent(); 1263 int delayWrappers = 0; 1264 while (parentDN != null) { 1265 if (!configRepository.hasEntry(parentDN)) { 1266 parentDN = parentDN.parent(); 1267 delayWrappers++; 1268 } else { 1269 for (ConfigAddListener l : configRepository.getAddListeners(parentDN)) { 1270 if (l instanceof DelayedConfigAddListener) { 1271 DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l; 1272 ConfigAddListener wrappedListener; 1273 1274 int i = delayWrappers; 1275 for (; i > 0; i--) { 1276 wrappedListener = delayListener.getDelayedAddListener(); 1277 if (wrappedListener instanceof DelayedConfigAddListener) { 1278 delayListener = (DelayedConfigAddListener) l; 1279 } else { 1280 break; 1281 } 1282 } 1283 1284 if (i > 0) { 1285 // There are not enough level of wrapping 1286 // so this can't be the listener we are looking for. 1287 continue; 1288 } 1289 1290 ConfigDeleteListener delayedListener = delayListener.getDelayedDeleteListener(); 1291 1292 if (delayedListener instanceof ConfigDeleteListenerAdaptor) { 1293 ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener; 1294 ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener(); 1295 if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { 1296 ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = 1297 (ServerManagedObjectDeleteListenerAdaptor<?>) l2; 1298 if (adaptor2.getConfigurationDeleteListener() == listener) { 1299 configRepository.deregisterAddListener(parentDN, l); 1300 } 1301 } 1302 } 1303 } 1304 } 1305 return; 1306 } 1307 } 1308 } 1309 1310 /** 1311 * Deregister a delayed listener with the nearest existing parent 1312 * entry to the provided base DN. 1313 */ 1314 private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN, 1315 ServerManagedObjectAddListener<M> listener) throws ConfigException { 1316 DN parentDN = baseDN.parent(); 1317 int delayWrappers = 0; 1318 while (parentDN != null) { 1319 if (!configRepository.hasEntry(parentDN)) { 1320 parentDN = parentDN.parent(); 1321 delayWrappers++; 1322 } else { 1323 for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) { 1324 if (configListener instanceof DelayedConfigAddListener) { 1325 DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener; 1326 ConfigAddListener wrappedListener; 1327 1328 int i = delayWrappers; 1329 for (; i > 0; i--) { 1330 wrappedListener = delayListener.getDelayedAddListener(); 1331 if (wrappedListener instanceof DelayedConfigAddListener) { 1332 delayListener = (DelayedConfigAddListener) configListener; 1333 } else { 1334 break; 1335 } 1336 } 1337 1338 if (i > 0) { 1339 // There are not enough level of wrapping 1340 // so this can't be the listener we are looking for. 1341 continue; 1342 } 1343 1344 ConfigAddListener delayedListener = delayListener.getDelayedAddListener(); 1345 1346 if (delayedListener instanceof ConfigAddListenerAdaptor) { 1347 ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener; 1348 if (adaptor.getServerManagedObjectAddListener() == listener) { 1349 configRepository.deregisterAddListener(parentDN, configListener); 1350 } 1351 } 1352 } 1353 } 1354 return; 1355 } 1356 } 1357 } 1358 1359 /** 1360 * Deregister a delayed listener with the nearest existing parent 1361 * entry to the provided base DN. 1362 */ 1363 private <M extends Configuration> void deregisterDelayedDeleteListener(DN baseDN, 1364 ServerManagedObjectDeleteListener<M> listener) throws ConfigException { 1365 DN parentDN = baseDN.parent(); 1366 int delayWrappers = 0; 1367 while (parentDN != null) { 1368 if (!configRepository.hasEntry(parentDN)) { 1369 parentDN = parentDN.parent(); 1370 delayWrappers++; 1371 } else { 1372 for (ConfigAddListener configListener : configRepository.getAddListeners(parentDN)) { 1373 if (configListener instanceof DelayedConfigAddListener) { 1374 DelayedConfigAddListener delayListener = (DelayedConfigAddListener) configListener; 1375 ConfigAddListener wrappedListener; 1376 1377 int i = delayWrappers; 1378 for (; i > 0; i--) { 1379 wrappedListener = delayListener.getDelayedAddListener(); 1380 if (wrappedListener instanceof DelayedConfigAddListener) { 1381 delayListener = (DelayedConfigAddListener) configListener; 1382 } else { 1383 break; 1384 } 1385 } 1386 1387 if (i > 0) { 1388 // There are not enough level of wrapping 1389 // so this can't be the listener we are looking for. 1390 continue; 1391 } 1392 1393 ConfigDeleteListener delayedListener = delayListener.getDelayedDeleteListener(); 1394 1395 if (delayedListener instanceof ConfigDeleteListenerAdaptor) { 1396 ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener; 1397 if (adaptor.getServerManagedObjectDeleteListener() == listener) { 1398 configRepository.deregisterAddListener(parentDN, configListener); 1399 } 1400 } 1401 } 1402 } 1403 return; 1404 } 1405 } 1406 } 1407 1408 /** Register an instantiable or optional relation delete listener. */ 1409 private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) throws ConfigException { 1410 if (configRepository.hasEntry(baseDN)) { 1411 configRepository.registerDeleteListener(baseDN, adaptor); 1412 } else { 1413 // The relation entry does not exist yet 1414 // so register a delayed add listener. 1415 ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor, configRepository); 1416 registerDelayedListener(baseDN, delayedListener); 1417 } 1418 } 1419 1420 /** Validate that a relation definition belongs to this managed object. */ 1421 private void validateRelationDefinition(RelationDefinition<?, ?> rd) { 1422 RelationDefinition<?, ?> tmp = definition.getRelationDefinition(rd.getName()); 1423 if (tmp != rd) { 1424 throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " 1425 + definition.getName()); 1426 } 1427 } 1428}