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 2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.admin.server; 029 030 031 032 import static org.opends.server.loggers.debug.DebugLogger.*; 033 import static org.opends.server.util.StaticUtils.*; 034 035 import java.util.ArrayList; 036 import java.util.Collection; 037 import java.util.Collections; 038 import java.util.HashMap; 039 import java.util.LinkedList; 040 import java.util.List; 041 import java.util.Map; 042 import java.util.Set; 043 import java.util.SortedSet; 044 import java.util.TreeSet; 045 046 import org.opends.messages.AdminMessages; 047 import org.opends.messages.Message; 048 import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider; 049 import org.opends.server.admin.AbstractManagedObjectDefinition; 050 import org.opends.server.admin.AggregationPropertyDefinition; 051 import org.opends.server.admin.AliasDefaultBehaviorProvider; 052 import org.opends.server.admin.Configuration; 053 import org.opends.server.admin.ConfigurationClient; 054 import org.opends.server.admin.DefaultBehaviorException; 055 import org.opends.server.admin.DefaultBehaviorProviderVisitor; 056 import org.opends.server.admin.DefinedDefaultBehaviorProvider; 057 import org.opends.server.admin.DefinitionDecodingException; 058 import org.opends.server.admin.DefinitionResolver; 059 import org.opends.server.admin.IllegalPropertyValueException; 060 import org.opends.server.admin.IllegalPropertyValueStringException; 061 import org.opends.server.admin.InstantiableRelationDefinition; 062 import org.opends.server.admin.LDAPProfile; 063 import org.opends.server.admin.ManagedObjectDefinition; 064 import org.opends.server.admin.ManagedObjectPath; 065 import org.opends.server.admin.PropertyDefinition; 066 import org.opends.server.admin.PropertyDefinitionVisitor; 067 import org.opends.server.admin.PropertyException; 068 import org.opends.server.admin.PropertyIsMandatoryException; 069 import org.opends.server.admin.PropertyIsSingleValuedException; 070 import org.opends.server.admin.PropertyNotFoundException; 071 import org.opends.server.admin.PropertyOption; 072 import org.opends.server.admin.Reference; 073 import org.opends.server.admin.RelationDefinition; 074 import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider; 075 import org.opends.server.admin.UndefinedDefaultBehaviorProvider; 076 import org.opends.server.admin.UnknownPropertyDefinitionException; 077 import org.opends.server.admin.DefinitionDecodingException.Reason; 078 import org.opends.server.admin.std.meta.RootCfgDefn; 079 import org.opends.server.admin.std.server.RootCfg; 080 import org.opends.server.api.AttributeValueDecoder; 081 import org.opends.server.config.ConfigEntry; 082 import org.opends.server.config.ConfigException; 083 import org.opends.server.core.DirectoryServer; 084 import org.opends.server.loggers.debug.DebugTracer; 085 import org.opends.server.types.AttributeType; 086 import org.opends.server.types.AttributeValue; 087 import org.opends.server.types.DN; 088 import org.opends.server.types.DebugLogLevel; 089 import org.opends.server.types.DirectoryException; 090 091 092 093 /** 094 * Server management connection context. 095 */ 096 public final class ServerManagementContext { 097 098 /** 099 * A default behavior visitor used for retrieving the default values 100 * of a property. 101 * 102 * @param <T> 103 * The type of the property. 104 */ 105 private class DefaultValueFinder<T> implements 106 DefaultBehaviorProviderVisitor<T, Collection<T>, Void> { 107 108 // Any exception that occurred whilst retrieving inherited default 109 // values. 110 private DefaultBehaviorException exception = null; 111 112 // Optional new configuration entry which does not yet exist in 113 // the configuration back-end. 114 private ConfigEntry newConfigEntry; 115 116 // The path of the managed object containing the next property. 117 private ManagedObjectPath<?, ?> nextPath = null; 118 119 // The next property whose default values were required. 120 private PropertyDefinition<T> nextProperty = null; 121 122 123 124 // Private constructor. 125 private DefaultValueFinder(ConfigEntry newConfigEntry) { 126 this.newConfigEntry = newConfigEntry; 127 } 128 129 130 131 /** 132 * {@inheritDoc} 133 */ 134 public Collection<T> visitAbsoluteInherited( 135 AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) { 136 try { 137 return getInheritedProperty(d.getManagedObjectPath(), d 138 .getManagedObjectDefinition(), d.getPropertyName()); 139 } catch (DefaultBehaviorException e) { 140 exception = e; 141 return Collections.emptySet(); 142 } 143 } 144 145 146 147 /** 148 * {@inheritDoc} 149 */ 150 public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) { 151 return Collections.emptySet(); 152 } 153 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d, 160 Void p) { 161 Collection<String> stringValues = d.getDefaultValues(); 162 List<T> values = new ArrayList<T>(stringValues.size()); 163 164 for (String stringValue : stringValues) { 165 try { 166 values.add(nextProperty.decodeValue(stringValue)); 167 } catch (IllegalPropertyValueStringException e) { 168 exception = new DefaultBehaviorException(nextProperty, e); 169 break; 170 } 171 } 172 173 return values; 174 } 175 176 177 178 /** 179 * {@inheritDoc} 180 */ 181 public Collection<T> visitRelativeInherited( 182 RelativeInheritedDefaultBehaviorProvider<T> d, Void p) { 183 try { 184 return getInheritedProperty(d.getManagedObjectPath(nextPath), d 185 .getManagedObjectDefinition(), d.getPropertyName()); 186 } catch (DefaultBehaviorException e) { 187 exception = e; 188 return Collections.emptySet(); 189 } 190 } 191 192 193 194 /** 195 * {@inheritDoc} 196 */ 197 public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, 198 Void p) { 199 return Collections.emptySet(); 200 } 201 202 203 204 // Find the default values for the next path/property. 205 private Collection<T> find(ManagedObjectPath<?, ?> p, 206 PropertyDefinition<T> pd) throws DefaultBehaviorException { 207 nextPath = p; 208 nextProperty = pd; 209 210 Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept( 211 this, null); 212 213 if (exception != null) { 214 throw exception; 215 } 216 217 if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { 218 throw new DefaultBehaviorException(pd, 219 new PropertyIsSingleValuedException(pd)); 220 } 221 222 return values; 223 } 224 225 226 227 // Get an inherited property value. 228 @SuppressWarnings("unchecked") 229 private Collection<T> getInheritedProperty(ManagedObjectPath target, 230 AbstractManagedObjectDefinition<?, ?> d, String propertyName) 231 throws DefaultBehaviorException { 232 // First check that the requested type of managed object 233 // corresponds to the path. 234 AbstractManagedObjectDefinition<?, ?> supr = target 235 .getManagedObjectDefinition(); 236 if (!supr.isParentOf(d)) { 237 throw new DefaultBehaviorException( 238 nextProperty, new DefinitionDecodingException(supr, 239 Reason.WRONG_TYPE_INFORMATION)); 240 } 241 242 // Save the current property in case of recursion. 243 PropertyDefinition<T> pd1 = nextProperty; 244 245 try { 246 // Get the actual managed object definition. 247 DN dn = DNBuilder.create(target); 248 ConfigEntry configEntry; 249 if (newConfigEntry != null && newConfigEntry.getDN().equals(dn)) { 250 configEntry = newConfigEntry; 251 } else { 252 configEntry = getManagedObjectConfigEntry(dn); 253 } 254 255 DefinitionResolver resolver = new MyDefinitionResolver(configEntry); 256 ManagedObjectDefinition<?, ?> mod = d 257 .resolveManagedObjectDefinition(resolver); 258 259 PropertyDefinition<T> pd2; 260 try { 261 PropertyDefinition<?> pdTmp = mod.getPropertyDefinition(propertyName); 262 pd2 = pd1.getClass().cast(pdTmp); 263 } catch (IllegalArgumentException e) { 264 throw new PropertyNotFoundException(propertyName); 265 } catch (ClassCastException e) { 266 // FIXME: would be nice to throw a better exception here. 267 throw new PropertyNotFoundException(propertyName); 268 } 269 270 List<AttributeValue> values = getAttribute(mod, pd2, configEntry); 271 if (values.isEmpty()) { 272 // Recursively retrieve this property's default values. 273 Collection<T> tmp = find(target, pd2); 274 Collection<T> pvalues = new ArrayList<T>(tmp.size()); 275 for (T value : tmp) { 276 pd1.validateValue(value); 277 pvalues.add(value); 278 } 279 return pvalues; 280 } else { 281 Collection<T> pvalues = new ArrayList<T>(values.size()); 282 for (AttributeValue value : values) { 283 pvalues.add(ValueDecoder.decode(pd1, value)); 284 } 285 return pvalues; 286 } 287 } catch (DefinitionDecodingException e) { 288 throw new DefaultBehaviorException(pd1, e); 289 } catch (PropertyNotFoundException e) { 290 throw new DefaultBehaviorException(pd1, e); 291 } catch (IllegalPropertyValueException e) { 292 throw new DefaultBehaviorException(pd1, e); 293 } catch (IllegalPropertyValueStringException e) { 294 throw new DefaultBehaviorException(pd1, e); 295 } catch (ConfigException e) { 296 throw new DefaultBehaviorException(pd1, e); 297 } 298 } 299 } 300 301 302 303 /** 304 * A definition resolver that determines the managed object 305 * definition from the object classes of a ConfigEntry. 306 */ 307 private class MyDefinitionResolver implements DefinitionResolver { 308 309 // The config entry. 310 private final ConfigEntry entry; 311 312 313 314 // Private constructor. 315 private MyDefinitionResolver(ConfigEntry entry) { 316 this.entry = entry; 317 } 318 319 320 321 /** 322 * {@inheritDoc} 323 */ 324 public boolean matches(AbstractManagedObjectDefinition<?, ?> d) { 325 String oc = LDAPProfile.getInstance().getObjectClass(d); 326 return entry.hasObjectClass(oc); 327 } 328 } 329 330 331 332 /** 333 * A visitor which is used to decode property LDAP values. 334 */ 335 private static final class ValueDecoder extends 336 PropertyDefinitionVisitor<Object, String> { 337 338 /** 339 * Decodes the provided property LDAP value. 340 * 341 * @param <PD> 342 * The type of the property. 343 * @param pd 344 * The property definition. 345 * @param value 346 * The LDAP string representation. 347 * @return Returns the decoded LDAP value. 348 * @throws IllegalPropertyValueStringException 349 * If the property value could not be decoded because it 350 * was invalid. 351 */ 352 public static <PD> PD decode(PropertyDefinition<PD> pd, 353 AttributeValue value) throws IllegalPropertyValueStringException { 354 String s = value.getStringValue(); 355 return pd.castValue(pd.accept(new ValueDecoder(), s)); 356 } 357 358 359 360 // Prevent instantiation. 361 private ValueDecoder() { 362 // No implementation required. 363 } 364 365 366 367 /** 368 * {@inheritDoc} 369 */ 370 @Override 371 public <C extends ConfigurationClient, S extends Configuration> 372 Object visitAggregation(AggregationPropertyDefinition<C, S> d, String p) { 373 // Aggregations values are stored as full DNs in LDAP, but 374 // just their common name is exposed in the admin framework. 375 try { 376 Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d 377 .getRelationDefinition(), p); 378 return reference.getName(); 379 } catch (IllegalArgumentException e) { 380 throw new IllegalPropertyValueStringException(d, p); 381 } 382 } 383 384 385 386 /** 387 * {@inheritDoc} 388 */ 389 @Override 390 public <T> Object visitUnknown(PropertyDefinition<T> d, String p) 391 throws UnknownPropertyDefinitionException { 392 // By default the property definition's decoder will do. 393 return d.decodeValue(p); 394 } 395 } 396 397 398 399 // Singleton instance. 400 private final static ServerManagementContext INSTANCE = 401 new ServerManagementContext(); 402 403 /** 404 * The root server managed object. 405 */ 406 private static final ServerManagedObject<RootCfg> ROOT = 407 new ServerManagedObject<RootCfg>( 408 ManagedObjectPath.emptyPath(), RootCfgDefn.getInstance(), Collections 409 .<PropertyDefinition<?>, SortedSet<?>> emptyMap(), null); 410 411 /** 412 * The tracer object for the debug logger. 413 */ 414 private static final DebugTracer TRACER = getTracer(); 415 416 417 418 /** 419 * Get the single server-side management context. 420 * 421 * @return Returns the single server-side management context. 422 */ 423 public static ServerManagementContext getInstance() { 424 return INSTANCE; 425 } 426 427 428 429 // Private constructor. 430 private ServerManagementContext() { 431 // No implementation required. 432 } 433 434 435 436 /** 437 * Gets the named managed object. 438 * 439 * @param <C> 440 * The type of client managed object configuration that the 441 * path definition refers to. 442 * @param <S> 443 * The type of server managed object configuration that the 444 * path definition refers to. 445 * @param path 446 * The path of the managed object. 447 * @return Returns the named managed object. 448 * @throws ConfigException 449 * If the named managed object could not be found or if it 450 * could not be decoded. 451 */ 452 @SuppressWarnings("unchecked") 453 public <C extends ConfigurationClient, S extends Configuration> 454 ServerManagedObject<? extends S> getManagedObject( 455 ManagedObjectPath<C, S> path) throws ConfigException { 456 // Be careful to handle the root configuration. 457 if (path.isEmpty()) { 458 return (ServerManagedObject<S>) getRootConfigurationManagedObject(); 459 } 460 461 // Get the configuration entry. 462 DN targetDN = DNBuilder.create(path); 463 ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN); 464 try { 465 ServerManagedObject<? extends S> managedObject; 466 managedObject = decode(path, configEntry); 467 468 // Enforce any constraints. 469 managedObject.ensureIsUsable(); 470 471 return managedObject; 472 } catch (DefinitionDecodingException e) { 473 throw ConfigExceptionFactory.getInstance() 474 .createDecodingExceptionAdaptor(targetDN, e); 475 } catch (ServerManagedObjectDecodingException e) { 476 throw ConfigExceptionFactory.getInstance() 477 .createDecodingExceptionAdaptor(e); 478 } catch (ConstraintViolationException e) { 479 throw ConfigExceptionFactory.getInstance() 480 .createDecodingExceptionAdaptor(e); 481 } 482 } 483 484 485 486 /** 487 * Gets the effective value of a property in the named managed 488 * object. 489 * 490 * @param <C> 491 * The type of client managed object configuration that the 492 * path definition refers to. 493 * @param <S> 494 * The type of server managed object configuration that the 495 * path definition refers to. 496 * @param <PD> 497 * The type of the property to be retrieved. 498 * @param path 499 * The path of the managed object containing the property. 500 * @param pd 501 * The property to be retrieved. 502 * @return Returns the property's effective value, or 503 * <code>null</code> if there are no values defined. 504 * @throws IllegalArgumentException 505 * If the property definition is not associated with the 506 * referenced managed object's definition. 507 * @throws PropertyException 508 * If the managed object was found but the requested 509 * property could not be decoded. 510 * @throws ConfigException 511 * If the named managed object could not be found or if it 512 * could not be decoded. 513 */ 514 public <C extends ConfigurationClient, S extends Configuration, PD> 515 PD getPropertyValue(ManagedObjectPath<C, S> path, 516 PropertyDefinition<PD> pd) throws IllegalArgumentException, 517 ConfigException, PropertyException { 518 SortedSet<PD> values = getPropertyValues(path, pd); 519 if (values.isEmpty()) { 520 return null; 521 } else { 522 return values.first(); 523 } 524 } 525 526 527 528 /** 529 * Gets the effective values of a property in the named managed 530 * object. 531 * 532 * @param <C> 533 * The type of client managed object configuration that the 534 * path definition refers to. 535 * @param <S> 536 * The type of server managed object configuration that the 537 * path definition refers to. 538 * @param <PD> 539 * The type of the property to be retrieved. 540 * @param path 541 * The path of the managed object containing the property. 542 * @param pd 543 * The property to be retrieved. 544 * @return Returns the property's effective values, or an empty set 545 * if there are no values defined. 546 * @throws IllegalArgumentException 547 * If the property definition is not associated with the 548 * referenced managed object's definition. 549 * @throws PropertyException 550 * If the managed object was found but the requested 551 * property could not be decoded. 552 * @throws ConfigException 553 * If the named managed object could not be found or if it 554 * could not be decoded. 555 */ 556 @SuppressWarnings("unchecked") 557 public <C extends ConfigurationClient, S extends Configuration, PD> 558 SortedSet<PD> getPropertyValues(ManagedObjectPath<C, S> path, 559 PropertyDefinition<PD> pd) throws IllegalArgumentException, 560 ConfigException, PropertyException { 561 // Check that the requested property is from the definition 562 // associated with the path. 563 AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition(); 564 PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName()); 565 if (tmp != pd) { 566 throw new IllegalArgumentException("The property " + pd.getName() 567 + " is not associated with a " + d.getName()); 568 } 569 570 // Determine the exact type of managed object referenced by the 571 // path. 572 DN dn = DNBuilder.create(path); 573 ConfigEntry configEntry = getManagedObjectConfigEntry(dn); 574 575 DefinitionResolver resolver = new MyDefinitionResolver(configEntry); 576 ManagedObjectDefinition<? extends C, ? extends S> mod; 577 578 try { 579 mod = d.resolveManagedObjectDefinition(resolver); 580 } catch (DefinitionDecodingException e) { 581 throw ConfigExceptionFactory.getInstance() 582 .createDecodingExceptionAdaptor(dn, e); 583 } 584 585 // Make sure we use the correct property definition, the 586 // provided one might have been overridden in the resolved 587 // definition. 588 pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName()); 589 590 List<AttributeValue> values = getAttribute(mod, pd, configEntry); 591 return decodeProperty(path.asSubType(mod), pd, values, null); 592 } 593 594 595 596 /** 597 * Get the root configuration manager associated with this 598 * management context. 599 * 600 * @return Returns the root configuration manager associated with 601 * this management context. 602 */ 603 public RootCfg getRootConfiguration() { 604 return getRootConfigurationManagedObject().getConfiguration(); 605 } 606 607 608 609 /** 610 * Get the root configuration server managed object associated with 611 * this management context. 612 * 613 * @return Returns the root configuration server managed object 614 * associated with this management context. 615 */ 616 public ServerManagedObject<RootCfg> getRootConfigurationManagedObject() { 617 return ROOT; 618 } 619 620 621 622 /** 623 * Lists the child managed objects of the named parent managed 624 * object. 625 * 626 * @param <C> 627 * The type of client managed object configuration that the 628 * relation definition refers to. 629 * @param <S> 630 * The type of server managed object configuration that the 631 * relation definition refers to. 632 * @param parent 633 * The path of the parent managed object. 634 * @param rd 635 * The instantiable relation definition. 636 * @return Returns the names of the child managed objects. 637 * @throws IllegalArgumentException 638 * If the relation definition is not associated with the 639 * parent managed object's definition. 640 */ 641 public <C extends ConfigurationClient, S extends Configuration> 642 String[] listManagedObjects( 643 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) 644 throws IllegalArgumentException { 645 validateRelationDefinition(parent, rd); 646 647 // Get the target entry. 648 DN targetDN = DNBuilder.create(parent, rd); 649 ConfigEntry configEntry; 650 try { 651 configEntry = DirectoryServer.getConfigEntry(targetDN); 652 } catch (ConfigException e) { 653 return new String[0]; 654 } 655 656 if (configEntry == null) { 657 return new String[0]; 658 } 659 660 // Retrieve the children. 661 Set<DN> children = configEntry.getChildren().keySet(); 662 ArrayList<String> names = new ArrayList<String>(children.size()); 663 for (DN child : children) { 664 // Assume that RDNs are single-valued and can be trimmed. 665 AttributeValue av = child.getRDN().getAttributeValue(0); 666 names.add(av.getStringValue().trim()); 667 } 668 669 return names.toArray(new String[names.size()]); 670 } 671 672 673 674 /** 675 * Determines whether or not the named managed object exists. 676 * 677 * @param path 678 * The path of the named managed object. 679 * @return Returns <code>true</code> if the named managed object 680 * exists, <code>false</code> otherwise. 681 */ 682 public boolean managedObjectExists(ManagedObjectPath<?, ?> path) { 683 // Get the configuration entry. 684 DN targetDN = DNBuilder.create(path); 685 try { 686 return (getManagedObjectConfigEntry(targetDN) != null); 687 } catch (ConfigException e) { 688 // Assume it doesn't exist. 689 return false; 690 } 691 } 692 693 694 695 /** 696 * Decodes a configuration entry into the required type of server 697 * managed object. 698 * 699 * @param <C> 700 * The type of client managed object configuration that the 701 * path definition refers to. 702 * @param <S> 703 * The type of server managed object configuration that the 704 * path definition refers to. 705 * @param path 706 * The location of the server managed object. 707 * @param configEntry 708 * The configuration entry that should be decoded. 709 * @return Returns the new server-side managed object from the 710 * provided definition and configuration entry. 711 * @throws DefinitionDecodingException 712 * If the managed object's type could not be determined. 713 * @throws ServerManagedObjectDecodingException 714 * If one or more of the managed object's properties could 715 * not be decoded. 716 */ 717 <C extends ConfigurationClient, S extends Configuration> 718 ServerManagedObject<? extends S> decode( 719 ManagedObjectPath<C, S> path, ConfigEntry configEntry) 720 throws DefinitionDecodingException, ServerManagedObjectDecodingException { 721 return decode(path, configEntry, null); 722 } 723 724 725 726 /** 727 * Decodes a configuration entry into the required type of server 728 * managed object. 729 * 730 * @param <C> 731 * The type of client managed object configuration that the 732 * path definition refers to. 733 * @param <S> 734 * The type of server managed object configuration that the 735 * path definition refers to. 736 * @param path 737 * The location of the server managed object. 738 * @param configEntry 739 * The configuration entry that should be decoded. 740 * @param newConfigEntry 741 * Optional new configuration that does not exist yet in 742 * the configuration back-end. This will be used for 743 * resolving inherited default values. 744 * @return Returns the new server-side managed object from the 745 * provided definition and configuration entry. 746 * @throws DefinitionDecodingException 747 * If the managed object's type could not be determined. 748 * @throws ServerManagedObjectDecodingException 749 * If one or more of the managed object's properties could 750 * not be decoded. 751 */ 752 <C extends ConfigurationClient, S extends Configuration> 753 ServerManagedObject<? extends S> decode( 754 ManagedObjectPath<C, S> path, ConfigEntry configEntry, 755 ConfigEntry newConfigEntry) throws DefinitionDecodingException, 756 ServerManagedObjectDecodingException { 757 // First determine the correct definition to use for the entry. 758 // This could either be the provided definition, or one of its 759 // sub-definitions. 760 DefinitionResolver resolver = new MyDefinitionResolver(configEntry); 761 AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition(); 762 ManagedObjectDefinition<? extends C, ? extends S> mod = d 763 .resolveManagedObjectDefinition(resolver); 764 765 // Build the managed object's properties. 766 List<PropertyException> exceptions = new LinkedList<PropertyException>(); 767 Map<PropertyDefinition<?>, SortedSet<?>> properties = 768 new HashMap<PropertyDefinition<?>, SortedSet<?>>(); 769 for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { 770 List<AttributeValue> values = getAttribute(mod, pd, configEntry); 771 try { 772 SortedSet<?> pvalues = decodeProperty(path, pd, values, newConfigEntry); 773 properties.put(pd, pvalues); 774 } catch (PropertyException e) { 775 exceptions.add(e); 776 } 777 } 778 779 // If there were no decoding problems then return the managed 780 // object, otherwise throw an operations exception. 781 ServerManagedObject<? extends S> mo = decodeAux(path, mod, properties, 782 configEntry); 783 if (exceptions.isEmpty()) { 784 return mo; 785 } else { 786 throw new ServerManagedObjectDecodingException(mo, exceptions); 787 } 788 } 789 790 791 792 // Decode helper method required to avoid generics warning. 793 private <C extends ConfigurationClient, S extends Configuration> 794 ServerManagedObject<S> decodeAux( 795 ManagedObjectPath<? super C, ? super S> path, 796 ManagedObjectDefinition<C, S> d, 797 Map<PropertyDefinition<?>, SortedSet<?>> properties, 798 ConfigEntry configEntry) { 799 ManagedObjectPath<C, S> newPath = path.asSubType(d); 800 return new ServerManagedObject<S>(newPath, d, properties, configEntry); 801 } 802 803 804 805 // Create a property using the provided string values. 806 private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path, 807 PropertyDefinition<T> pd, List<AttributeValue> values, 808 ConfigEntry newConfigEntry) throws PropertyException { 809 PropertyException exception = null; 810 SortedSet<T> pvalues = new TreeSet<T>(pd); 811 812 if (!values.isEmpty()) { 813 // The property has values defined for it. 814 for (AttributeValue value : values) { 815 try { 816 pvalues.add(ValueDecoder.decode(pd, value)); 817 } catch (IllegalPropertyValueStringException e) { 818 exception = e; 819 } 820 } 821 } else { 822 // No values defined so get the defaults. 823 try { 824 pvalues.addAll(getDefaultValues(path, pd, newConfigEntry)); 825 } catch (DefaultBehaviorException e) { 826 exception = e; 827 } 828 } 829 830 if (pvalues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { 831 // This exception takes precedence over previous exceptions. 832 exception = new PropertyIsSingleValuedException(pd); 833 T value = pvalues.first(); 834 pvalues.clear(); 835 pvalues.add(value); 836 } 837 838 if (pvalues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) { 839 // The values maybe empty because of a previous exception. 840 if (exception == null) { 841 exception = new PropertyIsMandatoryException(pd); 842 } 843 } 844 845 if (exception != null) { 846 throw exception; 847 } else { 848 return pvalues; 849 } 850 } 851 852 853 854 // Gets the attribute associated with a property from a ConfigEntry. 855 private List<AttributeValue> getAttribute(ManagedObjectDefinition<?, ?> d, 856 PropertyDefinition<?> pd, ConfigEntry configEntry) { 857 // TODO: we create a default attribute type if it is 858 // undefined. We should log a warning here if this is the case 859 // since the attribute should have been defined. 860 String attrID = LDAPProfile.getInstance().getAttributeName(d, pd); 861 AttributeType type = DirectoryServer.getAttributeType(attrID, true); 862 AttributeValueDecoder<AttributeValue> decoder = 863 new AttributeValueDecoder<AttributeValue>() { 864 865 public AttributeValue decode(AttributeValue value) 866 throws DirectoryException { 867 return value; 868 } 869 }; 870 871 List<AttributeValue> values = new LinkedList<AttributeValue>(); 872 try { 873 configEntry.getEntry().getAttributeValues(type, decoder, values); 874 } catch (DirectoryException e) { 875 // Should not happen. 876 throw new RuntimeException(e); 877 } 878 return values; 879 } 880 881 882 883 // Get the default values for the specified property. 884 private <T> Collection<T> getDefaultValues(ManagedObjectPath<?, ?> p, 885 PropertyDefinition<T> pd, ConfigEntry newConfigEntry) 886 throws DefaultBehaviorException { 887 DefaultValueFinder<T> v = new DefaultValueFinder<T>(newConfigEntry); 888 return v.find(p, pd); 889 } 890 891 892 893 // Gets a config entry required for a managed object and throws a 894 // config exception on failure. 895 private ConfigEntry getManagedObjectConfigEntry( 896 DN dn) throws ConfigException { 897 ConfigEntry configEntry; 898 try { 899 configEntry = DirectoryServer.getConfigEntry(dn); 900 } catch (ConfigException e) { 901 if (debugEnabled()) { 902 TRACER.debugCaught(DebugLogLevel.ERROR, e); 903 } 904 905 Message message = AdminMessages.ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get( 906 String.valueOf(dn), stackTraceToSingleLineString(e)); 907 throw new ConfigException(message, e); 908 } 909 910 // The configuration handler is free to return null indicating 911 // that the entry does not exist. 912 if (configEntry == null) { 913 Message message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST 914 .get(String.valueOf(dn)); 915 throw new ConfigException(message); 916 } 917 918 return configEntry; 919 } 920 921 922 923 // Validate that a relation definition belongs to the path. 924 private void validateRelationDefinition(ManagedObjectPath<?, ?> path, 925 RelationDefinition<?, ?> rd) throws IllegalArgumentException { 926 AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition(); 927 RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); 928 if (tmp != rd) { 929 throw new IllegalArgumentException("The relation " + rd.getName() 930 + " is not associated with a " + d.getName()); 931 } 932 } 933 }