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