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