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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.admin.server; 029 030 031 032 import static org.opends.messages.AdminMessages.*; 033 import static org.opends.server.loggers.debug.DebugLogger.*; 034 import static org.opends.server.util.StaticUtils.*; 035 036 import java.util.Collections; 037 import java.util.LinkedList; 038 import java.util.List; 039 import java.util.Map; 040 import java.util.Set; 041 import java.util.SortedSet; 042 043 import org.opends.messages.AdminMessages; 044 import org.opends.messages.Message; 045 import org.opends.server.admin.Configuration; 046 import org.opends.server.admin.Constraint; 047 import org.opends.server.admin.InstantiableRelationDefinition; 048 import org.opends.server.admin.ManagedObjectDefinition; 049 import org.opends.server.admin.ManagedObjectPath; 050 import org.opends.server.admin.OptionalRelationDefinition; 051 import org.opends.server.admin.PropertyDefinition; 052 import org.opends.server.admin.PropertyProvider; 053 import org.opends.server.admin.RelationDefinition; 054 import org.opends.server.admin.SingletonRelationDefinition; 055 import org.opends.server.api.ConfigAddListener; 056 import org.opends.server.api.ConfigChangeListener; 057 import org.opends.server.api.ConfigDeleteListener; 058 import org.opends.server.config.ConfigEntry; 059 import org.opends.server.config.ConfigException; 060 import org.opends.server.core.DirectoryServer; 061 import org.opends.server.loggers.debug.DebugTracer; 062 import org.opends.server.types.DN; 063 import org.opends.server.types.DebugLogLevel; 064 065 066 067 /** 068 * A server-side managed object. 069 * 070 * @param <S> 071 * The type of server configuration represented by the server 072 * managed object. 073 */ 074 public final class ServerManagedObject<S extends Configuration> implements 075 PropertyProvider { 076 077 /** 078 * The tracer object for the debug logger. 079 */ 080 private static final DebugTracer TRACER = getTracer(); 081 082 // The configuration entry associated with this server managed 083 // object (null if root). 084 private ConfigEntry configEntry; 085 086 // The management context. 087 private final ServerManagementContext context = ServerManagementContext 088 .getInstance(); 089 090 // The managed object's definition. 091 private final ManagedObjectDefinition<?, S> definition; 092 093 // The managed object path identifying this managed object's 094 // location. 095 private final ManagedObjectPath<?, S> path; 096 097 // The managed object's properties. 098 private final Map<PropertyDefinition<?>, SortedSet<?>> properties; 099 100 101 102 /** 103 * Creates an new server side managed object. 104 * 105 * @param path 106 * The managed object path. 107 * @param d 108 * The managed object definition. 109 * @param properties 110 * The managed object's properties. 111 * @param configEntry 112 * The configuration entry associated with the managed 113 * object. 114 */ 115 ServerManagedObject(ManagedObjectPath<?, S> path, 116 ManagedObjectDefinition<?, S> d, 117 Map<PropertyDefinition<?>, SortedSet<?>> properties, 118 ConfigEntry configEntry) { 119 this.definition = d; 120 this.path = path; 121 this.properties = properties; 122 this.configEntry = configEntry; 123 } 124 125 126 127 /** 128 * Deregisters an existing configuration add listener. 129 * 130 * @param <M> 131 * The type of the child server configuration object. 132 * @param d 133 * The instantiable relation definition. 134 * @param listener 135 * The configuration add listener. 136 * @throws IllegalArgumentException 137 * If the instantiable relation definition is not 138 * associated with this managed object's definition. 139 */ 140 public <M extends Configuration> void deregisterAddListener( 141 InstantiableRelationDefinition<?, M> d, 142 ConfigurationAddListener<M> listener) throws IllegalArgumentException { 143 validateRelationDefinition(d); 144 145 DN baseDN = DNBuilder.create(path, d); 146 deregisterAddListener(baseDN, listener); 147 } 148 149 150 151 /** 152 * Deregisters an existing server managed object add listener. 153 * 154 * @param <M> 155 * The type of the child server configuration object. 156 * @param d 157 * The instantiable relation definition. 158 * @param listener 159 * The server managed object add listener. 160 * @throws IllegalArgumentException 161 * If the instantiable relation definition is not 162 * associated with this managed object's definition. 163 */ 164 public <M extends Configuration> void deregisterAddListener( 165 InstantiableRelationDefinition<?, M> d, 166 ServerManagedObjectAddListener<M> listener) 167 throws IllegalArgumentException { 168 validateRelationDefinition(d); 169 170 DN baseDN = DNBuilder.create(path, d); 171 deregisterAddListener(baseDN, listener); 172 } 173 174 175 176 /** 177 * Deregisters an existing configuration add listener. 178 * 179 * @param <M> 180 * The type of the child server configuration object. 181 * @param d 182 * The optional relation definition. 183 * @param listener 184 * The configuration add listener. 185 * @throws IllegalArgumentException 186 * If the optional relation definition is not associated 187 * with this managed object's definition. 188 */ 189 public <M extends Configuration> void deregisterAddListener( 190 OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) 191 throws IllegalArgumentException { 192 validateRelationDefinition(d); 193 194 DN baseDN = DNBuilder.create(path, d).getParent(); 195 deregisterAddListener(baseDN, listener); 196 } 197 198 199 200 /** 201 * Deregisters an existing server managed object add listener. 202 * 203 * @param <M> 204 * The type of the child server configuration object. 205 * @param d 206 * The optional relation definition. 207 * @param listener 208 * The server managed object add listener. 209 * @throws IllegalArgumentException 210 * If the optional relation definition is not associated 211 * with this managed object's definition. 212 */ 213 public <M extends Configuration> void deregisterAddListener( 214 OptionalRelationDefinition<?, M> d, 215 ServerManagedObjectAddListener<M> listener) 216 throws IllegalArgumentException { 217 validateRelationDefinition(d); 218 219 DN baseDN = DNBuilder.create(path, d).getParent(); 220 deregisterAddListener(baseDN, listener); 221 } 222 223 224 225 /** 226 * Deregisters an existing configuration change listener. 227 * 228 * @param listener 229 * The configuration change listener. 230 */ 231 public void deregisterChangeListener( 232 ConfigurationChangeListener<? super S> listener) { 233 for (ConfigChangeListener l : configEntry.getChangeListeners()) { 234 if (l instanceof ConfigChangeListenerAdaptor) { 235 ConfigChangeListenerAdaptor<?> adaptor = 236 (ConfigChangeListenerAdaptor<?>) l; 237 ServerManagedObjectChangeListener<?> l2 = adaptor 238 .getServerManagedObjectChangeListener(); 239 if (l2 instanceof ServerManagedObjectChangeListenerAdaptor<?>) { 240 ServerManagedObjectChangeListenerAdaptor<?> adaptor2 = 241 (ServerManagedObjectChangeListenerAdaptor<?>) l2; 242 if (adaptor2.getConfigurationChangeListener() == listener) { 243 adaptor.finalizeChangeListener(); 244 configEntry.deregisterChangeListener(adaptor); 245 } 246 } 247 } 248 } 249 } 250 251 252 253 /** 254 * Deregisters an existing server managed object change listener. 255 * 256 * @param listener 257 * The server managed object change listener. 258 */ 259 public void deregisterChangeListener( 260 ServerManagedObjectChangeListener<? super S> listener) { 261 for (ConfigChangeListener l : configEntry.getChangeListeners()) { 262 if (l instanceof ConfigChangeListenerAdaptor) { 263 ConfigChangeListenerAdaptor<?> adaptor = 264 (ConfigChangeListenerAdaptor<?>) l; 265 if (adaptor.getServerManagedObjectChangeListener() == listener) { 266 adaptor.finalizeChangeListener(); 267 configEntry.deregisterChangeListener(adaptor); 268 } 269 } 270 } 271 } 272 273 274 275 /** 276 * Deregisters an existing configuration delete listener. 277 * 278 * @param <M> 279 * The type of the child server configuration object. 280 * @param d 281 * The instantiable relation definition. 282 * @param listener 283 * The configuration delete listener. 284 * @throws IllegalArgumentException 285 * If the instantiable relation definition is not 286 * associated with this managed object's definition. 287 */ 288 public <M extends Configuration> void deregisterDeleteListener( 289 InstantiableRelationDefinition<?, M> d, 290 ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { 291 validateRelationDefinition(d); 292 293 DN baseDN = DNBuilder.create(path, d); 294 deregisterDeleteListener(baseDN, listener); 295 } 296 297 298 299 /** 300 * Deregisters an existing server managed object delete listener. 301 * 302 * @param <M> 303 * The type of the child server configuration object. 304 * @param d 305 * The instantiable relation definition. 306 * @param listener 307 * The server managed object delete listener. 308 * @throws IllegalArgumentException 309 * If the instantiable relation definition is not 310 * associated with this managed object's definition. 311 */ 312 public <M extends Configuration> void deregisterDeleteListener( 313 InstantiableRelationDefinition<?, M> d, 314 ServerManagedObjectDeleteListener<M> listener) 315 throws IllegalArgumentException { 316 validateRelationDefinition(d); 317 318 DN baseDN = DNBuilder.create(path, d); 319 deregisterDeleteListener(baseDN, listener); 320 } 321 322 323 324 /** 325 * Deregisters an existing configuration delete listener. 326 * 327 * @param <M> 328 * The type of the child server configuration object. 329 * @param d 330 * The optional relation definition. 331 * @param listener 332 * The configuration delete listener. 333 * @throws IllegalArgumentException 334 * If the optional relation definition is not associated 335 * with this managed object's definition. 336 */ 337 public <M extends Configuration> void deregisterDeleteListener( 338 OptionalRelationDefinition<?, M> d, 339 ConfigurationDeleteListener<M> listener) throws IllegalArgumentException { 340 validateRelationDefinition(d); 341 342 DN baseDN = DNBuilder.create(path, d).getParent(); 343 deregisterDeleteListener(baseDN, listener); 344 } 345 346 347 348 /** 349 * Deregisters an existing server managed object delete listener. 350 * 351 * @param <M> 352 * The type of the child server configuration object. 353 * @param d 354 * The optional relation definition. 355 * @param listener 356 * The server managed object delete listener. 357 * @throws IllegalArgumentException 358 * If the optional relation definition is not associated 359 * with this managed object's definition. 360 */ 361 public <M extends Configuration> void deregisterDeleteListener( 362 OptionalRelationDefinition<?, M> d, 363 ServerManagedObjectDeleteListener<M> listener) 364 throws IllegalArgumentException { 365 validateRelationDefinition(d); 366 367 DN baseDN = DNBuilder.create(path, d).getParent(); 368 deregisterDeleteListener(baseDN, listener); 369 } 370 371 372 373 /** 374 * Retrieve an instantiable child managed object. 375 * 376 * @param <M> 377 * The requested type of the child server managed object 378 * configuration. 379 * @param d 380 * The instantiable relation definition. 381 * @param name 382 * The name of the child managed object. 383 * @return Returns the instantiable child managed object. 384 * @throws IllegalArgumentException 385 * If the relation definition is not associated with this 386 * managed object's definition. 387 * @throws ConfigException 388 * If the child managed object could not be found or if it 389 * could not be decoded. 390 */ 391 public <M extends Configuration> ServerManagedObject<? extends M> getChild( 392 InstantiableRelationDefinition<?, M> d, String name) 393 throws IllegalArgumentException, ConfigException { 394 validateRelationDefinition(d); 395 return context.getManagedObject(path.child(d, name)); 396 } 397 398 399 400 /** 401 * Retrieve an optional child managed object. 402 * 403 * @param <M> 404 * The requested type of the child server managed object 405 * configuration. 406 * @param d 407 * The optional relation definition. 408 * @return Returns the optional child managed object. 409 * @throws IllegalArgumentException 410 * If the optional relation definition is not associated 411 * with this managed object's definition. 412 * @throws ConfigException 413 * If the child managed object could not be found or if it 414 * could not be decoded. 415 */ 416 public <M extends Configuration> ServerManagedObject<? extends M> getChild( 417 OptionalRelationDefinition<?, M> d) throws IllegalArgumentException, 418 ConfigException { 419 validateRelationDefinition(d); 420 return context.getManagedObject(path.child(d)); 421 } 422 423 424 425 /** 426 * Retrieve a singleton child managed object. 427 * 428 * @param <M> 429 * The requested type of the child server managed object 430 * configuration. 431 * @param d 432 * The singleton relation definition. 433 * @return Returns the singleton child managed object. 434 * @throws IllegalArgumentException 435 * If the relation definition is not associated with this 436 * managed object's definition. 437 * @throws ConfigException 438 * If the child managed object could not be found or if it 439 * could not be decoded. 440 */ 441 public <M extends Configuration> ServerManagedObject<? extends M> getChild( 442 SingletonRelationDefinition<?, M> d) throws IllegalArgumentException, 443 ConfigException { 444 validateRelationDefinition(d); 445 return context.getManagedObject(path.child(d)); 446 } 447 448 449 450 /** 451 * Creates a server configuration view of this managed object. 452 * 453 * @return Returns the server configuration view of this managed 454 * object. 455 */ 456 public S getConfiguration() { 457 return definition.createServerConfiguration(this); 458 } 459 460 461 462 /** 463 * Get the DN of the LDAP entry associated with this server managed 464 * object. 465 * 466 * @return Returns the DN of the LDAP entry associated with this 467 * server managed object, or an null DN if this is the root 468 * managed object. 469 */ 470 public DN getDN() { 471 if (configEntry != null) { 472 return configEntry.getDN(); 473 } else { 474 return DN.nullDN(); 475 } 476 } 477 478 479 480 /** 481 * Get the definition associated with this server managed object. 482 * 483 * @return Returns the definition associated with this server 484 * managed object. 485 */ 486 public ManagedObjectDefinition<?, S> getManagedObjectDefinition() { 487 return definition; 488 } 489 490 491 492 /** 493 * Get the path of this server managed object. 494 * 495 * @return Returns the path of this server managed object. 496 */ 497 public ManagedObjectPath<?, S> getManagedObjectPath() { 498 return path; 499 } 500 501 502 503 /** 504 * Get the effective value of the specified property. If the 505 * property is multi-valued then just the first value is returned. 506 * If the property does not have a value then its default value is 507 * returned if it has one, or <code>null</code> indicating that 508 * any default behavior is applicable. 509 * 510 * @param <T> 511 * The type of the property to be retrieved. 512 * @param d 513 * The property to be retrieved. 514 * @return Returns the property's effective value, or 515 * <code>null</code> indicating that any default behavior 516 * is applicable. 517 * @throws IllegalArgumentException 518 * If the property definition is not associated with this 519 * managed object's definition. 520 */ 521 public <T> T getPropertyValue(PropertyDefinition<T> d) 522 throws IllegalArgumentException { 523 Set<T> values = getPropertyValues(d); 524 if (values.isEmpty()) { 525 return null; 526 } else { 527 return values.iterator().next(); 528 } 529 } 530 531 532 533 /** 534 * Get the effective values of the specified property. If the 535 * property does not have any values then its default values are 536 * returned if it has any, or an empty set indicating that any 537 * default behavior is applicable. 538 * 539 * @param <T> 540 * The type of the property to be retrieved. 541 * @param d 542 * The property to be retrieved. 543 * @return Returns an unmodifiable set containing the property's 544 * effective values. An empty set indicates that the 545 * property has no default values defined and any default 546 * behavior is applicable. 547 * @throws IllegalArgumentException 548 * If the property definition is not associated with this 549 * managed object's definition. 550 */ 551 @SuppressWarnings("unchecked") 552 public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d) 553 throws IllegalArgumentException { 554 if (!properties.containsKey(d)) { 555 throw new IllegalArgumentException("Unknown property " + d.getName()); 556 } 557 return Collections.unmodifiableSortedSet((SortedSet<T>) properties.get(d)); 558 } 559 560 561 562 /** 563 * Determines whether or not the optional managed object associated 564 * with the specified optional relations exists. 565 * 566 * @param d 567 * The optional relation definition. 568 * @return Returns <code>true</code> if the optional managed 569 * object exists, <code>false</code> otherwise. 570 * @throws IllegalArgumentException 571 * If the optional relation definition is not associated 572 * with this managed object's definition. 573 */ 574 public boolean hasChild(OptionalRelationDefinition<?, ?> d) 575 throws IllegalArgumentException { 576 validateRelationDefinition(d); 577 return context.managedObjectExists(path.child(d)); 578 } 579 580 581 582 /** 583 * Lists the child managed objects associated with the specified 584 * instantiable relation. 585 * 586 * @param d 587 * The instantiable relation definition. 588 * @return Returns the names of the child managed objects. 589 * @throws IllegalArgumentException 590 * If the relation definition is not associated with this 591 * managed object's definition. 592 */ 593 public String[] listChildren(InstantiableRelationDefinition<?, ?> d) 594 throws IllegalArgumentException { 595 validateRelationDefinition(d); 596 return context.listManagedObjects(path, d); 597 } 598 599 600 601 /** 602 * Register to be notified when new child configurations are added 603 * beneath an instantiable relation. 604 * 605 * @param <M> 606 * The type of the child server configuration object. 607 * @param d 608 * The instantiable relation definition. 609 * @param listener 610 * The configuration add listener. 611 * @throws IllegalArgumentException 612 * If the instantiable relation definition is not 613 * associated with this managed object's definition. 614 * @throws ConfigException 615 * If the configuration entry associated with the 616 * instantiable relation could not be retrieved. 617 */ 618 public <M extends Configuration> void registerAddListener( 619 InstantiableRelationDefinition<?, M> d, 620 ConfigurationAddListener<M> listener) throws IllegalArgumentException, 621 ConfigException { 622 registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>( 623 listener)); 624 } 625 626 627 628 /** 629 * Register to be notified when new child server managed object are 630 * added beneath an instantiable relation. 631 * 632 * @param <M> 633 * The type of the child server configuration object. 634 * @param d 635 * The instantiable relation definition. 636 * @param listener 637 * The server managed object add listener. 638 * @throws IllegalArgumentException 639 * If the instantiable relation definition is not 640 * associated with this managed object's definition. 641 * @throws ConfigException 642 * If the configuration entry associated with the 643 * instantiable relation could not be retrieved. 644 */ 645 public <M extends Configuration> void registerAddListener( 646 InstantiableRelationDefinition<?, M> d, 647 ServerManagedObjectAddListener<M> listener) 648 throws IllegalArgumentException, ConfigException { 649 validateRelationDefinition(d); 650 DN baseDN = DNBuilder.create(path, d); 651 ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, 652 listener); 653 registerAddListener(baseDN, adaptor); 654 } 655 656 657 658 /** 659 * Register to be notified when a new child configurations is added 660 * beneath an optional relation. 661 * 662 * @param <M> 663 * The type of the child server configuration object. 664 * @param d 665 * The optional relation definition. 666 * @param listener 667 * The configuration add listener. 668 * @throws IllegalArgumentException 669 * If the optional relation definition is not associated 670 * with this managed object's definition. 671 * @throws ConfigException 672 * If the configuration entry associated with the optional 673 * relation could not be retrieved. 674 */ 675 public <M extends Configuration> void registerAddListener( 676 OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener) 677 throws IllegalArgumentException, ConfigException { 678 registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>( 679 listener)); 680 } 681 682 683 684 /** 685 * Register to be notified when a new child server managed object is 686 * added beneath an optional relation. 687 * 688 * @param <M> 689 * The type of the child server configuration object. 690 * @param d 691 * The optional relation definition. 692 * @param listener 693 * The server managed object add listener. 694 * @throws IllegalArgumentException 695 * If the optional relation definition is not associated 696 * with this managed object's definition. 697 * @throws ConfigException 698 * If the configuration entry associated with the optional 699 * relation could not be retrieved. 700 */ 701 public <M extends Configuration> void registerAddListener( 702 OptionalRelationDefinition<?, M> d, 703 ServerManagedObjectAddListener<M> listener) 704 throws IllegalArgumentException, ConfigException { 705 validateRelationDefinition(d); 706 DN baseDN = DNBuilder.create(path, d).getParent(); 707 ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, 708 listener); 709 registerAddListener(baseDN, adaptor); 710 } 711 712 713 714 /** 715 * Register to be notified when this server managed object is 716 * changed. 717 * 718 * @param listener 719 * The configuration change listener. 720 */ 721 public void registerChangeListener( 722 ConfigurationChangeListener<? super S> listener) { 723 registerChangeListener(new ServerManagedObjectChangeListenerAdaptor<S>( 724 listener)); 725 } 726 727 728 729 /** 730 * Register to be notified when this server managed object is 731 * changed. 732 * 733 * @param listener 734 * The server managed object change listener. 735 */ 736 public void registerChangeListener( 737 ServerManagedObjectChangeListener<? super S> listener) { 738 ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path, 739 listener); 740 configEntry.registerChangeListener(adaptor); 741 742 // Change listener registration usually signifies that a managed 743 // object has been accepted and added to the server configuration 744 // during initialization post-add. 745 746 // FIXME: we should prevent multiple invocations in the case where 747 // multiple change listeners are registered for the same object. 748 for (Constraint constraint : definition.getAllConstraints()) { 749 for (ServerConstraintHandler handler : constraint 750 .getServerConstraintHandlers()) { 751 try { 752 handler.performPostAdd(this); 753 } catch (ConfigException e) { 754 if (debugEnabled()) { 755 TRACER.debugCaught(DebugLogLevel.ERROR, e); 756 } 757 } 758 } 759 } 760 } 761 762 763 764 /** 765 * Register to be notified when existing child configurations are 766 * deleted beneath an instantiable relation. 767 * 768 * @param <M> 769 * The type of the child server configuration object. 770 * @param d 771 * The instantiable relation definition. 772 * @param listener 773 * The configuration delete listener. 774 * @throws IllegalArgumentException 775 * If the instantiable relation definition is not 776 * associated with this managed object's definition. 777 * @throws ConfigException 778 * If the configuration entry associated with the 779 * instantiable relation could not be retrieved. 780 */ 781 public <M extends Configuration> void registerDeleteListener( 782 InstantiableRelationDefinition<?, M> d, 783 ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, 784 ConfigException { 785 registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>( 786 listener)); 787 } 788 789 790 791 /** 792 * Register to be notified when existing child server managed 793 * objects are deleted beneath an instantiable relation. 794 * 795 * @param <M> 796 * The type of the child server configuration object. 797 * @param d 798 * The instantiable relation definition. 799 * @param listener 800 * The server managed objects delete listener. 801 * @throws IllegalArgumentException 802 * If the instantiable relation definition is not 803 * associated with this managed object's definition. 804 * @throws ConfigException 805 * If the configuration entry associated with the 806 * instantiable relation could not be retrieved. 807 */ 808 public <M extends Configuration> void registerDeleteListener( 809 InstantiableRelationDefinition<?, M> d, 810 ServerManagedObjectDeleteListener<M> listener) 811 throws IllegalArgumentException, ConfigException { 812 validateRelationDefinition(d); 813 DN baseDN = DNBuilder.create(path, d); 814 ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, 815 listener); 816 registerDeleteListener(baseDN, adaptor); 817 } 818 819 820 821 /** 822 * Register to be notified when an existing child configuration is 823 * deleted beneath an optional relation. 824 * 825 * @param <M> 826 * The type of the child server configuration object. 827 * @param d 828 * The optional relation definition. 829 * @param listener 830 * The configuration delete listener. 831 * @throws IllegalArgumentException 832 * If the optional relation definition is not associated 833 * with this managed object's definition. 834 * @throws ConfigException 835 * If the configuration entry associated with the optional 836 * relation could not be retrieved. 837 */ 838 public <M extends Configuration> void registerDeleteListener( 839 OptionalRelationDefinition<?, M> d, 840 ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, 841 ConfigException { 842 registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>( 843 listener)); 844 } 845 846 847 848 /** 849 * Register to be notified when an existing child server managed 850 * object is deleted beneath an optional relation. 851 * 852 * @param <M> 853 * The type of the child server configuration object. 854 * @param d 855 * The optional relation definition. 856 * @param listener 857 * The server managed object delete listener. 858 * @throws IllegalArgumentException 859 * If the optional relation definition is not associated 860 * with this managed object's definition. 861 * @throws ConfigException 862 * If the configuration entry associated with the optional 863 * relation could not be retrieved. 864 */ 865 public <M extends Configuration> void registerDeleteListener( 866 OptionalRelationDefinition<?, M> d, 867 ServerManagedObjectDeleteListener<M> listener) 868 throws IllegalArgumentException, ConfigException { 869 validateRelationDefinition(d); 870 DN baseDN = DNBuilder.create(path, d).getParent(); 871 ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, 872 listener); 873 registerDeleteListener(baseDN, adaptor); 874 } 875 876 877 878 /** 879 * {@inheritDoc} 880 */ 881 @Override 882 public String toString() { 883 StringBuilder builder = new StringBuilder(); 884 885 builder.append("{ TYPE="); 886 builder.append(definition.getName()); 887 builder.append(", DN=\""); 888 builder.append(getDN()); 889 builder.append('\"'); 890 for (Map.Entry<PropertyDefinition<?>, SortedSet<?>> value : properties 891 .entrySet()) { 892 builder.append(", "); 893 builder.append(value.getKey().getName()); 894 builder.append('='); 895 builder.append(value.getValue()); 896 } 897 builder.append(" }"); 898 899 return builder.toString(); 900 } 901 902 903 904 /** 905 * Determines whether or not this managed object can be used by the 906 * server. 907 * 908 * @throws ConstraintViolationException 909 * If one or more constraints determined that this managed 910 * object cannot be used by the server. 911 */ 912 void ensureIsUsable() throws ConstraintViolationException { 913 // Enforce any constraints. 914 boolean isUsable = true; 915 List<Message> reasons = new LinkedList<Message>(); 916 for (Constraint constraint : definition.getAllConstraints()) { 917 for (ServerConstraintHandler handler : constraint 918 .getServerConstraintHandlers()) { 919 try { 920 if (!handler.isUsable(this, reasons)) { 921 isUsable = false; 922 } 923 } catch (ConfigException e) { 924 Message message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e 925 .getMessageObject()); 926 reasons.add(message); 927 isUsable = false; 928 } 929 } 930 } 931 932 if (!isUsable) { 933 throw new ConstraintViolationException(this, reasons); 934 } 935 } 936 937 938 939 /** 940 * Update the config entry associated with this server managed 941 * object. This is only intended to be used by change listener call 942 * backs in order to update the managed object with the correct 943 * config entry. 944 * 945 * @param configEntry 946 * The configuration entry. 947 */ 948 void setConfigEntry(ConfigEntry configEntry) { 949 this.configEntry = configEntry; 950 } 951 952 953 954 // Deregister an add listener. 955 private <M extends Configuration> void deregisterAddListener(DN baseDN, 956 ConfigurationAddListener<M> listener) { 957 try { 958 ConfigEntry configEntry = getListenerConfigEntry(baseDN); 959 if (configEntry != null) { 960 for (ConfigAddListener l : configEntry.getAddListeners()) { 961 if (l instanceof ConfigAddListenerAdaptor) { 962 ConfigAddListenerAdaptor<?> adaptor = 963 (ConfigAddListenerAdaptor<?>) l; 964 ServerManagedObjectAddListener<?> l2 = adaptor 965 .getServerManagedObjectAddListener(); 966 if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) { 967 ServerManagedObjectAddListenerAdaptor<?> adaptor2 = 968 (ServerManagedObjectAddListenerAdaptor<?>) l2; 969 if (adaptor2.getConfigurationAddListener() == listener) { 970 configEntry.deregisterAddListener(adaptor); 971 } 972 } 973 } 974 } 975 } 976 } catch (ConfigException e) { 977 // Ignore the exception since this implies deregistration. 978 if (debugEnabled()) { 979 TRACER.debugCaught(DebugLogLevel.ERROR, e); 980 } 981 } 982 } 983 984 985 986 // Deregister an add listener. 987 private <M extends Configuration> void deregisterAddListener(DN baseDN, 988 ServerManagedObjectAddListener<M> listener) { 989 try { 990 ConfigEntry configEntry = getListenerConfigEntry(baseDN); 991 if (configEntry != null) { 992 for (ConfigAddListener l : configEntry.getAddListeners()) { 993 if (l instanceof ConfigAddListenerAdaptor) { 994 ConfigAddListenerAdaptor<?> adaptor = 995 (ConfigAddListenerAdaptor<?>) l; 996 if (adaptor.getServerManagedObjectAddListener() == listener) { 997 configEntry.deregisterAddListener(adaptor); 998 } 999 } 1000 } 1001 } 1002 } catch (ConfigException e) { 1003 // Ignore the exception since this implies deregistration. 1004 if (debugEnabled()) { 1005 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1006 } 1007 } 1008 } 1009 1010 1011 1012 // Deregister a delete listener. 1013 private <M extends Configuration> void deregisterDeleteListener(DN baseDN, 1014 ConfigurationDeleteListener<M> listener) { 1015 try { 1016 ConfigEntry configEntry = getListenerConfigEntry(baseDN); 1017 if (configEntry != null) { 1018 for (ConfigDeleteListener l : configEntry.getDeleteListeners()) { 1019 if (l instanceof ConfigDeleteListenerAdaptor) { 1020 ConfigDeleteListenerAdaptor<?> adaptor = 1021 (ConfigDeleteListenerAdaptor<?>) l; 1022 ServerManagedObjectDeleteListener<?> l2 = adaptor 1023 .getServerManagedObjectDeleteListener(); 1024 if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) { 1025 ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 = 1026 (ServerManagedObjectDeleteListenerAdaptor<?>) l2; 1027 if (adaptor2.getConfigurationDeleteListener() == listener) { 1028 configEntry.deregisterDeleteListener(adaptor); 1029 } 1030 } 1031 } 1032 } 1033 } 1034 } catch (ConfigException e) { 1035 // Ignore the exception since this implies deregistration. 1036 if (debugEnabled()) { 1037 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1038 } 1039 } 1040 } 1041 1042 1043 1044 // Deregister a delete listener. 1045 private <M extends Configuration> void deregisterDeleteListener(DN baseDN, 1046 ServerManagedObjectDeleteListener<M> listener) { 1047 try { 1048 ConfigEntry configEntry = getListenerConfigEntry(baseDN); 1049 if (configEntry != null) { 1050 for (ConfigDeleteListener l : configEntry.getDeleteListeners()) { 1051 if (l instanceof ConfigDeleteListenerAdaptor) { 1052 ConfigDeleteListenerAdaptor<?> adaptor = 1053 (ConfigDeleteListenerAdaptor<?>) l; 1054 if (adaptor.getServerManagedObjectDeleteListener() == listener) { 1055 configEntry.deregisterDeleteListener(adaptor); 1056 } 1057 } 1058 } 1059 } 1060 } catch (ConfigException e) { 1061 // Ignore the exception since this implies deregistration. 1062 if (debugEnabled()) { 1063 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1064 } 1065 } 1066 } 1067 1068 1069 1070 // Gets a config entry required for a listener and throws a config 1071 // exception on failure or returns null if the entry does not exist. 1072 private ConfigEntry getListenerConfigEntry(DN dn) throws ConfigException { 1073 // Attempt to retrieve the listener base entry. 1074 ConfigEntry configEntry; 1075 try { 1076 configEntry = DirectoryServer.getConfigEntry(dn); 1077 } catch (ConfigException e) { 1078 if (debugEnabled()) { 1079 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1080 } 1081 1082 Message message = AdminMessages.ERR_ADMIN_CANNOT_GET_LISTENER_BASE.get( 1083 String.valueOf(dn), stackTraceToSingleLineString(e)); 1084 throw new ConfigException(message, e); 1085 } 1086 1087 return configEntry; 1088 } 1089 1090 1091 1092 // Register an instantiable or optional relation add listener. 1093 private void registerAddListener(DN baseDN, ConfigAddListener adaptor) 1094 throws IllegalArgumentException, ConfigException { 1095 ConfigEntry relationEntry = getListenerConfigEntry(baseDN); 1096 1097 if (relationEntry != null) { 1098 relationEntry.registerAddListener(adaptor); 1099 } else { 1100 // The relation entry does not exist yet so register a delayed 1101 // add listener. 1102 ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, 1103 adaptor); 1104 registerDelayedListener(baseDN, delayedListener); 1105 } 1106 } 1107 1108 1109 1110 // Register a delayed listener with the nearest existing parent 1111 // entry to the provided base DN. 1112 private void registerDelayedListener(DN baseDN, 1113 ConfigAddListener delayedListener) throws ConfigException { 1114 DN parentDN = baseDN.getParent(); 1115 while (parentDN != null) { 1116 ConfigEntry relationEntry = getListenerConfigEntry(parentDN); 1117 if (relationEntry == null) { 1118 delayedListener = new DelayedConfigAddListener(parentDN, 1119 delayedListener); 1120 parentDN = parentDN.getParent(); 1121 } else { 1122 relationEntry.registerAddListener(delayedListener); 1123 return; 1124 } 1125 } 1126 1127 // No parent entry could be found. 1128 Message message = AdminMessages.ERR_ADMIN_UNABLE_TO_REGISTER_LISTENER 1129 .get(String.valueOf(baseDN)); 1130 throw new ConfigException(message); 1131 } 1132 1133 1134 1135 // Register an instantiable or optional relation delete listener. 1136 private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) 1137 throws ConfigException { 1138 ConfigEntry relationEntry = getListenerConfigEntry(baseDN); 1139 1140 if (relationEntry != null) { 1141 relationEntry.registerDeleteListener(adaptor); 1142 } else { 1143 // The relation entry does not exist yet so register a delayed 1144 // add listener. 1145 ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, 1146 adaptor); 1147 registerDelayedListener(baseDN, delayedListener); 1148 } 1149 } 1150 1151 1152 1153 // Validate that a relation definition belongs to this managed 1154 // object. 1155 private void validateRelationDefinition(RelationDefinition<?, ?> rd) 1156 throws IllegalArgumentException { 1157 RelationDefinition<?, ?> tmp = definition.getRelationDefinition(rd 1158 .getName()); 1159 if (tmp != rd) { 1160 throw new IllegalArgumentException("The relation " + rd.getName() 1161 + " is not associated with a " + definition.getName()); 1162 } 1163 } 1164 }