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    }