001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2010 Sun Microsystems, Inc. 025 */ 026package org.forgerock.opendj.ldap.controls; 027 028import static com.forgerock.opendj.ldap.CoreMessages.ERR_PERMISSIVE_MODIFY_CONTROL_BAD_OID; 029import static com.forgerock.opendj.ldap.CoreMessages.ERR_PERMISSIVE_MODIFY_INVALID_CONTROL_VALUE; 030 031import org.forgerock.i18n.LocalizableMessage; 032import org.forgerock.opendj.ldap.ByteString; 033import org.forgerock.opendj.ldap.DecodeException; 034import org.forgerock.opendj.ldap.DecodeOptions; 035 036import org.forgerock.util.Reject; 037 038/** 039 * The Microsoft defined permissive modify request control. The OID for this 040 * control is 1.2.840.113556.1.4.1413, and it does not have a value. 041 * <p> 042 * This control can only be used with LDAP modify requests. It changes the 043 * behavior of the modify operation as follows: 044 * <ul> 045 * <li>Attempts to add an attribute value which already exists will be ignored 046 * and will not cause an 047 * {@link org.forgerock.opendj.ldap.ResultCode#ATTRIBUTE_OR_VALUE_EXISTS 048 * AttributeValueExists} error result to be returned. 049 * <li>Attempts to delete an attribute value which does not exist will be 050 * ignored and will not cause an 051 * {@link org.forgerock.opendj.ldap.ResultCode#NO_SUCH_ATTRIBUTE 052 * NoSuchAttribute} error result to be returned. 053 * </ul> 054 * In other words, a modify request {@code add} modification <i>ensures</i> that 055 * the attribute contains the specified attribute value, and a {@code delete} 056 * modification <i>ensures</i> that the attribute does not contain the specified 057 * attribute value. 058 * 059 * <pre> 060 * String groupDN = ...; 061 * String memberDN = ...; 062 * Connection connection = ...; 063 * 064 * // Add a member to a static group, telling the directory server not to 065 * // complain if the member already belongs to the group. 066 * ModifyRequest request = Requests.newModifyRequest(groupDN) 067 * .addControl(PermissiveModifyRequestControl.newControl(true)) 068 * .addModification(ModificationType.ADD, "member", memberDN); 069 * connection.modify(request); 070 * </pre> 071 */ 072public final class PermissiveModifyRequestControl implements Control { 073 /** 074 * The OID for the permissive modify request control. 075 */ 076 public static final String OID = "1.2.840.113556.1.4.1413"; 077 078 private static final PermissiveModifyRequestControl CRITICAL_INSTANCE = 079 new PermissiveModifyRequestControl(true); 080 081 private static final PermissiveModifyRequestControl NONCRITICAL_INSTANCE = 082 new PermissiveModifyRequestControl(false); 083 084 /** 085 * A decoder which can be used for decoding the permissive modify request 086 * control. 087 */ 088 public static final ControlDecoder<PermissiveModifyRequestControl> DECODER = 089 new ControlDecoder<PermissiveModifyRequestControl>() { 090 091 public PermissiveModifyRequestControl decodeControl(final Control control, 092 final DecodeOptions options) throws DecodeException { 093 Reject.ifNull(control); 094 095 if (control instanceof PermissiveModifyRequestControl) { 096 return (PermissiveModifyRequestControl) control; 097 } 098 099 if (!control.getOID().equals(OID)) { 100 final LocalizableMessage message = 101 ERR_PERMISSIVE_MODIFY_CONTROL_BAD_OID.get(control.getOID(), OID); 102 throw DecodeException.error(message); 103 } 104 105 if (control.hasValue()) { 106 final LocalizableMessage message = 107 ERR_PERMISSIVE_MODIFY_INVALID_CONTROL_VALUE.get(); 108 throw DecodeException.error(message); 109 } 110 111 return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE; 112 } 113 114 public String getOID() { 115 return OID; 116 } 117 }; 118 119 /** 120 * Creates a new permissive modify request control having the provided 121 * criticality. 122 * 123 * @param isCritical 124 * {@code true} if it is unacceptable to perform the operation 125 * without applying the semantics of this control, or 126 * {@code false} if it can be ignored. 127 * @return The new control. 128 */ 129 public static PermissiveModifyRequestControl newControl(final boolean isCritical) { 130 return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE; 131 } 132 133 private final boolean isCritical; 134 135 private PermissiveModifyRequestControl(final boolean isCritical) { 136 this.isCritical = isCritical; 137 } 138 139 /** {@inheritDoc} */ 140 public String getOID() { 141 return OID; 142 } 143 144 /** {@inheritDoc} */ 145 public ByteString getValue() { 146 return null; 147 } 148 149 /** {@inheritDoc} */ 150 public boolean hasValue() { 151 return false; 152 } 153 154 /** {@inheritDoc} */ 155 public boolean isCritical() { 156 return isCritical; 157 } 158 159 /** {@inheritDoc} */ 160 @Override 161 public String toString() { 162 final StringBuilder builder = new StringBuilder(); 163 builder.append("PermissiveModifyRequestControl(oid="); 164 builder.append(getOID()); 165 builder.append(", criticality="); 166 builder.append(isCritical()); 167 builder.append(")"); 168 return builder.toString(); 169 } 170 171}