001 /* 002 * Copyright 2012-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2015 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025 import java.util.ArrayList; 026 import java.util.Arrays; 027 import java.util.Collection; 028 import java.util.Collections; 029 import java.util.EnumSet; 030 import java.util.Iterator; 031 import java.util.Set; 032 033 import com.unboundid.asn1.ASN1Element; 034 import com.unboundid.asn1.ASN1Enumerated; 035 import com.unboundid.asn1.ASN1OctetString; 036 import com.unboundid.asn1.ASN1Sequence; 037 import com.unboundid.ldap.sdk.Control; 038 import com.unboundid.ldap.sdk.LDAPException; 039 import com.unboundid.ldap.sdk.ResultCode; 040 import com.unboundid.util.Debug; 041 import com.unboundid.util.NotMutable; 042 import com.unboundid.util.StaticUtils; 043 import com.unboundid.util.ThreadSafety; 044 import com.unboundid.util.ThreadSafetyLevel; 045 import com.unboundid.util.Validator; 046 047 import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 048 049 050 051 /** 052 * <BLOCKQUOTE> 053 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 054 * LDAP SDK for Java. It is not available for use in applications that 055 * include only the Standard Edition of the LDAP SDK, and is not supported for 056 * use in conjunction with non-UnboundID products. 057 * </BLOCKQUOTE> 058 * This class provides an implementation of a control that can be used to 059 * indicate that the server should suppress the update to one or more 060 * operational attributes for the associated request. 061 * <BR><BR> 062 * The request control has an OID of 1.3.6.1.4.1.30221.2.5.27, and the 063 * criticality may be either {@code true} or {@code false}. The control must 064 * have a value with the following encoding: 065 * <PRE> 066 * SuppressOperationalAttributeUpdateRequestValue ::= SEQUENCE { 067 * suppressTypes [0] SEQUENCE OF ENUMERATED { 068 * last-access-time (0), 069 * last-login-time (1), 070 * last-login-ip (2), 071 * lastmod (3), 072 * ... }, 073 * ... } 074 * </PRE> 075 */ 076 @NotMutable() 077 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 078 public final class SuppressOperationalAttributeUpdateRequestControl 079 extends Control 080 { 081 /** 082 * The OID (1.3.6.1.4.1.30221.2.5.27) for the suppress operational attribute 083 * update request control. 084 */ 085 public static final String SUPPRESS_OP_ATTR_UPDATE_REQUEST_OID = 086 "1.3.6.1.4.1.30221.2.5.27"; 087 088 089 090 /** 091 * The BER type to use for the set of suppress types. 092 */ 093 private static final byte TYPE_SUPPRESS_TYPES = (byte) 0x80; 094 095 096 /** 097 * The serial version UID for this serializable class. 098 */ 099 private static final long serialVersionUID = 4603958484615351672L; 100 101 102 103 // The set of suppress types to include in the control. 104 private final Set<SuppressType> suppressTypes; 105 106 107 108 /** 109 * Creates a new instance of this control that will suppress updates to the 110 * specified kinds of operational attributes. It will not be critical. 111 * 112 * @param suppressTypes The set of suppress types to include in the control. 113 * It must not be {@code null} or empty. 114 */ 115 public SuppressOperationalAttributeUpdateRequestControl( 116 final SuppressType... suppressTypes) 117 { 118 this(false, suppressTypes); 119 } 120 121 122 123 /** 124 * Creates a new instance of this control that will suppress updates to the 125 * specified kinds of operational attributes. It will not be critical. 126 * 127 * @param suppressTypes The set of suppress types to include in the control. 128 * It must not be {@code null} or empty. 129 */ 130 public SuppressOperationalAttributeUpdateRequestControl( 131 final Collection<SuppressType> suppressTypes) 132 { 133 this(false, suppressTypes); 134 } 135 136 137 138 /** 139 * Creates a new instance of this control that will suppress updates to the 140 * specified kinds of operational attributes. 141 * 142 * @param isCritical Indicates whether the control should be considered 143 * critical. 144 * @param suppressTypes The set of suppress types to include in the control. 145 * It must not be {@code null} or empty. 146 */ 147 public SuppressOperationalAttributeUpdateRequestControl( 148 final boolean isCritical, final SuppressType... suppressTypes) 149 { 150 this(isCritical, Arrays.asList(suppressTypes)); 151 } 152 153 154 155 /** 156 * Creates a new instance of this control that will suppress updates to the 157 * specified kinds of operational attributes. 158 * 159 * @param isCritical Indicates whether the control should be considered 160 * critical. 161 * @param suppressTypes The set of suppress types to include in the control. 162 * It must not be {@code null} or empty. 163 */ 164 public SuppressOperationalAttributeUpdateRequestControl( 165 final boolean isCritical, 166 final Collection<SuppressType> suppressTypes) 167 { 168 super(SUPPRESS_OP_ATTR_UPDATE_REQUEST_OID, isCritical, 169 encodeValue(suppressTypes)); 170 171 Validator.ensureFalse(suppressTypes.isEmpty()); 172 173 final EnumSet<SuppressType> s = EnumSet.noneOf(SuppressType.class); 174 for (final SuppressType t : suppressTypes) 175 { 176 s.add(t); 177 } 178 179 this.suppressTypes = Collections.unmodifiableSet(s); 180 } 181 182 183 184 /** 185 * Decodes the provided generic control as a suppress operational attribute 186 * update request control. 187 * 188 * @param control The generic control to be decoded as a suppress 189 * operational attribute update request control. 190 * 191 * @throws LDAPException If a problem is encountered while attempting to 192 * decode the provided control. 193 */ 194 public SuppressOperationalAttributeUpdateRequestControl(final Control control) 195 throws LDAPException 196 { 197 super(control); 198 199 final ASN1OctetString value = control.getValue(); 200 if (value == null) 201 { 202 throw new LDAPException(ResultCode.DECODING_ERROR, 203 ERR_SUPPRESS_OP_ATTR_UPDATE_REQUEST_MISSING_VALUE.get()); 204 } 205 206 try 207 { 208 final ASN1Sequence valueSequence = 209 ASN1Sequence.decodeAsSequence(value.getValue()); 210 final ASN1Sequence suppressTypesSequence = 211 ASN1Sequence.decodeAsSequence(valueSequence.elements()[0]); 212 213 final EnumSet<SuppressType> s = EnumSet.noneOf(SuppressType.class); 214 for (final ASN1Element e : suppressTypesSequence.elements()) 215 { 216 final ASN1Enumerated ae = ASN1Enumerated.decodeAsEnumerated(e); 217 final SuppressType t = SuppressType.valueOf(ae.intValue()); 218 if (t == null) 219 { 220 throw new LDAPException(ResultCode.DECODING_ERROR, 221 ERR_SUPPRESS_OP_ATTR_UNRECOGNIZED_SUPPRESS_TYPE.get( 222 ae.intValue())); 223 } 224 else 225 { 226 s.add(t); 227 } 228 } 229 230 suppressTypes = Collections.unmodifiableSet(s); 231 } 232 catch (final LDAPException le) 233 { 234 Debug.debugException(le); 235 throw le; 236 } 237 catch (final Exception e) 238 { 239 Debug.debugException(e); 240 throw new LDAPException(ResultCode.DECODING_ERROR, 241 ERR_SUPPRESS_OP_ATTR_UPDATE_REQUEST_CANNOT_DECODE.get( 242 StaticUtils.getExceptionMessage(e)), 243 e); 244 } 245 } 246 247 248 249 /** 250 * Encodes the provided information into an octet string suitable for use as 251 * the value of this control. 252 * 253 * @param suppressTypes The set of suppress types to include in the control. 254 * It must not be {@code null} or empty. 255 * 256 * @return The ASN.1 octet string containing the encoded value. 257 */ 258 private static ASN1OctetString encodeValue( 259 final Collection<SuppressType> suppressTypes) 260 { 261 final ArrayList<ASN1Element> suppressTypeElements = 262 new ArrayList<ASN1Element>(suppressTypes.size()); 263 for (final SuppressType t : suppressTypes) 264 { 265 suppressTypeElements.add(new ASN1Enumerated(t.intValue())); 266 } 267 268 final ASN1Sequence valueSequence = new ASN1Sequence( 269 new ASN1Sequence(TYPE_SUPPRESS_TYPES, suppressTypeElements)); 270 return new ASN1OctetString(valueSequence.encode()); 271 } 272 273 274 275 /** 276 * Retrieves the set of suppress types for this control. 277 * 278 * @return The set of suppress types for this control. 279 */ 280 public Set<SuppressType> getSuppressTypes() 281 { 282 return suppressTypes; 283 } 284 285 286 287 /** 288 * {@inheritDoc} 289 */ 290 @Override() 291 public String getControlName() 292 { 293 return INFO_CONTROL_NAME_SUPPRESS_OP_ATTR_UPDATE_REQUEST.get(); 294 } 295 296 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override() 302 public void toString(final StringBuilder buffer) 303 { 304 buffer.append("SuppressOperationalAttributeUpdateRequestControl(" + 305 "isCritical="); 306 buffer.append(isCritical()); 307 buffer.append(", suppressTypes={"); 308 309 final Iterator<SuppressType> iterator = suppressTypes.iterator(); 310 while (iterator.hasNext()) 311 { 312 buffer.append(iterator.next().name()); 313 if (iterator.hasNext()) 314 { 315 buffer.append(','); 316 } 317 } 318 319 buffer.append("})"); 320 } 321 }