| | |
| | | import java.util.SortedSet; |
| | | |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.admin.client.AuthorizationException; |
| | | import org.opends.server.admin.client.ClientConstraintHandler; |
| | | 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.ManagementContext; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.server.ConfigurationDeleteListener; |
| | | import org.opends.server.admin.server.ServerConstraintHandler; |
| | |
| | | |
| | | |
| | | /** |
| | | * Registers a boolean "enabled" property in this managed object. |
| | | * When all the registered properties are true, the enabled |
| | | * property in the aggregated managed object must also be true. |
| | | * <p> |
| | | * By default no source properties are defined which indicates |
| | | * that the target property must always be true. When there is one |
| | | * or more source properties defined, a target property must also |
| | | * be defined. |
| | | * |
| | | * @param sourceEnabledPropertyName |
| | | * The optional boolean "enabled" property in this |
| | | * managed object. |
| | | */ |
| | | public final void addSourceEnabledPropertyName( |
| | | String sourceEnabledPropertyName) { |
| | | this.sourceEnabledPropertyNames.add(sourceEnabledPropertyName); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the name of the managed object which is the parent of the |
| | | * aggregated managed objects. |
| | | * <p> |
| | |
| | | |
| | | |
| | | /** |
| | | * Registers a boolean "enabled" property in this managed object. |
| | | * When all the registered properties are true, the enabled |
| | | * property in the aggregated managed object must also be true. |
| | | * <p> |
| | | * By default no source properties are defined which indicates |
| | | * that the target property must always be true. When there is one |
| | | * or more source properties defined, a target property must also |
| | | * be defined. |
| | | * |
| | | * @param sourceEnabledPropertyName |
| | | * The optional boolean "enabled" property in this |
| | | * managed object. |
| | | */ |
| | | public final void addSourceEnabledPropertyName( |
| | | String sourceEnabledPropertyName) { |
| | | this.sourceEnabledPropertyNames.add(sourceEnabledPropertyName); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the optional boolean "enabled" property in the aggregated |
| | | * managed object. This property must not be false while the |
| | | * aggregated managed object is referenced. |
| | |
| | | if (!sourceEnabledPropertyNames.isEmpty() |
| | | && targetEnabledPropertyName == null) { |
| | | throw new IllegalStateException( |
| | | "One or more source properties defined but " + |
| | | "target property is undefined"); |
| | | "One or more source properties defined but " |
| | | + "target property is undefined"); |
| | | } |
| | | |
| | | return new AggregationPropertyDefinition<C, S>(d, propertyName, options, |
| | |
| | | */ |
| | | private class ServerHandler extends ServerConstraintHandler { |
| | | |
| | | // The associated property definition. |
| | | private final AggregationPropertyDefinition<C, S> pd; |
| | | |
| | | |
| | | |
| | | // Creates a new server-side constraint handler. |
| | | private ServerHandler(AggregationPropertyDefinition<C, S> pd) { |
| | | this.pd = pd; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isUsable(ServerManagedObject<?> managedObject, |
| | | Collection<Message> unacceptableReasons) throws ConfigException { |
| | | SortedSet<String> names = managedObject.getPropertyValues(pd); |
| | | SortedSet<String> names = managedObject |
| | | .getPropertyValues(AggregationPropertyDefinition.this); |
| | | ServerManagementContext context = ServerManagementContext.getInstance(); |
| | | BooleanPropertyDefinition tpd = pd.getTargetEnabledPropertyDefinition(); |
| | | List<BooleanPropertyDefinition> spdlist = pd |
| | | .getSourceEnabledPropertyDefinitions(); |
| | | BooleanPropertyDefinition tpd = getTargetEnabledPropertyDefinition(); |
| | | List<BooleanPropertyDefinition> spdlist = |
| | | getSourceEnabledPropertyDefinitions(); |
| | | Message thisUFN = managedObject.getManagedObjectDefinition() |
| | | .getUserFriendlyName(); |
| | | String thisDN = managedObject.getDN().toString(); |
| | | Message thatUFN = pd.getRelationDefinition().getUserFriendlyName(); |
| | | Message thatUFN = getRelationDefinition().getUserFriendlyName(); |
| | | |
| | | boolean isUsable = true; |
| | | for (String name : names) { |
| | | ManagedObjectPath<C, S> path = pd.getChildPath(name); |
| | | ManagedObjectPath<C, S> path = getChildPath(name); |
| | | String thatDN = path.toDN().toString(); |
| | | |
| | | if (!context.managedObjectExists(path)) { |
| | | Message msg = ERR_SERVER_REFINT_DANGLING_REFERENCE.get(name, pd |
| | | .getName(), thisUFN, thisDN, thatUFN, thatDN); |
| | | Message msg = ERR_SERVER_REFINT_DANGLING_REFERENCE.get(name, |
| | | getName(), thisUFN, thisDN, thatUFN, thatDN); |
| | | unacceptableReasons.add(msg); |
| | | isUsable = false; |
| | | } else if (tpd != null) { |
| | |
| | | |
| | | if (isRequired && !ref.getPropertyValue(tpd)) { |
| | | Message msg = ERR_SERVER_REFINT_SOURCE_ENABLED_TARGET_DISABLED |
| | | .get(name, pd.getName(), thisUFN, thisDN, thatUFN, thatDN); |
| | | .get(name, getName(), thisUFN, thisDN, thatUFN, thatDN); |
| | | unacceptableReasons.add(msg); |
| | | isUsable = false; |
| | | } |
| | | } else { |
| | | // Target must always be enabled. |
| | | if (!ref.getPropertyValue(tpd)) { |
| | | Message msg = ERR_SERVER_REFINT_TARGET_DISABLED.get(name, pd |
| | | .getName(), thisUFN, thisDN, thatUFN, thatDN); |
| | | Message msg = ERR_SERVER_REFINT_TARGET_DISABLED.get(name, |
| | | getName(), thisUFN, thisDN, thatUFN, thatDN); |
| | | unacceptableReasons.add(msg); |
| | | isUsable = false; |
| | | } |
| | |
| | | |
| | | // Add change and delete listeners against all referenced |
| | | // components. |
| | | BooleanPropertyDefinition tpd = pd.getTargetEnabledPropertyDefinition(); |
| | | List<BooleanPropertyDefinition> spdlist = pd |
| | | .getSourceEnabledPropertyDefinitions(); |
| | | BooleanPropertyDefinition tpd = getTargetEnabledPropertyDefinition(); |
| | | List<BooleanPropertyDefinition> spdlist = |
| | | getSourceEnabledPropertyDefinitions(); |
| | | Message thisUFN = managedObject.getManagedObjectDefinition() |
| | | .getUserFriendlyName(); |
| | | String thisDN = managedObject.getDN().toString(); |
| | | Message thatUFN = pd.getRelationDefinition().getUserFriendlyName(); |
| | | Message thatUFN = getRelationDefinition().getUserFriendlyName(); |
| | | |
| | | // Referenced managed objects will only need a change listener |
| | | // if they have can be disabled. |
| | |
| | | // Delete listeners need to be registered against the parent |
| | | // entry of the referenced components. |
| | | ServerManagementContext context = ServerManagementContext.getInstance(); |
| | | ManagedObjectPath<?, ?> parentPath = pd.getParentPath(); |
| | | ManagedObjectPath<?, ?> parentPath = getParentPath(); |
| | | ServerManagedObject<?> parent = context.getManagedObject(parentPath); |
| | | |
| | | // Create entries in the listener tables. |
| | |
| | | new LinkedList<ReferentialIntegrityChangeListener>(); |
| | | changeListeners.put(managedObject.getDN(), clist); |
| | | |
| | | for (String name : managedObject.getPropertyValues(pd)) { |
| | | ManagedObjectPath<C, S> path = pd.getChildPath(name); |
| | | for (String name : managedObject |
| | | .getPropertyValues(AggregationPropertyDefinition.this)) { |
| | | ManagedObjectPath<C, S> path = getChildPath(name); |
| | | DN dn = path.toDN(); |
| | | String thatDN = dn.toString(); |
| | | |
| | | // Register the delete listener. |
| | | Message msg = ERR_SERVER_REFINT_CANNOT_DELETE.get(thatUFN, thatDN, pd |
| | | .getName(), thisUFN, thisDN); |
| | | Message msg = ERR_SERVER_REFINT_CANNOT_DELETE.get(thatUFN, thatDN, |
| | | getName(), thisUFN, thisDN); |
| | | ReferentialIntegrityDeleteListener dl = |
| | | new ReferentialIntegrityDeleteListener(dn, msg); |
| | | parent.registerDeleteListener(pd.getRelationDefinition(), dl); |
| | | parent.registerDeleteListener(getRelationDefinition(), dl); |
| | | dlist.add(dl); |
| | | |
| | | // Register the change listener if required. |
| | | if (needsChangeListeners) { |
| | | ServerManagedObject<? extends S> ref = context.getManagedObject(path); |
| | | msg = ERR_SERVER_REFINT_CANNOT_DISABLE.get(thatUFN, thatDN, pd |
| | | .getName(), thisUFN, thisDN); |
| | | msg = ERR_SERVER_REFINT_CANNOT_DISABLE.get(thatUFN, thatDN, |
| | | getName(), thisUFN, thisDN); |
| | | ReferentialIntegrityChangeListener cl = |
| | | new ReferentialIntegrityChangeListener(path, msg); |
| | | ref.registerChangeListener(cl); |
| | |
| | | |
| | | // Delete listeners need to be deregistered against the parent |
| | | // entry of the referenced components. |
| | | ManagedObjectPath<?, ?> parentPath = pd.getParentPath(); |
| | | ManagedObjectPath<?, ?> parentPath = getParentPath(); |
| | | ServerManagedObject<?> parent = context.getManagedObject(parentPath); |
| | | if (deleteListeners.containsKey(dn)) { |
| | | for (ReferentialIntegrityDeleteListener dl : deleteListeners.get(dn)) { |
| | | parent.deregisterDeleteListener(pd.getRelationDefinition(), dl); |
| | | parent.deregisterDeleteListener(getRelationDefinition(), dl); |
| | | } |
| | | deleteListeners.remove(dn); |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * The client-side constraint handler implementation which enforces |
| | | * referential integrity when aggregating managed objects are added |
| | | * or modified. |
| | | */ |
| | | private class SourceClientHandler extends ClientConstraintHandler { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isAddAcceptable(ManagementContext context, |
| | | ManagedObject<?> managedObject, Collection<Message> unacceptableReasons) |
| | | throws AuthorizationException, CommunicationException { |
| | | // If all of this managed object's "enabled" properties are true |
| | | // then any referenced managed objects must also be enabled. |
| | | boolean needsEnabling = true; |
| | | for (BooleanPropertyDefinition spd : |
| | | getSourceEnabledPropertyDefinitions()) { |
| | | if (!managedObject.getPropertyValue(spd)) { |
| | | needsEnabling = false; |
| | | } |
| | | } |
| | | |
| | | // Check the referenced managed objects exist and, if required, |
| | | // are enabled. |
| | | boolean isAcceptable = true; |
| | | BooleanPropertyDefinition tpd = getTargetEnabledPropertyDefinition(); |
| | | Message ufn = getRelationDefinition().getUserFriendlyName(); |
| | | for (String name : managedObject |
| | | .getPropertyValues(AggregationPropertyDefinition.this)) { |
| | | // Retrieve the referenced managed object and make sure it |
| | | // exists. |
| | | ManagedObjectPath<?, ?> path = getChildPath(name); |
| | | ManagedObject<?> ref; |
| | | try { |
| | | ref = context.getManagedObject(path); |
| | | } catch (DefinitionDecodingException e) { |
| | | Message msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name, |
| | | getName(), e.getMessageObject()); |
| | | unacceptableReasons.add(msg); |
| | | isAcceptable = false; |
| | | continue; |
| | | } catch (ManagedObjectDecodingException e) { |
| | | Message msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name, |
| | | getName(), e.getMessageObject()); |
| | | unacceptableReasons.add(msg); |
| | | isAcceptable = false; |
| | | continue; |
| | | } catch (ManagedObjectNotFoundException e) { |
| | | Message msg = ERR_CLIENT_REFINT_TARGET_DANGLING_REFERENCE.get(ufn, |
| | | name, getName()); |
| | | unacceptableReasons.add(msg); |
| | | isAcceptable = false; |
| | | continue; |
| | | } |
| | | |
| | | // Make sure the reference managed object is enabled. |
| | | if (tpd != null && needsEnabling) { |
| | | if (!ref.getPropertyValue(tpd)) { |
| | | Message msg = ERR_CLIENT_REFINT_TARGET_DISABLED.get(ufn, name, |
| | | getName()); |
| | | unacceptableReasons.add(msg); |
| | | isAcceptable = false; |
| | | } |
| | | } |
| | | } |
| | | return isAcceptable; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isModifyAcceptable(ManagementContext context, |
| | | ManagedObject<?> managedObject, Collection<Message> unacceptableReasons) |
| | | throws AuthorizationException, CommunicationException { |
| | | // The same constraint applies as for adds. |
| | | return isAddAcceptable(context, managedObject, unacceptableReasons); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * The client-side constraint handler implementation which enforces |
| | | * referential integrity when aggregated managed objects are deleted |
| | | * or modified. |
| | | */ |
| | | private class TargetClientHandler extends ClientConstraintHandler { |
| | | |
| | | /** |
| | | * Instances of this class are used to search for all managed |
| | | * objects that contain a reference to the named managed object. |
| | | */ |
| | | private class Finder implements |
| | | RelationDefinitionVisitor<Void, ManagedObject<?>> { |
| | | |
| | | // Any authorization exceptions that were encountered. |
| | | private AuthorizationException ae = null; |
| | | |
| | | // Any communication exceptions that were encountered. |
| | | private CommunicationException ce = null; |
| | | |
| | | // The name of the managed object being deleted or modified. |
| | | private final String name; |
| | | |
| | | // The collected list of referencing managed objects. |
| | | private final Collection<ManagedObject<?>> references; |
| | | |
| | | |
| | | |
| | | // Private constructor. |
| | | private Finder(String name, Collection<ManagedObject<?>> references) { |
| | | this.name = name; |
| | | this.references = references; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Void visitInstantiable(InstantiableRelationDefinition<?, ?> rd, |
| | | ManagedObject<?> p) { |
| | | try { |
| | | for (String childName : p.listChildren(rd)) { |
| | | find(p.getChild(rd, childName)); |
| | | } |
| | | } catch (AuthorizationException e) { |
| | | ae = e; |
| | | } catch (CommunicationException e) { |
| | | ce = e; |
| | | } catch (OperationsException e) { |
| | | // Ignore all other types of exception. |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Void visitOptional(OptionalRelationDefinition<?, ?> rd, |
| | | ManagedObject<?> p) { |
| | | try { |
| | | find(p.getChild(rd)); |
| | | } catch (AuthorizationException e) { |
| | | ae = e; |
| | | } catch (CommunicationException e) { |
| | | ce = e; |
| | | } catch (OperationsException e) { |
| | | // Ignore all other types of exception. |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Void visitSingleton(SingletonRelationDefinition<?, ?> rd, |
| | | ManagedObject<?> p) { |
| | | try { |
| | | find(p.getChild(rd)); |
| | | } catch (AuthorizationException e) { |
| | | ae = e; |
| | | } catch (CommunicationException e) { |
| | | ce = e; |
| | | } catch (OperationsException e) { |
| | | // Ignore all other types of exception. |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | |
| | | |
| | | private void find(ManagedObject<?> current) |
| | | throws AuthorizationException, CommunicationException { |
| | | // First check the current managed object to see if it |
| | | // contains a reference. |
| | | ManagedObjectDefinition<?, ?> mod = current |
| | | .getManagedObjectDefinition(); |
| | | if (mod.isChildOf(getManagedObjectDefinition())) { |
| | | for (String value : current |
| | | .getPropertyValues(AggregationPropertyDefinition.this)) { |
| | | if (compare(value, name) == 0) { |
| | | references.add(current); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Now check its children. |
| | | for (RelationDefinition<?, ?> rd : mod.getAllRelationDefinitions()) { |
| | | rd.accept(this, current); |
| | | |
| | | if (ae != null) { |
| | | throw ae; |
| | | } |
| | | |
| | | if (ce != null) { |
| | | throw ce; |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isDeleteAcceptable(ManagementContext context, |
| | | ManagedObjectPath<?, ?> path, Collection<Message> unacceptableReasons) |
| | | throws AuthorizationException, CommunicationException { |
| | | // Any references to the deleted managed object should cause a |
| | | // constraint violation. |
| | | boolean isAcceptable = true; |
| | | for (ManagedObject<?> mo : findReferences(context, path.getName())) { |
| | | String name = mo.getManagedObjectPath().getName(); |
| | | if (name == null) { |
| | | Message msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITHOUT_NAME.get( |
| | | getName(), mo.getManagedObjectDefinition().getUserFriendlyName(), |
| | | getManagedObjectDefinition().getUserFriendlyName()); |
| | | unacceptableReasons.add(msg); |
| | | } else { |
| | | Message msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITH_NAME.get( |
| | | getName(), mo.getManagedObjectDefinition().getUserFriendlyName(), |
| | | name, getManagedObjectDefinition().getUserFriendlyName()); |
| | | unacceptableReasons.add(msg); |
| | | } |
| | | isAcceptable = false; |
| | | } |
| | | return isAcceptable; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isModifyAcceptable(ManagementContext context, |
| | | ManagedObject<?> managedObject, Collection<Message> unacceptableReasons) |
| | | throws AuthorizationException, CommunicationException { |
| | | // If the modified managed object is disabled and there are some |
| | | // active references then refuse the change. |
| | | BooleanPropertyDefinition tpd = getTargetEnabledPropertyDefinition(); |
| | | |
| | | // The referenced managed object cannot be disabled: always ok. |
| | | if (tpd == null) { |
| | | return true; |
| | | } |
| | | |
| | | // The referenced managed object is enabled: always ok. |
| | | if (managedObject.getPropertyValue(tpd)) { |
| | | return true; |
| | | } |
| | | |
| | | // The referenced managed object is disabled. Need to check for |
| | | // active references. |
| | | boolean isAcceptable = true; |
| | | for (ManagedObject<?> mo : findReferences(context, managedObject |
| | | .getManagedObjectPath().getName())) { |
| | | boolean needsEnabling = true; |
| | | for (BooleanPropertyDefinition spd : |
| | | getSourceEnabledPropertyDefinitions()) { |
| | | if (!mo.getPropertyValue(spd)) { |
| | | needsEnabling = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (needsEnabling) { |
| | | String name = mo.getManagedObjectPath().getName(); |
| | | if (name == null) { |
| | | Message msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITHOUT_NAME.get( |
| | | managedObject.getManagedObjectDefinition() |
| | | .getUserFriendlyName(), getName(), mo |
| | | .getManagedObjectDefinition().getUserFriendlyName()); |
| | | unacceptableReasons.add(msg); |
| | | } else { |
| | | Message msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITH_NAME.get( |
| | | managedObject.getManagedObjectDefinition() |
| | | .getUserFriendlyName(), getName(), mo |
| | | .getManagedObjectDefinition().getUserFriendlyName(), name); |
| | | unacceptableReasons.add(msg); |
| | | } |
| | | isAcceptable = false; |
| | | } |
| | | } |
| | | return isAcceptable; |
| | | } |
| | | |
| | | |
| | | |
| | | // Find all managed objects which reference the named managed |
| | | // object using this property. |
| | | private Collection<ManagedObject<?>> findReferences( |
| | | ManagementContext context, String name) throws AuthorizationException, |
| | | CommunicationException { |
| | | List<ManagedObject<?>> references = new LinkedList<ManagedObject<?>>(); |
| | | Finder finder = new Finder(name, references); |
| | | finder.find(context.getRootConfigurationManagedObject()); |
| | | return references; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates an aggregation property definition builder. |
| | | * |
| | | * @param <C> |
| | |
| | | * @return Returns the new aggregation property definition builder. |
| | | */ |
| | | public static <C extends ConfigurationClient, S extends Configuration> |
| | | Builder<C, S> createBuilder( |
| | | Builder<C, S> createBuilder( |
| | | AbstractManagedObjectDefinition<?, ?> d, String propertyName) { |
| | | return new Builder<C, S>(d, propertyName); |
| | | } |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | public Collection<ClientConstraintHandler> getClientConstraintHandlers() { |
| | | // TODO: not yet implemented. |
| | | return Collections.emptyList(); |
| | | ClientConstraintHandler handler = new SourceClientHandler(); |
| | | return Collections.singleton(handler); |
| | | } |
| | | |
| | | |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | public Collection<ServerConstraintHandler> getServerConstraintHandlers() { |
| | | ServerConstraintHandler handler = new ServerHandler(this); |
| | | ServerConstraintHandler handler = new ServerHandler(); |
| | | return Collections.singleton(handler); |
| | | } |
| | | |
| | |
| | | sourceEnabledProperties.add(BooleanPropertyDefinition.class.cast(pd)); |
| | | } |
| | | |
| | | d = relationDefinition.getChildDefinition(); |
| | | if (targetEnabledPropertyName == null) { |
| | | targetEnabledProperty = null; |
| | | } else { |
| | | PropertyDefinition<?> pd; |
| | | |
| | | d = relationDefinition.getChildDefinition(); |
| | | pd = d.getPropertyDefinition(targetEnabledPropertyName); |
| | | PropertyDefinition<?> pd = d |
| | | .getPropertyDefinition(targetEnabledPropertyName); |
| | | |
| | | // Runtime cast is required to workaround a |
| | | // bug in JDK versions prior to 1.5.0_08. |
| | | targetEnabledProperty = BooleanPropertyDefinition.class.cast(pd); |
| | | } |
| | | |
| | | // Register a client-side constraint with the referenced |
| | | // definition. This will be used to enforce referential integrity |
| | | // for actions performed against referenced managed objects. |
| | | Constraint constraint = new Constraint() { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Collection<ClientConstraintHandler> getClientConstraintHandlers() { |
| | | ClientConstraintHandler handler = new TargetClientHandler(); |
| | | return Collections.singleton(handler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Collection<ServerConstraintHandler> getServerConstraintHandlers() { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | }; |
| | | |
| | | d.registerConstraint(constraint); |
| | | } |
| | | |
| | | } |