001    /*
002     * Copyright 2011-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.extensions;
022    
023    
024    
025    import java.util.ArrayList;
026    import java.util.Collection;
027    import java.util.Collections;
028    import java.util.Iterator;
029    import java.util.List;
030    
031    import com.unboundid.asn1.ASN1Boolean;
032    import com.unboundid.asn1.ASN1Element;
033    import com.unboundid.asn1.ASN1OctetString;
034    import com.unboundid.asn1.ASN1Sequence;
035    import com.unboundid.ldap.sdk.LDAPException;
036    import com.unboundid.ldap.sdk.ResultCode;
037    import com.unboundid.util.Debug;
038    import com.unboundid.util.NotMutable;
039    import com.unboundid.util.StaticUtils;
040    import com.unboundid.util.ThreadSafety;
041    import com.unboundid.util.ThreadSafetyLevel;
042    import com.unboundid.util.Validator;
043    
044    import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
045    
046    
047    
048    /**
049     * <BLOCKQUOTE>
050     *   <B>NOTE:</B>  This class is part of the Commercial Edition of the UnboundID
051     *   LDAP SDK for Java.  It is not available for use in applications that
052     *   include only the Standard Edition of the LDAP SDK, and is not supported for
053     *   use in conjunction with non-UnboundID products.
054     * </BLOCKQUOTE>
055     * This class provides an implementation of a get changelog batch change
056     * selection criteria value that indicates that the server should not return
057     * changes which target only the specified attributes.  This can be useful for
058     * ignoring changes to attributes which are changed frequently but not of
059     * interest to the client.  Note that changes returned may include changes to
060     * these attributes, but only if the change targets other attributes that should
061     * not be ignored.
062     */
063    @NotMutable()
064    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
065    public final class IgnoreAttributesChangeSelectionCriteria
066           extends ChangelogBatchChangeSelectionCriteria
067    {
068      /**
069       * The inner BER type that should be used for encoded elements that represent
070       * an ignore attributes get changelog batch selection criteria value.
071       */
072      static final byte TYPE_SELECTION_CRITERIA_IGNORE_ATTRIBUTES = (byte) 0xA3;
073    
074    
075    
076      // Indicates whether to automatically consider all operational attributes in
077      // the ignore list.
078      private final boolean ignoreOperationalAttributes;
079    
080      // The names of the attributes to ignore.
081      private final List<String> attributeNames;
082    
083    
084    
085      /**
086       * Creates a new ignore attributes change selection criteria value with the
087       * provided information.
088       *
089       * @param  ignoreOperationalAttributes  Indicates whether to automatically
090       *                                      include all operational attributes in
091       *                                      the set of attributes to ignore.
092       * @param  attributeNames               The names of the attributes to ignore.
093       *                                      It may be {@code null} or empty only
094       *                                      if
095       *                                      {@code ignoreOperationalAttributes}
096       *                                      is {@code true} and no user attributes
097       *                                      changes should be ignored.
098       */
099      public IgnoreAttributesChangeSelectionCriteria(
100                  final boolean ignoreOperationalAttributes,
101                  final String... attributeNames)
102      {
103        this(ignoreOperationalAttributes, StaticUtils.toList(attributeNames));
104      }
105    
106    
107    
108      /**
109       * Creates a new ignore attributes change selection criteria value with the
110       * provided information.
111       *
112       * @param  ignoreOperationalAttributes  Indicates whether to automatically
113       *                                      include all operational attributes in
114       *                                      the set of attributes to ignore.
115       * @param  attributeNames               The names of the attributes to ignore.
116       *                                      It may be {@code null} or empty only
117       *                                      if
118       *                                      {@code ignoreOperationalAttributes}
119       *                                      is {@code true} and no user attributes
120       *                                      changes should be ignored.
121       */
122      public IgnoreAttributesChangeSelectionCriteria(
123                  final boolean ignoreOperationalAttributes,
124                  final Collection<String> attributeNames)
125      {
126        if ((attributeNames == null) || attributeNames.isEmpty())
127        {
128          Validator.ensureTrue(ignoreOperationalAttributes);
129          this.attributeNames = Collections.emptyList();
130        }
131        else
132        {
133          this.attributeNames =
134               Collections.unmodifiableList(new ArrayList<String>(attributeNames));
135        }
136    
137        this.ignoreOperationalAttributes = ignoreOperationalAttributes;
138      }
139    
140    
141    
142      /**
143       * Decodes the provided ASN.1 element, which is the inner element of a
144       * changelog batch change selection criteria element, as an all attributes
145       * change selection criteria value.
146       *
147       * @param  innerElement  The inner element of a changelog batch change
148       *                       selection criteria element to be decoded.
149       *
150       * @return  The decoded all attributes change selection criteria value.
151       *
152       * @throws  LDAPException  If a problem is encountered while trying to decode
153       *                         the provided element as the inner element of an all
154       *                         attributes change selection criteria value.
155       */
156      static IgnoreAttributesChangeSelectionCriteria decodeInnerElement(
157                  final ASN1Element innerElement)
158             throws LDAPException
159      {
160        try
161        {
162          final ASN1Element[] elements =
163               ASN1Sequence.decodeAsSequence(innerElement).elements();
164          final ASN1Element[] attrElements =
165               ASN1Sequence.decodeAsSequence(elements[0]).elements();
166          final ArrayList<String> attrNames =
167               new ArrayList<String>(attrElements.length);
168          for (final ASN1Element e : attrElements)
169          {
170            attrNames.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
171          }
172    
173          return new IgnoreAttributesChangeSelectionCriteria(
174               ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue(),
175               attrNames);
176        }
177        catch (final Exception e)
178        {
179          Debug.debugException(e);
180          throw new LDAPException(ResultCode.DECODING_ERROR,
181               ERR_IGNORE_ATTRS_CHANGE_SELECTION_CRITERIA_DECODE_ERROR.get(
182                    StaticUtils.getExceptionMessage(e)),
183               e);
184        }
185      }
186    
187    
188    
189      /**
190       * Indicates whether to automatically include all operational attributes in
191       * the set of attributes to ignore.
192       *
193       * @return  {@code true} if all operational attributes should automatically be
194       *          included in the set of attributes to ignore, or {@code false} if
195       *          only those operational attributes which are explicitly named
196       *          should be ignored.
197       */
198      public boolean ignoreOperationalAttributes()
199      {
200        return ignoreOperationalAttributes;
201      }
202    
203    
204    
205      /**
206       * Retrieves the names of the target attributes for changes that should be
207       * retrieved.
208       *
209       * @return  The names of the target attributes for changes that should be
210       *          retrieved.
211       */
212      public List<String> getAttributeNames()
213      {
214        return attributeNames;
215      }
216    
217    
218    
219      /**
220       * {@inheritDoc}
221       */
222      @Override()
223      public ASN1Element encodeInnerElement()
224      {
225        final ArrayList<ASN1Element> attrNameElements =
226             new ArrayList<ASN1Element>(attributeNames.size());
227        for (final String s : attributeNames)
228        {
229          attrNameElements.add(new ASN1OctetString(s));
230        }
231    
232        return new ASN1Sequence(TYPE_SELECTION_CRITERIA_IGNORE_ATTRIBUTES,
233             new ASN1Sequence(attrNameElements),
234             new ASN1Boolean(ignoreOperationalAttributes));
235      }
236    
237    
238    
239      /**
240       * {@inheritDoc}
241       */
242      @Override()
243      public void toString(final StringBuilder buffer)
244      {
245        buffer.append("IgnoreAttributesChangeSelectionCriteria(attributeNames={");
246    
247        final Iterator<String> iterator = attributeNames.iterator();
248        while (iterator.hasNext())
249        {
250          buffer.append(iterator.next());
251          if (iterator.hasNext())
252          {
253            buffer.append(',');
254          }
255        }
256    
257        buffer.append("}, ignoreOperationalAttributes=");
258        buffer.append(ignoreOperationalAttributes);
259        buffer.append(')');
260      }
261    }