opends/src/server/org/opends/server/admin/client/ManagedObject.java
@@ -216,7 +216,7 @@ /** * Retrieve an instantiable child managed object. * Retrieves an instantiable child managed object. * * @param <C> * The requested type of the child managed object @@ -262,7 +262,7 @@ /** * Retrieve an optional child managed object. * Retrieves an optional child managed object. * * @param <C> * The requested type of the child managed object @@ -306,7 +306,7 @@ /** * Retrieve a singleton child managed object. * Retrieves a singleton child managed object. * * @param <C> * The requested type of the child managed object @@ -362,7 +362,7 @@ /** * Get the definition associated with this managed object. * Gets the definition associated with this managed object. * * @return Returns the definition associated with this managed * object. @@ -373,7 +373,7 @@ /** * Get the path of this managed object. * Gets the path of this managed object. * * @return Returns the path of this managed object. */ @@ -382,30 +382,31 @@ /** * Get the default values of the specified property. * Gets a mutable copy of the set of default values for the * specified property. * * @param <P> * @param <PD> * The type of the property to be retrieved. * @param pd * The property to be retrieved. * @return Returns the property's default values, or an empty set * if there are no default values defined. * @return Returns the property's default values, or an empty set if * there are no default values defined. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. */ <P> SortedSet<P> getPropertyDefaultValues(PropertyDefinition<P> pd) <PD> SortedSet<PD> getPropertyDefaultValues(PropertyDefinition<PD> pd) throws IllegalArgumentException; /** * Get the effective value of the specified property. * Gets the effective value of the specified property. * <p> * See the class description for more information about how the * effective property value is derived. * * @param <P> * @param <PD> * The type of the property to be retrieved. * @param pd * The property to be retrieved. @@ -416,18 +417,19 @@ * If the property definition is not associated with this * managed object's definition. */ <P> P getPropertyValue(PropertyDefinition<P> pd) <PD> PD getPropertyValue(PropertyDefinition<PD> pd) throws IllegalArgumentException; /** * Get the effective values of the specified property. * Gets a mutable copy of the set of effective values for the * specified property. * <p> * See the class description for more information about how the * effective property values are derived. * * @param <P> * @param <PD> * The type of the property to be retrieved. * @param pd * The property to be retrieved. @@ -437,7 +439,7 @@ * If the property definition is not associated with this * managed object's definition. */ <P> SortedSet<P> getPropertyValues(PropertyDefinition<P> pd) <PD> SortedSet<PD> getPropertyValues(PropertyDefinition<PD> pd) throws IllegalArgumentException; @@ -653,12 +655,12 @@ /** * Set a new pending value for the specified property. * Sets a new pending value for the specified property. * <p> * See the class description for more information regarding pending * values. * * @param <P> * @param <PD> * The type of the property to be modified. * @param pd * The property to be modified. @@ -678,19 +680,19 @@ * If the specified property definition is not associated * with this managed object. */ <P> void setPropertyValue(PropertyDefinition<P> pd, P value) <PD> void setPropertyValue(PropertyDefinition<PD> pd, PD value) throws IllegalPropertyValueException, PropertyIsReadOnlyException, PropertyIsMandatoryException, IllegalArgumentException; /** * Set a new pending values for the specified property. * Sets a new pending values for the specified property. * <p> * See the class description for more information regarding pending * values. * * @param <P> * @param <PD> * The type of the property to be modified. * @param pd * The property to be modified. @@ -714,7 +716,7 @@ * If the specified property definition is not associated * with this managed object. */ <P> void setPropertyValues(PropertyDefinition<P> pd, Collection<P> values) <PD> void setPropertyValues(PropertyDefinition<PD> pd, Collection<PD> values) throws IllegalPropertyValueException, PropertyIsSingleValuedException, PropertyIsReadOnlyException, PropertyIsMandatoryException, IllegalArgumentException; opends/src/server/org/opends/server/admin/client/ManagementContext.java
@@ -34,7 +34,7 @@ /** * Management connection context. * Client management connection context. */ public abstract class ManagementContext { @@ -48,21 +48,9 @@ /** * Get the root configuration managed object associated with this * Gets the root configuration client associated with this * management context. * * @return Returns the root configuration managed object associated * with this management context. */ public abstract ManagedObject<RootCfgClient> getRootConfigurationManagedObject(); /** * Get the root configuration client associated with this management * context. * * @return Returns the root configuration client associated with * this management context. */ @@ -70,4 +58,16 @@ return getRootConfigurationManagedObject().getConfiguration(); } /** * Gets the root configuration managed object associated with this * management context. * * @return Returns the root configuration managed object associated * with this management context. */ public abstract ManagedObject<RootCfgClient> getRootConfigurationManagedObject(); } opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
New file @@ -0,0 +1,595 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.admin.client.ldap; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NoPermissionException; import javax.naming.OperationNotSupportedException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.ldap.LdapName; import org.opends.server.admin.AbstractManagedObjectDefinition; import org.opends.server.admin.Configuration; import org.opends.server.admin.ConfigurationClient; import org.opends.server.admin.DefaultBehaviorException; import org.opends.server.admin.DefinitionDecodingException; import org.opends.server.admin.DefinitionResolver; import org.opends.server.admin.IllegalPropertyValueStringException; import org.opends.server.admin.InstantiableRelationDefinition; import org.opends.server.admin.LDAPProfile; import org.opends.server.admin.ManagedObjectDefinition; import org.opends.server.admin.ManagedObjectNotFoundException; import org.opends.server.admin.ManagedObjectPath; import org.opends.server.admin.OptionalRelationDefinition; import org.opends.server.admin.PropertyDefinition; import org.opends.server.admin.PropertyException; import org.opends.server.admin.PropertyIsMandatoryException; import org.opends.server.admin.PropertyIsSingleValuedException; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.RelationDefinition; import org.opends.server.admin.DefinitionDecodingException.Reason; import org.opends.server.admin.client.AuthorizationException; import org.opends.server.admin.client.CommunicationException; import org.opends.server.admin.client.ManagedObject; import org.opends.server.admin.client.ManagedObjectDecodingException; import org.opends.server.admin.client.OperationRejectedException; import org.opends.server.admin.client.spi.Driver; import org.opends.server.admin.client.spi.PropertySet; /** * The LDAP management context driver implementation. */ final class LDAPDriver extends Driver { // The LDAP connection. private final LDAPConnection connection; // The LDAP profile which should be used to construct LDAP // requests and decode LDAP responses. private final LDAPProfile profile; /** * Creates a new LDAP driver using the specified LDAP connection and * profile. * * @param connection * The LDAP connection. * @param profile * The LDAP profile. */ public LDAPDriver(LDAPConnection connection, LDAPProfile profile) { this.connection = connection; this.profile = profile; } /** * {@inheritDoc} */ @Override public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, String name) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, AuthorizationException, CommunicationException { validateRelationDefinition(parent, rd); if (!entryExists(parent)) { throw new ManagedObjectNotFoundException(); } return removeManagedObject(parent.child(rd, name)); } /** * {@inheritDoc} */ @Override public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, AuthorizationException, CommunicationException { validateRelationDefinition(parent, rd); if (!entryExists(parent)) { throw new ManagedObjectNotFoundException(); } return removeManagedObject(parent.child(rd)); } /** * {@inheritDoc} */ @Override public <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getManagedObject( ManagedObjectPath<C, S> path) throws DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException { if (!entryExists(path)) { throw new ManagedObjectNotFoundException(); } try { // Read the entry associated with the managed object. LdapName dn = LDAPNameBuilder.create(path, profile); AbstractManagedObjectDefinition<C, S> d = path .getManagedObjectDefinition(); ManagedObjectDefinition<? extends C, ? extends S> mod = getEntryDefinition(d, dn); ArrayList<String> attrIds = new ArrayList<String>(); for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { String attrId = profile.getAttributeName(mod, pd); attrIds.add(attrId); } Attributes attributes = connection.readEntry(dn, attrIds); // Build the managed object's properties. List<PropertyException> exceptions = new LinkedList<PropertyException>(); PropertySet newProperties = new PropertySet(); for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { String attrID = profile.getAttributeName(mod, pd); Attribute attribute = attributes.get(attrID); List<String> values = new LinkedList<String>(); if (attribute != null && attribute.size() != 0) { NamingEnumeration<?> ldapValues = attribute.getAll(); while (ldapValues.hasMore()) { Object obj = ldapValues.next(); if (obj != null) { values.add(obj.toString()); } } } try { decodeProperty(newProperties, path, pd, values); } catch (PropertyException e) { exceptions.add(e); } } // If there were no decoding problems then return the object, // otherwise throw an operations exception. ManagedObject<? extends C> mo = createExistingManagedObject(mod, path, newProperties); if (exceptions.isEmpty()) { return mo; } else { throw new ManagedObjectDecodingException(mo, exceptions); } } catch (NameNotFoundException e) { throw new ManagedObjectNotFoundException(); } catch (NoPermissionException e) { throw new AuthorizationException(e); } catch (NamingException e) { throw new CommunicationException(e); } } /** * {@inheritDoc} */ @Override public <PD> SortedSet<PD> getPropertyValues(ManagedObjectPath<?, ?> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, DefinitionDecodingException, AuthorizationException, ManagedObjectNotFoundException, CommunicationException, PropertyException { if (!entryExists(path)) { throw new ManagedObjectNotFoundException(); } try { // Read the entry associated with the managed object. LdapName dn = LDAPNameBuilder.create(path, profile); AbstractManagedObjectDefinition<?, ?> d = path .getManagedObjectDefinition(); ManagedObjectDefinition<?, ?> mod = getEntryDefinition(d, dn); String attrID = profile.getAttributeName(mod, pd); Attributes attributes = connection.readEntry(dn, Collections .singleton(attrID)); Attribute attribute = attributes.get(attrID); SortedSet<PD> values = new TreeSet<PD>(pd); if (attribute == null || attribute.size() == 0) { // Use the property's default values. values.addAll(findDefaultValues(path, pd, false)); } else { // Decode the values. NamingEnumeration<?> ldapValues = attribute.getAll(); while (ldapValues.hasMore()) { Object obj = ldapValues.next(); if (obj != null) { PD value = pd.decodeValue(obj.toString()); values.add(value); } } } // Sanity check the returned values. if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { throw new PropertyIsSingleValuedException(pd); } if (values.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) { throw new PropertyIsMandatoryException(pd); } return values; } catch (NameNotFoundException e) { throw new ManagedObjectNotFoundException(); } catch (NoPermissionException e) { throw new AuthorizationException(e); } catch (NamingException e) { throw new CommunicationException(e); } } /** * {@inheritDoc} */ @Override public <C extends ConfigurationClient, S extends Configuration> boolean hasManagedObject( ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd) throws IllegalArgumentException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException { validateRelationDefinition(parent, rd); if (!entryExists(parent)) { throw new ManagedObjectNotFoundException(); } return entryExists(parent.child(rd)); } /** * {@inheritDoc} */ @Override public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, AbstractManagedObjectDefinition<? extends C, ? extends S> d) throws IllegalArgumentException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException { validateRelationDefinition(parent, rd); if (!entryExists(parent)) { throw new ManagedObjectNotFoundException(); } // Get the search base DN. LdapName dn = LDAPNameBuilder.create(parent, rd, profile); // Retrieve only those entries which are sub-types of the // specified definition. StringBuilder builder = new StringBuilder(); builder.append("(objectclass="); builder.append(profile.getObjectClass(d)); builder.append(')'); String filter = builder.toString(); List<String> children = new ArrayList<String>(); try { for (LdapName child : connection.listEntries(dn, filter)) { children.add(child.getRdn(child.size() - 1).getValue().toString()); } } catch (NameNotFoundException e) { // Ignore this - it means that the base entry does not exist // (which it might not if this managed object has just been // created. } catch (NamingException e) { adaptNamingException(e); } return children.toArray(new String[children.size()]); } /** * Adapts a naming exception to an appropriate admin client * exception. * * @param ne * The naming exception. * @throws CommunicationException * If the naming exception mapped to a communication * exception. * @throws AuthorizationException * If the naming exception mapped to an authorization * exception. */ void adaptNamingException(NamingException ne) throws CommunicationException, AuthorizationException { try { throw ne; } catch (javax.naming.CommunicationException e) { throw new CommunicationException(e); } catch (javax.naming.ServiceUnavailableException e) { throw new CommunicationException(e); } catch (javax.naming.NoPermissionException e) { throw new AuthorizationException(e); } catch (NamingException e) { // Just treat it as a communication problem. throw new CommunicationException(e); } } /** * Determines whether the named LDAP entry exists. * * @param dn * The LDAP entry name. * @return Returns <code>true</code> if the named LDAP entry * exists. * @throws AuthorizationException * If the server refuses to make the determination because * the client does not have the correct privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ boolean entryExists(LdapName dn) throws CommunicationException, AuthorizationException { try { return connection.entryExists(dn); } catch (NamingException e) { adaptNamingException(e); } return false; } /** * Gets the LDAP connection used for interacting with the server. * * @return Returns the LDAP connection used for interacting with the * server. */ LDAPConnection getLDAPConnection() { return connection; } /** * Gets the LDAP profile which should be used to construct LDAP * requests and decode LDAP responses. * * @return Returns the LDAP profile which should be used to * construct LDAP requests and decode LDAP responses. */ LDAPProfile getLDAPProfile() { return profile; } // Create a managed object which already exists on the server. private <M extends ConfigurationClient, N extends Configuration> ManagedObject<M> createExistingManagedObject( ManagedObjectDefinition<M, N> d, ManagedObjectPath<? super M, ? super N> p, PropertySet properties) { RelationDefinition<?, ?> rd = p.getRelationDefinition(); PropertyDefinition<?> pd = null; if (rd instanceof InstantiableRelationDefinition) { InstantiableRelationDefinition<?, ?> ird = (InstantiableRelationDefinition<?, ?>) rd; pd = ird.getNamingPropertyDefinition(); } return new LDAPManagedObject<M>(this, d, p.asSubType(d), properties, true, pd); } // Create a property using the provided string values. private <PD> void decodeProperty(PropertySet newProperties, ManagedObjectPath<?, ?> p, PropertyDefinition<PD> pd, List<String> values) throws PropertyException { PropertyException exception = null; // Get the property's active values. Collection<PD> activeValues = new ArrayList<PD>(values.size()); for (String value : values) { try { activeValues.add(pd.decodeValue(value)); } catch (IllegalPropertyValueStringException e) { exception = e; } } if (activeValues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { // This exception takes precedence over previous exceptions. exception = new PropertyIsSingleValuedException(pd); PD value = activeValues.iterator().next(); activeValues.clear(); activeValues.add(value); } if (activeValues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) { // The active values maybe empty because of a previous // exception. if (exception == null) { exception = new PropertyIsMandatoryException(pd); } } // Get the property's default values. Collection<PD> defaultValues; try { defaultValues = findDefaultValues(p, pd, false); } catch (DefaultBehaviorException e) { defaultValues = Collections.emptySet(); exception = e; } newProperties.addProperty(pd, defaultValues, activeValues); if (exception != null) { throw exception; } } // Determines whether the LDAP entry associated with the managed // object path exists. private boolean entryExists(ManagedObjectPath<?, ?> path) throws CommunicationException, AuthorizationException { if (path.isEmpty()) { return true; } LdapName dn = LDAPNameBuilder.create(path, profile); return entryExists(dn); } // Determine the type of managed object associated with the named // entry. private <C extends ConfigurationClient, S extends Configuration> ManagedObjectDefinition<? extends C, ? extends S> getEntryDefinition( AbstractManagedObjectDefinition<C, S> d, LdapName dn) throws NamingException, DefinitionDecodingException { Attributes attributes = connection.readEntry(dn, Collections .singleton("objectclass")); Attribute oc = attributes.get("objectclass"); if (oc == null) { // No object classes. throw new DefinitionDecodingException(Reason.NO_TYPE_INFORMATION); } final Set<String> objectClasses = new HashSet<String>(); NamingEnumeration<?> values = oc.getAll(); while (values.hasMore()) { Object value = values.next(); if (value != null) { objectClasses.add(value.toString().toLowerCase().trim()); } } if (objectClasses.isEmpty()) { // No object classes. throw new DefinitionDecodingException(Reason.NO_TYPE_INFORMATION); } // Resolve the appropriate sub-type based on the object classes. DefinitionResolver resolver = new DefinitionResolver() { public boolean matches(AbstractManagedObjectDefinition<?, ?> d) { String objectClass = profile.getObjectClass(d); return objectClasses.contains(objectClass); } }; return d.resolveManagedObjectDefinition(resolver); } // Remove the named managed object. private boolean removeManagedObject(ManagedObjectPath<?, ?> path) throws CommunicationException, AuthorizationException, OperationRejectedException, ManagedObjectNotFoundException { if (!entryExists(path)) { return false; } // Delete the entry and any subordinate entries. LdapName dn = LDAPNameBuilder.create(path, profile); try { connection.deleteSubtree(dn); } catch (OperationNotSupportedException e) { // Unwilling to perform. throw new OperationRejectedException(e); } catch (NamingException e) { adaptNamingException(e); } return true; } // Validate that a relation definition belongs to this managed // object. private void validateRelationDefinition(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> rd) throws IllegalArgumentException { AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition(); RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + d.getName()); } } } opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -29,18 +29,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.SortedSet; import javax.naming.NameAlreadyBoundException; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NoPermissionException; import javax.naming.OperationNotSupportedException; @@ -51,46 +40,24 @@ import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider; import org.opends.server.admin.AbstractManagedObjectDefinition; import org.opends.server.admin.AliasDefaultBehaviorProvider; import org.opends.server.admin.Configuration; import org.opends.server.admin.ConfigurationClient; import org.opends.server.admin.DefaultBehaviorException; import org.opends.server.admin.DefaultBehaviorProviderVisitor; import org.opends.server.admin.DefinedDefaultBehaviorProvider; import org.opends.server.admin.DefinitionDecodingException; import org.opends.server.admin.DefinitionResolver; import org.opends.server.admin.IllegalPropertyValueException; import org.opends.server.admin.IllegalPropertyValueStringException; import org.opends.server.admin.InstantiableRelationDefinition; import org.opends.server.admin.ManagedObjectAlreadyExistsException; import org.opends.server.admin.ManagedObjectDefinition; import org.opends.server.admin.ManagedObjectNotFoundException; import org.opends.server.admin.ManagedObjectPath; import org.opends.server.admin.OptionalRelationDefinition; import org.opends.server.admin.PropertyDefinition; import org.opends.server.admin.PropertyException; import org.opends.server.admin.PropertyIsMandatoryException; import org.opends.server.admin.PropertyIsReadOnlyException; import org.opends.server.admin.PropertyIsSingleValuedException; import org.opends.server.admin.PropertyNotFoundException; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.RelationDefinition; import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider; import org.opends.server.admin.SingletonRelationDefinition; import org.opends.server.admin.UndefinedDefaultBehaviorProvider; import org.opends.server.admin.DefinitionDecodingException.Reason; import org.opends.server.admin.client.AuthorizationException; import org.opends.server.admin.client.CommunicationException; import org.opends.server.admin.client.ConcurrentModificationException; import org.opends.server.admin.client.IllegalManagedObjectNameException; import org.opends.server.admin.client.ManagedObject; import org.opends.server.admin.client.ManagedObjectDecodingException; import org.opends.server.admin.client.MissingMandatoryPropertiesException; import org.opends.server.admin.client.OperationRejectedException; import org.opends.server.admin.client.Property; import org.opends.server.admin.client.PropertySet; import org.opends.server.admin.client.spi.AbstractManagedObject; import org.opends.server.admin.client.spi.Driver; import org.opends.server.admin.client.spi.Property; import org.opends.server.admin.client.spi.PropertySet; import org.opends.server.admin.std.client.RootCfgClient; import org.opends.server.admin.std.meta.RootCfgDefn; @@ -103,384 +70,55 @@ * The type of client configuration represented by the client * managed object. */ final class LDAPManagedObject<T extends ConfigurationClient> implements ManagedObject<T> { final class LDAPManagedObject<T extends ConfigurationClient> extends AbstractManagedObject<T> { /** * A default behavior visitor used for retrieving the default values * of a property. * Constructs a root LDAP managed object associated with the * provided LDAP driver. * * @param <T> * The type of the property. */ private static class DefaultValueFinder<T> implements DefaultBehaviorProviderVisitor<T, Collection<T>, Void> { /** * Get the default values for the specified property. * * @param <T> * The type of the property. * @param context * The LDAP management context. * @param p * The managed object path of the current managed object. * @param pd * The property definition. * @param isCreate * Indicates whether the managed object has been created * yet. * @return Returns the default values for the specified property. * @throws DefaultBehaviorException * If the default values could not be retrieved or * decoded properly. */ public static <T> Collection<T> getDefaultValues( LDAPManagementContext context, ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd, boolean isCreate) throws DefaultBehaviorException { DefaultValueFinder<T> v = new DefaultValueFinder<T>(context, p, isCreate); return v.find(p, pd); } // The LDAP management context. private final LDAPManagementContext context; // Any exception that occurred whilst retrieving inherited default // values. private DefaultBehaviorException exception = null; // Indicates whether the managed object has been created yet. private final boolean isCreate; // The path of the managed object containing the first property. private final ManagedObjectPath<?, ?> firstPath; // The path of the managed object containing the next property. private ManagedObjectPath<?, ?> nextPath = null; // The next property whose default values were required. private PropertyDefinition<T> nextProperty = null; // Private constructor. private DefaultValueFinder(LDAPManagementContext context, ManagedObjectPath<?, ?> p, boolean isCreate) { this.context = context; this.firstPath = p; this.isCreate = isCreate; } /** * {@inheritDoc} */ public Collection<T> visitAbsoluteInherited( AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(), d .getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } /** * {@inheritDoc} */ public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d, Void p) { Collection<String> stringValues = d.getDefaultValues(); List<T> values = new ArrayList<T>(stringValues.size()); for (String stringValue : stringValues) { try { values.add(nextProperty.decodeValue(stringValue)); } catch (IllegalPropertyValueStringException e) { exception = new DefaultBehaviorException(nextProperty, e); break; } } return values; } /** * {@inheritDoc} */ public Collection<T> visitRelativeInherited( RelativeInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(nextPath), d .getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } // Find the default values for the next path/property. private Collection<T> find(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd) throws DefaultBehaviorException { this.nextPath = p; this.nextProperty = pd; Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept( this, null); if (exception != null) { throw exception; } if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { throw new DefaultBehaviorException(pd, new PropertyIsSingleValuedException(pd)); } return values; } // Get an inherited property value. @SuppressWarnings("unchecked") private Collection<T> getInheritedProperty(ManagedObjectPath target, AbstractManagedObjectDefinition<?, ?> d, String propertyName) throws DefaultBehaviorException { // First check that the requested type of managed object // corresponds to the path. AbstractManagedObjectDefinition<?, ?> supr = target .getManagedObjectDefinition(); if (!supr.isParentOf(d)) { throw new DefaultBehaviorException(nextProperty, new DefinitionDecodingException(Reason.WRONG_TYPE_INFORMATION)); } // Save the current property in case of recursion. PropertyDefinition<T> pd1 = nextProperty; try { // If the path relates to the current managed object and the // managed object is in the process of being created it won't // exist, so we should just use the default values of the // referenced property. if (isCreate && firstPath.equals(target)) { PropertyDefinition<T> pd2; try { // FIXME: we use the definition taken from the default // behavior here when we should really use the exact // definition of the component being created. PropertyDefinition<?> pdTmp = d.getPropertyDefinition(propertyName); pd2 = pd1.getClass().cast(pdTmp); } catch (IllegalArgumentException e) { throw new PropertyNotFoundException(propertyName); } catch (ClassCastException e) { // FIXME: would be nice to throw a better exception here. throw new PropertyNotFoundException(propertyName); } // Recursively retrieve this property's default values. Collection<T> tmp = find(target, pd2); Collection<T> values = new ArrayList<T>(tmp.size()); for (T value : tmp) { pd1.validateValue(value); values.add(value); } return values; } else { // Get the actual managed object definition. LdapName dn = LDAPNameBuilder .create(target, context.getLDAPProfile()); ManagedObjectDefinition<?, ?> mod = getEntryDefinition(context, d, dn); PropertyDefinition<T> pd2; try { PropertyDefinition<?> pdTmp = mod .getPropertyDefinition(propertyName); pd2 = pd1.getClass().cast(pdTmp); } catch (IllegalArgumentException e) { throw new PropertyNotFoundException(propertyName); } catch (ClassCastException e) { // FIXME: would be nice to throw a better exception here. throw new PropertyNotFoundException(propertyName); } String attrID = context.getLDAPProfile().getAttributeName(mod, pd2); Attributes attributes = context.getLDAPConnection().readEntry(dn, Collections.singleton(attrID)); Attribute attr = attributes.get(attrID); if (attr == null || attr.size() == 0) { // Recursively retrieve this property's default values. Collection<T> tmp = find(target, pd2); Collection<T> values = new ArrayList<T>(tmp.size()); for (T value : tmp) { pd1.validateValue(value); values.add(value); } return values; } else { Collection<T> values = new LinkedList<T>(); NamingEnumeration<?> ne = attr.getAll(); while (ne.hasMore()) { Object value = ne.next(); if (value != null) { values.add(pd1.decodeValue(value.toString())); } } return values; } } } catch (DefaultBehaviorException e) { // Wrap any errors due to recursion. throw new DefaultBehaviorException(pd1, e); } catch (DefinitionDecodingException e) { throw new DefaultBehaviorException(pd1, e); } catch (PropertyNotFoundException e) { throw new DefaultBehaviorException(pd1, e); } catch (IllegalPropertyValueException e) { throw new DefaultBehaviorException(pd1, e); } catch (IllegalPropertyValueStringException e) { throw new DefaultBehaviorException(pd1, e); } catch (NameNotFoundException e) { throw new DefaultBehaviorException(pd1, new ManagedObjectNotFoundException()); } catch (NoPermissionException e) { throw new DefaultBehaviorException(pd1, new AuthorizationException(e)); } catch (NamingException e) { throw new DefaultBehaviorException(pd1, new CommunicationException(e)); } } }; /** * Construct a root LDAP managed object associated with the provided * LDAP context. * * @param context * The LDAP management context. * @param driver * The LDAP management driver. * @return Returns a root LDAP managed object associated with the * provided LDAP context. * provided LDAP driver. */ static ManagedObject<RootCfgClient> getRootManagedObject( LDAPManagementContext context) { return new LDAPManagedObject<RootCfgClient>(context, RootCfgDefn LDAPDriver driver) { return new LDAPManagedObject<RootCfgClient>(driver, RootCfgDefn .getInstance(), ManagedObjectPath.emptyPath(), new PropertySet(), true, null); } // Determine the type of managed object associated with the named // entry. private static <M extends ConfigurationClient, N extends Configuration> ManagedObjectDefinition<? extends M, ? extends N> getEntryDefinition( final LDAPManagementContext context, AbstractManagedObjectDefinition<M, N> d, LdapName dn) throws NamingException, DefinitionDecodingException { Attributes attributes = context.getLDAPConnection().readEntry(dn, Collections.singleton("objectclass")); Attribute oc = attributes.get("objectclass"); if (oc == null) { // No object classes. throw new DefinitionDecodingException(Reason.NO_TYPE_INFORMATION); } final Set<String> objectClasses = new HashSet<String>(); NamingEnumeration<?> values = oc.getAll(); while (values.hasMore()) { Object value = values.next(); if (value != null) { objectClasses.add(value.toString().toLowerCase().trim()); } } if (objectClasses.isEmpty()) { // No object classes. throw new DefinitionDecodingException(Reason.NO_TYPE_INFORMATION); } // Resolve the appropriate sub-type based on the object classes. DefinitionResolver resolver = new DefinitionResolver() { public boolean matches(AbstractManagedObjectDefinition<?, ?> d) { String objectClass = context.getLDAPProfile().getObjectClass(d); return objectClasses.contains(objectClass); } }; return d.resolveManagedObjectDefinition(resolver); } // The LDAP management context used for the ldap connection. private final LDAPManagementContext context; // The managed object definition associated with this managed // object. private final ManagedObjectDefinition<T, ? extends Configuration> definition; // Indicates whether or not this managed object exists on the server // (false means the managed object is new and has not been // committed). private boolean existsOnServer; // Optional naming property definition. private final PropertyDefinition<?> namingPropertyDefinition; // The path associated with this managed object. private ManagedObjectPath<T, ? extends Configuration> path; // The managed object's properties. private final PropertySet properties; // The LDAP management driver associated with this managed object. private final LDAPDriver driver; // Create an new LDAP managed object with the provided JNDI context. private LDAPManagedObject(LDAPManagementContext context, /** * Creates a new LDAP managed object instance. * * @param driver * The underlying LDAP management driver. * @param d * The managed object's definition. * @param path * The managed object's path. * @param properties * The managed object's properties. * @param existsOnServer * Indicates whether or not the managed object already * exists. * @param namingPropertyDefinition * The managed object's naming property definition if there * is one. */ LDAPManagedObject(LDAPDriver driver, ManagedObjectDefinition<T, ? extends Configuration> d, ManagedObjectPath<T, ? extends Configuration> path, PropertySet properties, boolean existsOnServer, PropertyDefinition<?> namingPropertyDefinition) { this.definition = d; this.context = context; this.path = path; this.properties = properties; this.existsOnServer = existsOnServer; this.namingPropertyDefinition = namingPropertyDefinition; super(d, path, properties, existsOnServer, namingPropertyDefinition); this.driver = driver; } @@ -488,411 +126,16 @@ /** * {@inheritDoc} */ public void commit() throws MissingMandatoryPropertiesException, ConcurrentModificationException, OperationRejectedException, AuthorizationException, CommunicationException, ManagedObjectAlreadyExistsException { // First make sure all mandatory properties are defined. List<PropertyIsMandatoryException> exceptions = new LinkedList<PropertyIsMandatoryException>(); for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { Property<?> p = properties.getProperty(pd); if (pd.hasOption(PropertyOption.MANDATORY) && p.getEffectiveValues().isEmpty()) { exceptions.add(new PropertyIsMandatoryException(pd)); } } if (!exceptions.isEmpty()) { throw new MissingMandatoryPropertiesException(exceptions); } // Commit the managed object. if (existsOnServer) { commitExistingManagedObject(); } else { commitNewManagedObject(); } } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration, CC extends C> ManagedObject<CC> createChild(InstantiableRelationDefinition<C, S> r, ManagedObjectDefinition<CC, ? extends S> d, String name, Collection<DefaultBehaviorException> exceptions) throws IllegalManagedObjectNameException, IllegalArgumentException { validateRelationDefinition(r); // Empty names are not allowed. if (name.trim().length() == 0) { throw new IllegalManagedObjectNameException(name); } // If the relation uses a naming property definition then it must // be a valid value. PropertyDefinition<?> pd = r.getNamingPropertyDefinition(); if (pd != null) { try { pd.decodeValue(name); } catch (IllegalPropertyValueStringException e) { throw new IllegalManagedObjectNameException(name, pd); } } ManagedObjectPath<CC, ? extends S> childPath = path.child(r, d, name); return createNewManagedObject(d, childPath, pd, name, exceptions); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration, CC extends C> ManagedObject<CC> createChild(OptionalRelationDefinition<C, S> r, ManagedObjectDefinition<CC, ? extends S> d, Collection<DefaultBehaviorException> exceptions) throws IllegalArgumentException { validateRelationDefinition(r); ManagedObjectPath<CC, ? extends S> childPath = path.child(r, d); return createNewManagedObject(d, childPath, null, null, exceptions); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild(InstantiableRelationDefinition<C, S> r, String name) throws IllegalArgumentException, DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); return readManagedObject(r.getChildDefinition(), path.child(r, name)); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild(OptionalRelationDefinition<C, S> r) throws IllegalArgumentException, DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); return readManagedObject(r.getChildDefinition(), path.child(r)); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( SingletonRelationDefinition<C, S> r) throws IllegalArgumentException, DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); return readManagedObject(r.getChildDefinition(), path.child(r)); } /** * {@inheritDoc} */ public T getConfiguration() { return definition.createClientConfiguration(this); } /** * {@inheritDoc} */ public ManagedObjectDefinition<T, ? extends Configuration> getManagedObjectDefinition() { return definition; } /** * {@inheritDoc} */ public ManagedObjectPath<T, ? extends Configuration> getManagedObjectPath() { return path; } /** * {@inheritDoc} */ public <P> SortedSet<P> getPropertyDefaultValues(PropertyDefinition<P> pd) throws IllegalArgumentException { Property<P> p = properties.getProperty(pd); return p.getDefaultValues(); } /** * {@inheritDoc} */ public <P> P getPropertyValue(PropertyDefinition<P> pd) throws IllegalArgumentException { return properties.getPropertyValue(pd); } /** * {@inheritDoc} */ public <P> SortedSet<P> getPropertyValues(PropertyDefinition<P> pd) throws IllegalArgumentException { return properties.getPropertyValues(pd); } /** * {@inheritDoc} */ public boolean isPropertyPresent(PropertyDefinition<?> pd) throws IllegalArgumentException { Property<?> p = properties.getProperty(pd); return !p.isEmpty(); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> boolean hasChild(OptionalRelationDefinition<C, S> r) throws IllegalArgumentException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); ManagedObjectPath<C, S> p = path.child(r); LdapName dn = LDAPNameBuilder.create(p, context.getLDAPProfile()); return entryExists(dn); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> String[] listChildren(InstantiableRelationDefinition<C, S> r) throws IllegalArgumentException, ConcurrentModificationException, AuthorizationException, CommunicationException { return listChildren(r, r.getChildDefinition()); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> String[] listChildren(InstantiableRelationDefinition<C, S> r, AbstractManagedObjectDefinition<? extends C, ? extends S> d) throws IllegalArgumentException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); // Get the search base DN. LdapName dn = LDAPNameBuilder.create(path, r, context.getLDAPProfile()); // Retrieve only those entries which are sub-types of the // specified definition. StringBuilder builder = new StringBuilder(); builder.append("(objectclass="); builder.append(context.getLDAPProfile().getObjectClass(d)); builder.append(')'); String filter = builder.toString(); List<String> children = new ArrayList<String>(); try { for (LdapName child : context.getLDAPConnection().listEntries(dn, filter)) { children.add(child.getRdn(child.size() - 1).getValue().toString()); } } catch (NameNotFoundException e) { // Ignore this - it means that the base entry does not exist // (which it might not if this managed object has just been // created. } catch (NamingException e) { adaptNamingException(e); } return children.toArray(new String[children.size()]); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> void removeChild(InstantiableRelationDefinition<C, S> r, String name) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); ManagedObjectPath<C, S> p = path.child(r, name); removeManagedObject(p); } /** * {@inheritDoc} */ public <C extends ConfigurationClient, S extends Configuration> void removeChild(OptionalRelationDefinition<C, S> r) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); ManagedObjectPath<C, S> p = path.child(r); removeManagedObject(p); } /** * {@inheritDoc} */ public <P> void setPropertyValue(PropertyDefinition<P> pd, P value) throws IllegalPropertyValueException, PropertyIsReadOnlyException, PropertyIsMandatoryException, IllegalArgumentException { if (value == null) { setPropertyValues(pd, Collections.<P> emptySet()); } else { setPropertyValues(pd, Collections.singleton(value)); } } /** * {@inheritDoc} */ public <P> void setPropertyValues(PropertyDefinition<P> pd, Collection<P> values) throws IllegalPropertyValueException, PropertyIsSingleValuedException, PropertyIsReadOnlyException, PropertyIsMandatoryException, IllegalArgumentException { if (pd.hasOption(PropertyOption.MONITORING)) { throw new PropertyIsReadOnlyException(pd); } if (existsOnServer && pd.hasOption(PropertyOption.READ_ONLY)) { throw new PropertyIsReadOnlyException(pd); } properties.setPropertyValues(pd, values); // If this is a naming property then update the name. if (pd.equals(namingPropertyDefinition)) { // The property must be single-valued and mandatory. String newName = pd.encodeValue(values.iterator().next()); path = path.rename(newName); } } // Adapts a naming exception to an appropriate admin client // exception. private void adaptNamingException(NamingException ne) throws CommunicationException, AuthorizationException { try { throw ne; } catch (javax.naming.CommunicationException e) { throw new CommunicationException(e); } catch (javax.naming.ServiceUnavailableException e) { throw new CommunicationException(e); } catch (javax.naming.NoPermissionException e) { throw new AuthorizationException(e); } catch (NamingException e) { // Just treat it as a communication problem. throw new CommunicationException(e); } } // Commit modifications made to this managed object. private void commitExistingManagedObject() throws ConcurrentModificationException, OperationRejectedException, AuthorizationException, CommunicationException { // Build the list of modified attributes. Attributes mods = new BasicAttributes(); for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { Property<?> p = properties.getProperty(pd); if (p.isModified()) { String attrID = context.getLDAPProfile().getAttributeName(definition, pd); Attribute attribute = new BasicAttribute(attrID); encodeProperty(attribute, pd, properties); mods.put(attribute); } } // Perform the LDAP modification if something has changed. if (mods.size() > 0) { try { LdapName dn = LDAPNameBuilder.create(path, context.getLDAPProfile()); context.getLDAPConnection().modifyEntry(dn, mods); } catch (NoPermissionException e) { throw new AuthorizationException(e); } catch (OperationNotSupportedException e) { // Unwilling to perform. throw new OperationRejectedException(e); } catch (NamingException e) { // Just treat it as a communication problem. throw new CommunicationException(e); } } // The changes were committed successfully so update this managed // object's state. properties.commit(); } // Commit this new managed object. private void commitNewManagedObject() throws AuthorizationException, @Override protected void addNewManagedObject() throws AuthorizationException, CommunicationException, OperationRejectedException, ConcurrentModificationException, ManagedObjectAlreadyExistsException { // First make sure that the parent managed object still exists. ManagedObjectPath<?, ?> path = getManagedObjectPath(); ManagedObjectPath<?, ?> parent = path.parent(); if (!parent.isEmpty()) { LdapName dn = LDAPNameBuilder.create(parent, context.getLDAPProfile()); if (!entryExists(dn)) { LdapName dn = LDAPNameBuilder.create(parent, driver.getLDAPProfile()); if (!driver.entryExists(dn)) { throw new ConcurrentModificationException(); } } @@ -908,14 +151,14 @@ // comprise of more than one RDN arc (this will probably never // be required anyway). LdapName dn = LDAPNameBuilder .create(parent, ir, context.getLDAPProfile()); if (!entryExists(dn)) { .create(parent, ir, driver.getLDAPProfile()); if (!driver.entryExists(dn)) { // We need to create the entry. Attributes attributes = new BasicAttributes(); // Create the branch's object class attribute. Attribute oc = new BasicAttribute("objectClass"); for (String objectClass : context.getLDAPProfile() for (String objectClass : driver.getLDAPProfile() .getInstantiableRelationObjectClasses(ir)) { oc.add(objectClass); } @@ -927,39 +170,41 @@ // Create the entry. try { context.getLDAPConnection().createEntry(dn, attributes); driver.getLDAPConnection().createEntry(dn, attributes); } catch (OperationNotSupportedException e) { // Unwilling to perform. throw new OperationRejectedException(e); } catch (NamingException e) { adaptNamingException(e); driver.adaptNamingException(e); } } } // Now add the entry representing this new managed object. LdapName dn = LDAPNameBuilder.create(path, context.getLDAPProfile()); LdapName dn = LDAPNameBuilder.create(path, driver.getLDAPProfile()); Attributes attributes = new BasicAttributes(true); // Create the object class attribute. Attribute oc = new BasicAttribute("objectclass"); for (String objectClass : context.getLDAPProfile().getObjectClasses( ManagedObjectDefinition<?, ?> definition = getManagedObjectDefinition(); for (String objectClass : driver.getLDAPProfile().getObjectClasses( definition)) { oc.add(objectClass); } attributes.put(oc); // Create the naming attribute if there is not naming property. if (namingPropertyDefinition == null) { PropertyDefinition<?> npd = getNamingPropertyDefinition(); if (npd == null) { Rdn rdn = dn.getRdn(dn.size() - 1); attributes.put(rdn.getType(), rdn.getValue().toString()); } // Create the remaining attributes. for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { String attrID = context.getLDAPProfile().getAttributeName(definition, pd); String attrID = driver.getLDAPProfile().getAttributeName(definition, pd); Attribute attribute = new BasicAttribute(attrID); encodeProperty(attribute, pd, properties); encodeProperty(attribute, pd); if (attribute.size() != 0) { attributes.put(attribute); } @@ -967,287 +212,100 @@ try { // Create the entry. context.getLDAPConnection().createEntry(dn, attributes); driver.getLDAPConnection().createEntry(dn, attributes); } catch (NameAlreadyBoundException e) { throw new ManagedObjectAlreadyExistsException(); } catch (OperationNotSupportedException e) { // Unwilling to perform. throw new OperationRejectedException(e); } catch (NamingException e) { adaptNamingException(e); driver.adaptNamingException(e); } // The entry was created successfully so update this managed // object's state. properties.commit(); existsOnServer = true; } // Create a managed object which already exists on the server. private <M extends ConfigurationClient, N extends Configuration> ManagedObject<M> createExistingManagedObject( ManagedObjectDefinition<M, N> d, ManagedObjectPath<? super M, ? super N> p, PropertySet properties) { RelationDefinition<?, ?> rd = p.getRelationDefinition(); PropertyDefinition<?> pd = null; if (rd instanceof InstantiableRelationDefinition) { InstantiableRelationDefinition<?, ?> ird = (InstantiableRelationDefinition<?, ?>) rd; pd = ird.getNamingPropertyDefinition(); } return new LDAPManagedObject<M>(context, d, p.asSubType(d), properties, true, pd); /** * {@inheritDoc} */ @Override protected Driver getDriver() { return driver; } // Creates a new managed object with no active values, just default // values. private <M extends ConfigurationClient, P> ManagedObject<M> createNewManagedObject( ManagedObjectDefinition<M, ?> d, ManagedObjectPath<M, ?> p, PropertyDefinition<P> namingPropertyDefinition, String name, Collection<DefaultBehaviorException> exceptions) { PropertySet childProperties = new PropertySet(); for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) { /** * {@inheritDoc} */ @Override protected void modifyExistingManagedObject() throws ConcurrentModificationException, OperationRejectedException, AuthorizationException, CommunicationException { // Build the list of modified attributes. Attributes mods = new BasicAttributes(); ManagedObjectDefinition<?, ?> definition = getManagedObjectDefinition(); for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { Property<?> p = getProperty(pd); if (p.isModified()) { String attrID = driver.getLDAPProfile().getAttributeName(definition, pd); Attribute attribute = new BasicAttribute(attrID); encodeProperty(attribute, pd); mods.put(attribute); } } // Perform the LDAP modification if something has changed. if (mods.size() > 0) { try { createProperty(childProperties, p, pd); } catch (DefaultBehaviorException e) { // Add the exception if requested. if (exceptions != null) { exceptions.add(e); ManagedObjectPath<?, ?> path = getManagedObjectPath(); LdapName dn = LDAPNameBuilder.create(path, driver.getLDAPProfile()); driver.getLDAPConnection().modifyEntry(dn, mods); } catch (NoPermissionException e) { throw new AuthorizationException(e); } catch (OperationNotSupportedException e) { // Unwilling to perform. throw new OperationRejectedException(e); } catch (NamingException e) { // Just treat it as a communication problem. throw new CommunicationException(e); } } } // Set the naming property if there is one. if (namingPropertyDefinition != null) { P value = namingPropertyDefinition.decodeValue(name); childProperties.setPropertyValue(namingPropertyDefinition, value); } return new LDAPManagedObject<M>(context, d, p, childProperties, false, namingPropertyDefinition); } // Create an empty property. private <P> void createProperty(PropertySet properties, ManagedObjectPath<?, ?> p, PropertyDefinition<P> pd) throws DefaultBehaviorException { try { Collection<P> defaultValues = DefaultValueFinder.getDefaultValues( context, p, pd, true); properties.addProperty(pd, defaultValues, Collections.<P> emptySet()); } catch (DefaultBehaviorException e) { // Make sure that we have still created the property. properties.addProperty(pd, Collections.<P> emptySet(), Collections .<P> emptySet()); throw e; } } // Create a property using the provided string values. private <P> void decodeProperty(PropertySet newProperties, ManagedObjectPath<?, ?> p, PropertyDefinition<P> pd, List<String> values) throws PropertyException { PropertyException exception = null; // Get the property's active values. Collection<P> activeValues = new ArrayList<P>(values.size()); for (String value : values) { try { activeValues.add(pd.decodeValue(value)); } catch (IllegalPropertyValueStringException e) { exception = e; } } if (activeValues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { // This exception takes precedence over previous exceptions. exception = new PropertyIsSingleValuedException(pd); P value = activeValues.iterator().next(); activeValues.clear(); activeValues.add(value); } if (activeValues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) { // The active values maybe empty because of a previous exception. if (exception == null) { exception = new PropertyIsMandatoryException(pd); } } // Get the property's default values. Collection<P> defaultValues; try { defaultValues = DefaultValueFinder.getDefaultValues(context, p, pd, false); } catch (DefaultBehaviorException e) { defaultValues = Collections.emptySet(); exception = e; } newProperties.addProperty(pd, defaultValues, activeValues); if (exception != null) { throw exception; } /** * {@inheritDoc} */ @Override protected <M extends ConfigurationClient> ManagedObject<M> newInstance( ManagedObjectDefinition<M, ?> d, ManagedObjectPath<M, ?> path, PropertySet properties, boolean existsOnServer, PropertyDefinition<?> namingPropertyDefinition) { return new LDAPManagedObject<M>(driver, d, path, properties, existsOnServer, namingPropertyDefinition); } // Encode a property into LDAP string values. private <P> void encodeProperty(Attribute attribute, PropertyDefinition<P> pd, PropertySet properties) { Property<P> p = properties.getProperty(pd); private <PD> void encodeProperty(Attribute attribute, PropertyDefinition<PD> pd) { Property<PD> p = getProperty(pd); if (pd.hasOption(PropertyOption.MANDATORY)) { // For mandatory properties we fall-back to the default values // if defined which can sometimes be the case e.g when a // mandatory property is overridden. for (P value : p.getEffectiveValues()) { for (PD value : p.getEffectiveValues()) { attribute.add(pd.encodeValue(value)); } } else { for (P value : p.getPendingValues()) { for (PD value : p.getPendingValues()) { attribute.add(pd.encodeValue(value)); } } } // Makes sure that the entry corresponding to this managed object // exists. private void ensureThisManagedObjectExists() throws ConcurrentModificationException, CommunicationException, AuthorizationException { if (!path.isEmpty()) { LdapName dn = LDAPNameBuilder.create(path, context.getLDAPProfile()); if (!entryExists(dn)) { throw new ConcurrentModificationException(); } } } // Determine whether the named entry exists or not. private boolean entryExists(LdapName dn) throws CommunicationException, AuthorizationException { try { return context.getLDAPConnection().entryExists(dn); } catch (NamingException e) { adaptNamingException(e); } return false; } // Read the entry identified by the path and which is a sub-type of // the specified definition. private <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> readManagedObject( AbstractManagedObjectDefinition<C, S> d, ManagedObjectPath<C, S> p) throws DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException { try { // Read the entry associated with the managed object. LdapName dn = LDAPNameBuilder.create(p, context.getLDAPProfile()); ManagedObjectDefinition<? extends C, ? extends S> mod = getEntryDefinition(context, d, dn); ArrayList<String> attrIds = new ArrayList<String>(); for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { String attrId = context.getLDAPProfile().getAttributeName(mod, pd); attrIds.add(attrId); } Attributes attributes = context.getLDAPConnection() .readEntry(dn, attrIds); // Build the managed object's properties. List<PropertyException> exceptions = new LinkedList<PropertyException>(); PropertySet newProperties = new PropertySet(); for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) { String attrID = context.getLDAPProfile().getAttributeName(mod, pd); Attribute attribute = attributes.get(attrID); List<String> values = new LinkedList<String>(); if (attribute != null && attribute.size() != 0) { NamingEnumeration<?> ldapValues = attribute.getAll(); while (ldapValues.hasMore()) { Object obj = ldapValues.next(); if (obj != null) { values.add(obj.toString()); } } } try { decodeProperty(newProperties, p, pd, values); } catch (PropertyException e) { exceptions.add(e); } } // If there were no decoding problems then return the object, // otherwise throw an operations exception. ManagedObject<? extends C> mo = createExistingManagedObject(mod, p, newProperties); if (exceptions.isEmpty()) { return mo; } else { throw new ManagedObjectDecodingException(mo, exceptions); } } catch (NameNotFoundException e) { throw new ManagedObjectNotFoundException(); } catch (NoPermissionException e) { throw new AuthorizationException(e); } catch (NamingException e) { throw new CommunicationException(e); } } // Remove the named managed object. private void removeManagedObject(ManagedObjectPath<?, ?> p) throws CommunicationException, AuthorizationException, OperationRejectedException, ManagedObjectNotFoundException { LdapName dn = LDAPNameBuilder.create(p, context.getLDAPProfile()); if (entryExists(dn)) { // Delete the entry and any subordinate entries. try { context.getLDAPConnection().deleteSubtree(dn); } catch (OperationNotSupportedException e) { // Unwilling to perform. throw new OperationRejectedException(e); } catch (NamingException e) { adaptNamingException(e); } } else { throw new ManagedObjectNotFoundException(); } } // Validate that a relation definition belongs to this managed // object. private void validateRelationDefinition(RelationDefinition<?, ?> rd) throws IllegalArgumentException { ManagedObjectDefinition<T, ?> d = getManagedObjectDefinition(); RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + d.getName()); } } } opends/src/server/org/opends/server/admin/client/ldap/LDAPManagementContext.java
@@ -55,20 +55,15 @@ return new LDAPManagementContext(connection, LDAPProfile.getInstance()); } // The LDAP connection. private final LDAPConnection connection; // The LDAP profile which should be used to construct LDAP requests // and decode LDAP responses. private final LDAPProfile profile; // The LDAP management context driver. private final LDAPDriver driver; // Private constructor. private LDAPManagementContext(LDAPConnection connection, LDAPProfile profile) { this.connection = connection; this.profile = profile; this.driver = new LDAPDriver(connection, profile); } @@ -77,31 +72,6 @@ * {@inheritDoc} */ public ManagedObject<RootCfgClient> getRootConfigurationManagedObject() { return LDAPManagedObject.getRootManagedObject(this); } /** * Gets the LDAP connection used for interacting with the server. * * @return Returns the LDAP connection used for interacting with the * server. */ LDAPConnection getLDAPConnection() { return connection; } /** * Gets the LDAP profile which should be used to construct LDAP * requests and decode LDAP responses. * * @return Returns the LDAP profile which should be used to * construct LDAP requests and decode LDAP responses. */ LDAPProfile getLDAPProfile() { return profile; return LDAPManagedObject.getRootManagedObject(driver); } } opends/src/server/org/opends/server/admin/client/package-info.java
@@ -30,12 +30,8 @@ /** * Common client-side administration classes. * <p> * This package contains classes which client applications and client-side * driver implementations are expected to use. * <p> * In addition, there are also two example client * applications, <code>ExampleClient</code> and * <code>ExampleIntrospection</code>. * This package contains classes which client applications are * expected to use. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.PRIVATE) opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
New file @@ -0,0 +1,696 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.admin.client.spi; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.opends.server.admin.AbstractManagedObjectDefinition; import org.opends.server.admin.Configuration; import org.opends.server.admin.ConfigurationClient; import org.opends.server.admin.DefaultBehaviorException; import org.opends.server.admin.DefinitionDecodingException; import org.opends.server.admin.IllegalPropertyValueException; import org.opends.server.admin.IllegalPropertyValueStringException; import org.opends.server.admin.InstantiableRelationDefinition; import org.opends.server.admin.ManagedObjectAlreadyExistsException; import org.opends.server.admin.ManagedObjectDefinition; import org.opends.server.admin.ManagedObjectNotFoundException; import org.opends.server.admin.ManagedObjectPath; import org.opends.server.admin.OptionalRelationDefinition; import org.opends.server.admin.PropertyDefinition; import org.opends.server.admin.PropertyIsMandatoryException; import org.opends.server.admin.PropertyIsReadOnlyException; import org.opends.server.admin.PropertyIsSingleValuedException; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.RelationDefinition; import org.opends.server.admin.SingletonRelationDefinition; import org.opends.server.admin.client.AuthorizationException; import org.opends.server.admin.client.CommunicationException; import org.opends.server.admin.client.ConcurrentModificationException; import org.opends.server.admin.client.IllegalManagedObjectNameException; import org.opends.server.admin.client.ManagedObject; import org.opends.server.admin.client.ManagedObjectDecodingException; import org.opends.server.admin.client.MissingMandatoryPropertiesException; import org.opends.server.admin.client.OperationRejectedException; /** * An abstract managed object implementation. * * @param <T> * The type of client configuration represented by the client * managed object. */ public abstract class AbstractManagedObject<T extends ConfigurationClient> implements ManagedObject<T> { // The managed object definition associated with this managed // object. private final ManagedObjectDefinition<T, ? extends Configuration> definition; // Indicates whether or not this managed object exists on the server // (false means the managed object is new and has not been // committed). private boolean existsOnServer; // Optional naming property definition. private final PropertyDefinition<?> namingPropertyDefinition; // The path associated with this managed object. private ManagedObjectPath<T, ? extends Configuration> path; // The managed object's properties. private final PropertySet properties; /** * Creates a new abstract managed object. * * @param d * The managed object's definition. * @param path * The managed object's path. * @param properties * The managed object's properties. * @param existsOnServer * Indicates whether or not the managed object exists on * the server (false means the managed object is new and * has not been committed). * @param namingPropertyDefinition * Optional naming property definition. */ protected AbstractManagedObject( ManagedObjectDefinition<T, ? extends Configuration> d, ManagedObjectPath<T, ? extends Configuration> path, PropertySet properties, boolean existsOnServer, PropertyDefinition<?> namingPropertyDefinition) { this.definition = d; this.path = path; this.properties = properties; this.existsOnServer = existsOnServer; this.namingPropertyDefinition = namingPropertyDefinition; } /** * {@inheritDoc} */ public final void commit() throws ManagedObjectAlreadyExistsException, MissingMandatoryPropertiesException, ConcurrentModificationException, OperationRejectedException, AuthorizationException, CommunicationException { // First make sure all mandatory properties are defined. List<PropertyIsMandatoryException> exceptions = new LinkedList<PropertyIsMandatoryException>(); for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { Property<?> p = getProperty(pd); if (pd.hasOption(PropertyOption.MANDATORY) && p.getEffectiveValues().isEmpty()) { exceptions.add(new PropertyIsMandatoryException(pd)); } } if (!exceptions.isEmpty()) { throw new MissingMandatoryPropertiesException(exceptions); } // Commit the managed object. if (existsOnServer) { modifyExistingManagedObject(); } else { addNewManagedObject(); existsOnServer = true; } // Make all pending property values active. properties.commit(); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration, CC extends C> ManagedObject<CC> createChild( InstantiableRelationDefinition<C, S> r, ManagedObjectDefinition<CC, ? extends S> d, String name, Collection<DefaultBehaviorException> exceptions) throws IllegalManagedObjectNameException, IllegalArgumentException { validateRelationDefinition(r); // Empty names are not allowed. if (name.trim().length() == 0) { throw new IllegalManagedObjectNameException(name); } // If the relation uses a naming property definition then it must // be a valid value. PropertyDefinition<?> pd = r.getNamingPropertyDefinition(); if (pd != null) { try { pd.decodeValue(name); } catch (IllegalPropertyValueStringException e) { throw new IllegalManagedObjectNameException(name, pd); } } ManagedObjectPath<CC, ? extends S> childPath = path.child(r, d, name); return createNewManagedObject(d, childPath, pd, name, exceptions); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration, CC extends C> ManagedObject<CC> createChild( OptionalRelationDefinition<C, S> r, ManagedObjectDefinition<CC, ? extends S> d, Collection<DefaultBehaviorException> exceptions) throws IllegalArgumentException { validateRelationDefinition(r); ManagedObjectPath<CC, ? extends S> childPath = path.child(r, d); return createNewManagedObject(d, childPath, null, null, exceptions); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( InstantiableRelationDefinition<C, S> r, String name) throws IllegalArgumentException, DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); Driver ctx = getDriver(); return ctx.getManagedObject(path.child(r, name)); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( OptionalRelationDefinition<C, S> r) throws IllegalArgumentException, DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); Driver ctx = getDriver(); return ctx.getManagedObject(path.child(r)); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( SingletonRelationDefinition<C, S> r) throws IllegalArgumentException, DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); ensureThisManagedObjectExists(); Driver ctx = getDriver(); return ctx.getManagedObject(path.child(r)); } /** * {@inheritDoc} */ public final T getConfiguration() { return definition.createClientConfiguration(this); } /** * {@inheritDoc} */ public final ManagedObjectDefinition<T, ? extends Configuration> getManagedObjectDefinition() { return definition; } /** * {@inheritDoc} */ public final ManagedObjectPath<T, ? extends Configuration> getManagedObjectPath() { return path; } /** * {@inheritDoc} */ public final <PD> SortedSet<PD> getPropertyDefaultValues( PropertyDefinition<PD> pd) throws IllegalArgumentException { return new TreeSet<PD>(getProperty(pd).getDefaultValues()); } /** * {@inheritDoc} */ public final <PD> PD getPropertyValue(PropertyDefinition<PD> pd) throws IllegalArgumentException { Set<PD> values = getProperty(pd).getEffectiveValues(); if (values.isEmpty()) { return null; } else { return values.iterator().next(); } } /** * {@inheritDoc} */ public final <PD> SortedSet<PD> getPropertyValues(PropertyDefinition<PD> pd) throws IllegalArgumentException { return new TreeSet<PD>(getProperty(pd).getEffectiveValues()); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> boolean hasChild( OptionalRelationDefinition<C, S> r) throws IllegalArgumentException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); Driver ctx = getDriver(); try { return ctx.hasManagedObject(path, r); } catch (ManagedObjectNotFoundException e) { throw new ConcurrentModificationException(); } } /** * {@inheritDoc} */ public final boolean isPropertyPresent(PropertyDefinition<?> pd) throws IllegalArgumentException { return !getProperty(pd).isEmpty(); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> String[] listChildren( InstantiableRelationDefinition<C, S> r) throws IllegalArgumentException, ConcurrentModificationException, AuthorizationException, CommunicationException { return listChildren(r, r.getChildDefinition()); } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> String[] listChildren( InstantiableRelationDefinition<C, S> r, AbstractManagedObjectDefinition<? extends C, ? extends S> d) throws IllegalArgumentException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); Driver ctx = getDriver(); try { return ctx.listManagedObjects(path, r, d); } catch (ManagedObjectNotFoundException e) { throw new ConcurrentModificationException(); } } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> void removeChild( InstantiableRelationDefinition<C, S> r, String name) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); Driver ctx = getDriver(); boolean found; try { found = ctx.deleteManagedObject(path, r, name); } catch (ManagedObjectNotFoundException e) { throw new ConcurrentModificationException(); } if (!found) { throw new ManagedObjectNotFoundException(); } } /** * {@inheritDoc} */ public final <C extends ConfigurationClient, S extends Configuration> void removeChild( OptionalRelationDefinition<C, S> r) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, ConcurrentModificationException, AuthorizationException, CommunicationException { validateRelationDefinition(r); Driver ctx = getDriver(); boolean found; try { found = ctx.deleteManagedObject(path, r); } catch (ManagedObjectNotFoundException e) { throw new ConcurrentModificationException(); } if (!found) { throw new ManagedObjectNotFoundException(); } } /** * {@inheritDoc} */ public final <PD> void setPropertyValue(PropertyDefinition<PD> pd, PD value) throws IllegalPropertyValueException, PropertyIsReadOnlyException, PropertyIsMandatoryException, IllegalArgumentException { if (value == null) { setPropertyValues(pd, Collections.<PD> emptySet()); } else { setPropertyValues(pd, Collections.singleton(value)); } } /** * {@inheritDoc} */ public final <PD> void setPropertyValues(PropertyDefinition<PD> pd, Collection<PD> values) throws IllegalPropertyValueException, PropertyIsSingleValuedException, PropertyIsReadOnlyException, PropertyIsMandatoryException, IllegalArgumentException { if (pd.hasOption(PropertyOption.MONITORING)) { throw new PropertyIsReadOnlyException(pd); } if (existsOnServer && pd.hasOption(PropertyOption.READ_ONLY)) { throw new PropertyIsReadOnlyException(pd); } properties.setPropertyValues(pd, values); // If this is a naming property then update the name. if (pd.equals(namingPropertyDefinition)) { // The property must be single-valued and mandatory. String newName = pd.encodeValue(values.iterator().next()); path = path.rename(newName); } } /** * Adds this new managed object. * * @throws ManagedObjectAlreadyExistsException * If the managed object cannot be added to the server * because it already exists. * @throws ConcurrentModificationException * If the managed object's parent has been removed by * another client. * @throws OperationRejectedException * If the server refuses to add this managed object due to * some server-side constraint which cannot be satisfied. * @throws AuthorizationException * If the server refuses to add this managed object * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ protected abstract void addNewManagedObject() throws AuthorizationException, CommunicationException, OperationRejectedException, ConcurrentModificationException, ManagedObjectAlreadyExistsException; /** * Gets the management context driver associated with this managed * object. * * @return Returns the management context driver associated with * this managed object. */ protected abstract Driver getDriver(); /** * Gets the naming property definition associated with this managed * object. * * @return Returns the naming property definition associated with * this managed object, or <code>null</code> if this * managed object does not have a naming property. */ protected final PropertyDefinition<?> getNamingPropertyDefinition() { return namingPropertyDefinition; } /** * Gets the property associated with the specified property * definition. * * @param <PD> * The underlying type of the property. * @param pd * The Property definition. * @return Returns the property associated with the specified * property definition. * @throws IllegalArgumentException * If this property provider does not recognize the * requested property definition. */ protected final <PD> Property<PD> getProperty(PropertyDefinition<PD> pd) throws IllegalArgumentException { return properties.getProperty(pd); } /** * Applies changes made to this managed object. * * @throws ConcurrentModificationException * If this managed object has been removed from the server * by another client. * @throws OperationRejectedException * If the server refuses to modify this managed object due * to some server-side constraint which cannot be * satisfied. * @throws AuthorizationException * If the server refuses to modify this managed object * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ protected abstract void modifyExistingManagedObject() throws ConcurrentModificationException, OperationRejectedException, AuthorizationException, CommunicationException; /** * Creates a new managed object. * * @param <M> * The type of client configuration represented by the * client managed object. * @param d * The managed object's definition. * @param path * The managed object's path. * @param properties * The managed object's properties. * @param existsOnServer * Indicates whether or not the managed object exists on * the server (false means the managed object is new and * has not been committed). * @param namingPropertyDefinition * Optional naming property definition. * @return Returns the new managed object. */ protected abstract <M extends ConfigurationClient> ManagedObject<M> newInstance( ManagedObjectDefinition<M, ?> d, ManagedObjectPath<M, ?> path, PropertySet properties, boolean existsOnServer, PropertyDefinition<?> namingPropertyDefinition); // Creates a new managed object with no active values, just default // values. private <M extends ConfigurationClient, PD> ManagedObject<M> createNewManagedObject( ManagedObjectDefinition<M, ?> d, ManagedObjectPath<M, ?> p, PropertyDefinition<PD> namingPropertyDefinition, String name, Collection<DefaultBehaviorException> exceptions) { PropertySet childProperties = new PropertySet(); for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) { try { createProperty(childProperties, p, pd); } catch (DefaultBehaviorException e) { // Add the exception if requested. if (exceptions != null) { exceptions.add(e); } } } // Set the naming property if there is one. if (namingPropertyDefinition != null) { PD value = namingPropertyDefinition.decodeValue(name); childProperties.setPropertyValues(namingPropertyDefinition, Collections .singleton(value)); } return newInstance(d, p, childProperties, false, namingPropertyDefinition); } // Create an empty property. private <PD> void createProperty(PropertySet properties, ManagedObjectPath<?, ?> p, PropertyDefinition<PD> pd) throws DefaultBehaviorException { try { Driver context = getDriver(); Collection<PD> defaultValues = context.findDefaultValues(p, pd, true); properties.addProperty(pd, defaultValues, Collections.<PD> emptySet()); } catch (DefaultBehaviorException e) { // Make sure that we have still created the property. properties.addProperty(pd, Collections.<PD> emptySet(), Collections .<PD> emptySet()); throw e; } } // Makes sure that this managed object exists. private void ensureThisManagedObjectExists() throws ConcurrentModificationException, CommunicationException, AuthorizationException { if (!path.isEmpty()) { Driver ctx = getDriver(); try { ctx.getManagedObject(path); } catch (DefinitionDecodingException e) { // Ignore. } catch (ManagedObjectDecodingException e) { // Ignore. } catch (ManagedObjectNotFoundException e) { throw new ConcurrentModificationException(); } } } // Validate that a relation definition belongs to this managed // object. private void validateRelationDefinition(RelationDefinition<?, ?> rd) throws IllegalArgumentException { ManagedObjectDefinition<T, ?> d = getManagedObjectDefinition(); RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); if (tmp != rd) { throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " + d.getName()); } } } opends/src/server/org/opends/server/admin/client/spi/Driver.java
New file @@ -0,0 +1,701 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.admin.client.spi; import static org.opends.server.util.StaticUtils.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.SortedSet; import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider; import org.opends.server.admin.AbstractManagedObjectDefinition; import org.opends.server.admin.AliasDefaultBehaviorProvider; import org.opends.server.admin.Configuration; import org.opends.server.admin.ConfigurationClient; import org.opends.server.admin.DefaultBehaviorException; import org.opends.server.admin.DefaultBehaviorProviderVisitor; import org.opends.server.admin.DefinedDefaultBehaviorProvider; import org.opends.server.admin.DefinitionDecodingException; import org.opends.server.admin.IllegalPropertyValueStringException; import org.opends.server.admin.InstantiableRelationDefinition; import org.opends.server.admin.ManagedObjectNotFoundException; import org.opends.server.admin.ManagedObjectPath; import org.opends.server.admin.OptionalRelationDefinition; import org.opends.server.admin.PropertyDefinition; import org.opends.server.admin.PropertyException; import org.opends.server.admin.PropertyIsSingleValuedException; import org.opends.server.admin.PropertyNotFoundException; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider; import org.opends.server.admin.UndefinedDefaultBehaviorProvider; import org.opends.server.admin.DefinitionDecodingException.Reason; import org.opends.server.admin.client.AuthorizationException; import org.opends.server.admin.client.CommunicationException; import org.opends.server.admin.client.ManagedObject; import org.opends.server.admin.client.ManagedObjectDecodingException; import org.opends.server.admin.client.OperationRejectedException; /** * An abstract management connection context driver which should form * the basis of driver implementations. */ public abstract class Driver { /** * A default behavior visitor used for retrieving the default values * of a property. * * @param <T> * The type of the property. */ private class DefaultValueFinder<T> implements DefaultBehaviorProviderVisitor<T, Collection<T>, Void> { // Any exception that occurred whilst retrieving inherited default // values. private DefaultBehaviorException exception = null; // The path of the managed object containing the first property. private final ManagedObjectPath<?, ?> firstPath; // Indicates whether the managed object has been created yet. private final boolean isCreate; // The path of the managed object containing the next property. private ManagedObjectPath<?, ?> nextPath = null; // The next property whose default values were required. private PropertyDefinition<T> nextProperty = null; // Private constructor. private DefaultValueFinder(ManagedObjectPath<?, ?> p, boolean isCreate) { this.firstPath = p; this.isCreate = isCreate; } /** * {@inheritDoc} */ public Collection<T> visitAbsoluteInherited( AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(), d .getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } /** * {@inheritDoc} */ public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d, Void p) { Collection<String> stringValues = d.getDefaultValues(); List<T> values = new ArrayList<T>(stringValues.size()); for (String stringValue : stringValues) { try { values.add(nextProperty.decodeValue(stringValue)); } catch (IllegalPropertyValueStringException e) { exception = new DefaultBehaviorException(nextProperty, e); break; } } return values; } /** * {@inheritDoc} */ public Collection<T> visitRelativeInherited( RelativeInheritedDefaultBehaviorProvider<T> d, Void p) { try { return getInheritedProperty(d.getManagedObjectPath(nextPath), d .getManagedObjectDefinition(), d.getPropertyName()); } catch (DefaultBehaviorException e) { exception = e; return Collections.emptySet(); } } /** * {@inheritDoc} */ public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, Void p) { return Collections.emptySet(); } // Find the default values for the next path/property. private Collection<T> find(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd) throws DefaultBehaviorException { this.nextPath = p; this.nextProperty = pd; Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept( this, null); if (exception != null) { throw exception; } if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) { throw new DefaultBehaviorException(pd, new PropertyIsSingleValuedException(pd)); } return values; } // Get an inherited property value. @SuppressWarnings("unchecked") private Collection<T> getInheritedProperty(ManagedObjectPath target, AbstractManagedObjectDefinition<?, ?> d, String propertyName) throws DefaultBehaviorException { // First check that the requested type of managed object // corresponds to the path. AbstractManagedObjectDefinition<?, ?> supr = target .getManagedObjectDefinition(); if (!supr.isParentOf(d)) { throw new DefaultBehaviorException(nextProperty, new DefinitionDecodingException(Reason.WRONG_TYPE_INFORMATION)); } // Save the current property in case of recursion. PropertyDefinition<T> pd1 = nextProperty; try { // Determine the requested property definition. PropertyDefinition<T> pd2; try { // FIXME: we use the definition taken from the default // behavior here when we should really use the exact // definition of the component being created. PropertyDefinition<?> pdTmp = d.getPropertyDefinition(propertyName); pd2 = pd1.getClass().cast(pdTmp); } catch (IllegalArgumentException e) { throw new PropertyNotFoundException(propertyName); } catch (ClassCastException e) { // FIXME: would be nice to throw a better exception here. throw new PropertyNotFoundException(propertyName); } // If the path relates to the current managed object and the // managed object is in the process of being created it won't // exist, so we should just use the default values of the // referenced property. if (isCreate && firstPath.equals(target)) { // Recursively retrieve this property's default values. Collection<T> tmp = find(target, pd2); Collection<T> values = new ArrayList<T>(tmp.size()); for (T value : tmp) { pd1.validateValue(value); values.add(value); } return values; } else { return getPropertyValues(target, pd2); } } catch (DefaultBehaviorException e) { // Wrap any errors due to recursion. throw new DefaultBehaviorException(pd1, e); } catch (DefinitionDecodingException e) { throw new DefaultBehaviorException(pd1, e); } catch (PropertyNotFoundException e) { throw new DefaultBehaviorException(pd1, e); } catch (AuthorizationException e) { throw new DefaultBehaviorException(pd1, e); } catch (ManagedObjectNotFoundException e) { throw new DefaultBehaviorException(pd1, e); } catch (CommunicationException e) { throw new DefaultBehaviorException(pd1, e); } catch (PropertyException e) { throw new DefaultBehaviorException(pd1, e); } } }; /** * Creates a new abstract management context. */ protected Driver() { // No implementation required. } /** * Deletes the named instantiable child managed object from the * named parent managed object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The instantiable relation definition. * @param name * The name of the child managed object to be removed. * @return Returns <code>true</code> if the named instantiable * child managed object was found, or <code>false</code> * if it was not found. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. * @throws ManagedObjectNotFoundException * If the parent managed object could not be found. * @throws OperationRejectedException * If the server refuses to remove the child managed * object due to some server-side constraint which cannot * be satisfied (for example, if it is referenced by * another managed object). * @throws AuthorizationException * If the server refuses to make the list the managed * objects because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public abstract <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, String name) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, AuthorizationException, CommunicationException; /** * Deletes the optional child managed object from the named parent * managed object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The optional relation definition. * @return Returns <code>true</code> if the optional child managed * object was found, or <code>false</code> if it was not * found. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. * @throws ManagedObjectNotFoundException * If the parent managed object could not be found. * @throws OperationRejectedException * If the server refuses to remove the child managed * object due to some server-side constraint which cannot * be satisfied (for example, if it is referenced by * another managed object). * @throws AuthorizationException * If the server refuses to make the list the managed * objects because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public abstract <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd) throws IllegalArgumentException, ManagedObjectNotFoundException, OperationRejectedException, AuthorizationException, CommunicationException; /** * Gets the named managed object. * * @param <C> * The type of client managed object configuration that the * path definition refers to. * @param <S> * The type of server managed object configuration that the * path definition refers to. * @param path * The path of the managed object. * @return Returns the named managed object. * @throws DefinitionDecodingException * If the managed object was found but its type could not * be determined. * @throws ManagedObjectDecodingException * If the managed object was found but one or more of its * properties could not be decoded. * @throws ManagedObjectNotFoundException * If the requested managed object could not be found on * the server. * @throws AuthorizationException * If the server refuses to retrieve the managed object * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public abstract <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getManagedObject( ManagedObjectPath<C, S> path) throws DefinitionDecodingException, ManagedObjectDecodingException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException; /** * Gets the effective value of a property in the named managed * object. * * @param <PD> * The type of the property to be retrieved. * @param path * The path of the managed object containing the property. * @param pd * The property to be retrieved. * @return Returns the property's effective value, or * <code>null</code> if there are no values defined. * @throws IllegalArgumentException * If the property definition is not associated with the * referenced managed object's definition. * @throws DefinitionDecodingException * If the managed object was found but its type could not * be determined. * @throws PropertyException * If the managed object was found but the requested * property could not be decoded. * @throws ManagedObjectNotFoundException * If the requested managed object could not be found on * the server. * @throws AuthorizationException * If the server refuses to retrieve the managed object * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public final <PD> PD getPropertyValue(ManagedObjectPath<?, ?> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, DefinitionDecodingException, AuthorizationException, ManagedObjectNotFoundException, CommunicationException, PropertyException { Set<PD> values = getPropertyValues(path, pd); if (values.isEmpty()) { return null; } else { return values.iterator().next(); } } /** * Gets the effective values of a property in the named managed * object. * <p> * Implementations MUST NOT not use * {@link #getManagedObject(ManagedObjectPath)} to read the * referenced managed object in its entirety. Specifically, * implementations MUST only attempt to resolve the default values * for the requested property and its dependencies (if it uses * inherited defaults). This is to avoid infinite recursion where a * managed object contains a property which inherits default values * from another property in the same managed object. * * @param <PD> * The type of the property to be retrieved. * @param path * The path of the managed object containing the property. * @param pd * The property to be retrieved. * @return Returns the property's effective values, or an empty set * if there are no values defined. * @throws IllegalArgumentException * If the property definition is not associated with the * referenced managed object's definition. * @throws DefinitionDecodingException * If the managed object was found but its type could not * be determined. * @throws PropertyException * If the managed object was found but the requested * property could not be decoded. * @throws ManagedObjectNotFoundException * If the requested managed object could not be found on * the server. * @throws AuthorizationException * If the server refuses to retrieve the managed object * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public abstract <PD> SortedSet<PD> getPropertyValues( ManagedObjectPath<?, ?> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, DefinitionDecodingException, AuthorizationException, ManagedObjectNotFoundException, CommunicationException, PropertyException; /** * Determines whether or not the named parent managed object has the * named instantiable child managed object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The instantiable relation definition. * @param name * The name of the child managed object. * @return Returns <code>true</code> if the named instantiable * child managed object exists, <code>false</code> * otherwise. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. * @throws ManagedObjectNotFoundException * If the parent managed object could not be found. * @throws AuthorizationException * If the server refuses to make the determination because * the client does not have the correct privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public final <C extends ConfigurationClient, S extends Configuration> boolean hasManagedObject( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, String name) throws IllegalArgumentException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException { // FIXME: use naming properties for comparison where available. String[] children = listManagedObjects(parent, rd); String nname = toLowerCase(name.trim().replaceAll(" +", " ")); for (String child : children) { if (nname.equals(toLowerCase(child.trim().replaceAll(" +", " ")))) { return true; } } return false; } /** * Determines whether or not the named parent managed object has an * optional child managed object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The optional relation definition. * @return Returns <code>true</code> if the optional child managed * object exists, <code>false</code> otherwise. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. * @throws ManagedObjectNotFoundException * If the parent managed object could not be found. * @throws AuthorizationException * If the server refuses to make the determination because * the client does not have the correct privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public abstract <C extends ConfigurationClient, S extends Configuration> boolean hasManagedObject( ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd) throws IllegalArgumentException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException; /** * Lists the child managed objects of the named parent managed * object. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The instantiable relation definition. * @return Returns the names of the child managed objects. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. * @throws ManagedObjectNotFoundException * If the parent managed object could not be found. * @throws AuthorizationException * If the server refuses to list the managed objects * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public final <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) throws IllegalArgumentException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException { return listManagedObjects(parent, rd, rd.getChildDefinition()); } /** * Lists the child managed objects of the named parent managed * object which are a sub-type of the specified managed object * definition. * * @param <C> * The type of client managed object configuration that the * relation definition refers to. * @param <S> * The type of server managed object configuration that the * relation definition refers to. * @param parent * The path of the parent managed object. * @param rd * The instantiable relation definition. * @param d * The managed object definition. * @return Returns the names of the child managed objects which are * a sub-type of the specified managed object definition. * @throws IllegalArgumentException * If the relation definition is not associated with the * parent managed object's definition. * @throws ManagedObjectNotFoundException * If the parent managed object could not be found. * @throws AuthorizationException * If the server refuses to list the managed objects * because the client does not have the correct * privileges. * @throws CommunicationException * If the client cannot contact the server due to an * underlying communication problem. */ public abstract <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, AbstractManagedObjectDefinition<? extends C, ? extends S> d) throws IllegalArgumentException, ManagedObjectNotFoundException, AuthorizationException, CommunicationException; /** * Gets the default values for the specified property. * * @param <PD> * The type of the property. * @param p * The managed object path of the current managed object. * @param pd * The property definition. * @param isCreate * Indicates whether the managed object has been created * yet. * @return Returns the default values for the specified property. * @throws DefaultBehaviorException * If the default values could not be retrieved or decoded * properly. */ protected final <PD> Collection<PD> findDefaultValues( ManagedObjectPath<?, ?> p, PropertyDefinition<PD> pd, boolean isCreate) throws DefaultBehaviorException { DefaultValueFinder<PD> v = new DefaultValueFinder<PD>(p, isCreate); return v.find(p, pd); } } opends/src/server/org/opends/server/admin/client/spi/Property.java
File was renamed from opends/src/server/org/opends/server/admin/client/Property.java @@ -25,7 +25,7 @@ * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.admin.client; package org.opends.server.admin.client.spi; @@ -36,28 +36,26 @@ /** * A managed object property comprising of the property's definition and its set * of values. * A managed object property comprising of the property's definition * and its set of values. * <p> * The property stores the values in a sorted set in which values are compared * using the comparator defined by the property definition. * The property stores the values in a sorted set in which values are * compared using the comparator defined by the property definition. * <p> * The property keeps track of whether or not its pending set of values differs * from its active values. * The property keeps track of whether or not its pending set of * values differs from its active values. * * @param <T> * The type of the property. * @see ManagedObject The <code>ManagedObject</code> documentation describes * the different types of property values in more detail. */ public interface Property<T> { /** * Get an immutable set view of this property's active values. * * @return Returns an immutable set view of this property's active values. An * empty set indicates that there are no active values, and any * default values are applicable. * @return Returns an immutable set view of this property's active * values. An empty set indicates that there are no active * values, and any default values are applicable. */ SortedSet<T> getActiveValues(); @@ -66,8 +64,9 @@ /** * Get an immutable set view of this property's default values. * * @return Returns an immutable set view of this property's default values. An * empty set indicates that there are no default values. * @return Returns an immutable set view of this property's default * values. An empty set indicates that there are no default * values. */ SortedSet<T> getDefaultValues(); @@ -76,7 +75,8 @@ /** * Get an immutable set view of this property's effective values. * * @return Returns an immutable set view of this property's effective values. * @return Returns an immutable set view of this property's * effective values. */ SortedSet<T> getEffectiveValues(); @@ -85,12 +85,12 @@ /** * Get an immutable set view of this property's pending values. * <p> * Immediately after construction, the pending values matches the active * values. * Immediately after construction, the pending values matches the * active values. * * @return Returns an immutable set view of this property's pending values. An * empty set indicates that there are no pending values, and any * default values are applicable. * @return Returns an immutable set view of this property's pending * values. An empty set indicates that there are no pending * values, and any default values are applicable. */ SortedSet<T> getPendingValues(); @@ -99,39 +99,42 @@ /** * Get the property definition associated with this property. * * @return Returns the property definition associated with this property. * @return Returns the property definition associated with this * property. */ PropertyDefinition<T> getPropertyDefinition(); /** * Determines whether or not this property contains any pending values. * Determines whether or not this property contains any pending * values. * * @return Returns <code>true</code> if this property does not contain any * pending values. * @return Returns <code>true</code> if this property does not * contain any pending values. */ boolean isEmpty(); /** * Determines whether or not this property has been modified since it was * constructed. In other words, whether or not the set of pending values * differs from the set of active values. * Determines whether or not this property has been modified since * it was constructed. In other words, whether or not the set of * pending values differs from the set of active values. * * @return Returns <code>true</code> if this property has been modified * since it was constructed. * @return Returns <code>true</code> if this property has been * modified since it was constructed. */ boolean isModified(); /** * Determines whether or not this property contains any active values. * Determines whether or not this property contains any active * values. * * @return Returns <code>true</code> if this property does not contain any * active values. * @return Returns <code>true</code> if this property does not * contain any active values. */ boolean wasEmpty(); } opends/src/server/org/opends/server/admin/client/spi/PropertySet.java
File was renamed from opends/src/server/org/opends/server/admin/client/PropertySet.java @@ -25,7 +25,7 @@ * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.admin.client; package org.opends.server.admin.client.spi; @@ -33,7 +33,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -42,7 +41,6 @@ import org.opends.server.admin.PropertyIsMandatoryException; import org.opends.server.admin.PropertyIsSingleValuedException; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.PropertyProvider; @@ -50,7 +48,7 @@ * A set of properties. Instances of this class can be used as the * core of a managed object implementation. */ public final class PropertySet implements PropertyProvider { public final class PropertySet { /** * Internal property implementation. @@ -255,17 +253,6 @@ /** * Makes all pending values active. */ public void commit() { for (MyProperty<?> p : properties.values()) { p.commit(); } } /** * Get the property associated with the specified property * definition. * @@ -292,88 +279,34 @@ /** * Get the effective value of the specified property. * <p> * See the class description for more information about how the * effective property value is derived. * * @param <T> * The type of the property to be retrieved. * @param d * The property to be retrieved. * @return Returns the property's effective value, or * <code>null</code> if there is no effective value * defined. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. * {@inheritDoc} */ public <T> T getPropertyValue(PropertyDefinition<T> d) throws IllegalArgumentException { Set<T> values = getPropertyValues(d); if (values.isEmpty()) { return null; } else { return values.iterator().next(); @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append('{'); for (Map.Entry<PropertyDefinition<?>, MyProperty<?>> entry : properties .entrySet()) { builder.append(entry.getKey().getName()); builder.append('='); builder.append(entry.getValue().toString()); builder.append(' '); } builder.append('}'); return builder.toString(); } /** * Get the effective values of the specified property. * <p> * See the class description for more information about how the * effective property values are derived. * * @param <T> * The type of the property to be retrieved. * @param d * The property to be retrieved. * @return Returns the property's effective values, or an empty set * if there are no effective values defined. * @throws IllegalArgumentException * If the property definition is not associated with this * managed object's definition. * Makes all pending values active. */ public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d) throws IllegalArgumentException { Property<T> property = getProperty(d); return new TreeSet<T>(property.getEffectiveValues()); } /** * Set a new pending value for the specified property. * <p> * See the class description for more information regarding pending * values. * * @param <T> * The type of the property to be modified. * @param d * The property to be modified. * @param value * The new pending value for the property, or * <code>null</code> if the property should be reset to * its default behavior. * @throws IllegalPropertyValueException * If the new pending value is deemed to be invalid * according to the property definition. * @throws PropertyIsMandatoryException * If an attempt was made to remove a mandatory property. * @throws IllegalArgumentException * If the specified property definition is not associated * with this managed object. */ public <T> void setPropertyValue(PropertyDefinition<T> d, T value) throws IllegalPropertyValueException, PropertyIsMandatoryException, IllegalArgumentException { if (value == null) { setPropertyValues(d, Collections.<T> emptySet()); } else { setPropertyValues(d, Collections.singleton(value)); void commit() { for (MyProperty<?> p : properties.values()) { p.commit(); } } @@ -406,7 +339,7 @@ * If the specified property definition is not associated * with this managed object. */ public <T> void setPropertyValues(PropertyDefinition<T> d, <T> void setPropertyValues(PropertyDefinition<T> d, Collection<T> values) throws IllegalPropertyValueException, PropertyIsSingleValuedException, PropertyIsMandatoryException, IllegalArgumentException { @@ -435,24 +368,4 @@ // Update the property. property.setPendingValues(values); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append('{'); for (Map.Entry<PropertyDefinition<?>, MyProperty<?>> entry : properties .entrySet()) { builder.append(entry.getKey().getName()); builder.append('='); builder.append(entry.getValue().toString()); builder.append(' '); } builder.append('}'); return builder.toString(); } } opends/src/server/org/opends/server/admin/client/spi/package-info.java
New file @@ -0,0 +1,39 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ /** * Client side driver implementation interfaces. * <p> * This package contains classes which client-side driver * implementations are expected to use. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.PRIVATE) package org.opends.server.admin.client.spi; opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/spi/PropertySetTest.java
File was renamed from opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/PropertySetTest.java @@ -25,12 +25,15 @@ * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.admin.client; package org.opends.server.admin.client.spi; import static org.testng.Assert.*; import org.testng.annotations.*; import org.opends.server.admin.*; import org.opends.server.admin.Configuration; import org.opends.server.admin.client.ManagedObject; import org.opends.server.admin.client.spi.Property; import org.opends.server.admin.client.spi.PropertySet; import org.opends.server.admin.server.ServerManagedObject; import org.opends.server.admin.std.meta.RootCfgDefn;