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 2006-2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS
026 */
027package org.opends.server.controls;
028
029import static org.opends.messages.ProtocolMessages.*;
030
031import java.util.HashSet;
032import java.util.Iterator;
033import java.util.Set;
034
035import org.forgerock.i18n.LocalizableMessage;
036import org.opends.server.protocols.ldap.LDAPResultCode;
037import org.opends.server.types.LDAPException;
038
039/**
040 * This enumeration defines the set of possible change types that may be used in
041 * conjunction with the persistent search control, as defined in
042 * draft-ietf-ldapext-psearch.
043 * <p>
044 * It is a different type from {@link ChangeOperationType} to enforce type
045 * safety, despite mirroring it completely.
046 */
047public enum PersistentSearchChangeType
048{
049  /** The change type that will be used for add operations. */
050  ADD(1),
051
052  /** The change type that will be used for delete operations. */
053  DELETE(2),
054
055  /** The change type that will be used for modify operations. */
056  MODIFY(4),
057
058  /** The change type that will be used for modify DN operations. */
059  MODIFY_DN(8);
060
061
062
063  /** The integer value associated with this change type. */
064  private int intValue;
065
066  /**
067   * Creates a new instance of a persistent search change type with the provided
068   * integer value.
069   *
070   * @param  intValue  The integer value associated with this change type.
071   */
072  private PersistentSearchChangeType(int intValue)
073  {
074    this.intValue = intValue;
075  }
076
077
078
079  /**
080   * Retrieves the integer value associated with this change type.
081   *
082   * @return  The integer value associated with this change type.
083   */
084  public int intValue()
085  {
086    return intValue;
087  }
088
089
090
091  /**
092   * Retrieves a string representation of this persistent search change type.
093   *
094   * @return  A string representation of this persistent search change type, or
095   *          "unknown" if it has an unknown type.
096   */
097  @Override
098  public String toString()
099  {
100    switch (intValue)
101    {
102      case 1:
103        return "add";
104      case 2:
105        return "delete";
106      case 4:
107        return "modify";
108      case 8:
109        return "modDN";
110      default:
111        return "unknown";
112    }
113  }
114
115
116
117  /**
118   * Retrieves the change type associated with the provided integer value.
119   *
120   * @param  intValue  The integer value to decode as a change type.
121   *
122   * @return  The change type corresponding to the provided integer value.
123   *
124   * @throws  LDAPException  If the provided integer value is not associated
125   *                         with a valid change type.
126   */
127  public static PersistentSearchChangeType valueOf(int intValue)
128         throws LDAPException
129  {
130    switch (intValue)
131    {
132      case 1:
133        return ADD;
134      case 2:
135        return DELETE;
136      case 4:
137        return MODIFY;
138      case 8:
139        return MODIFY_DN;
140      default:
141        LocalizableMessage message = ERR_PSEARCH_CHANGETYPES_INVALID_TYPE.get(intValue);
142        throw new LDAPException(LDAPResultCode.CONSTRAINT_VIOLATION, message);
143    }
144  }
145
146
147
148  /**
149   * Decodes the provided int value into a set of change types as per the
150   * specification in draft-ietf-ldapext-psearch.
151   *
152   * @param  intValue  The integer value representing the encoded change types.
153   *
154   * @return  The set of change types decoded from the provided integer value.
155   *
156   * @throws  LDAPException  If the provided integer value does not represent a
157   *                         valid encoded set of change types.
158   */
159  public static Set<PersistentSearchChangeType> intToTypes(int intValue)
160         throws LDAPException
161  {
162    Set<PersistentSearchChangeType> changeTypes = new HashSet<>(4);
163
164    switch (intValue)
165    {
166      case 0:
167        // No change types are included.  This won't be allowed because it
168        // doesn't make any sense.
169        LocalizableMessage message = ERR_PSEARCH_CHANGETYPES_NO_TYPES.get();
170        throw new LDAPException(LDAPResultCode.CONSTRAINT_VIOLATION, message);
171      case 1:
172        changeTypes.add(ADD);
173        break;
174      case 2:
175        changeTypes.add(DELETE);
176        break;
177      case 3:
178        changeTypes.add(ADD);
179        changeTypes.add(DELETE);
180        break;
181      case 4:
182        changeTypes.add(MODIFY);
183        break;
184      case 5:
185        changeTypes.add(ADD);
186        changeTypes.add(MODIFY);
187        break;
188      case 6:
189        changeTypes.add(DELETE);
190        changeTypes.add(MODIFY);
191        break;
192      case 7:
193        changeTypes.add(ADD);
194        changeTypes.add(DELETE);
195        changeTypes.add(MODIFY);
196        break;
197      case 8:
198        changeTypes.add(MODIFY_DN);
199        break;
200      case 9:
201        changeTypes.add(ADD);
202        changeTypes.add(MODIFY_DN);
203        break;
204      case 10:
205        changeTypes.add(DELETE);
206        changeTypes.add(MODIFY_DN);
207        break;
208      case 11:
209        changeTypes.add(ADD);
210        changeTypes.add(DELETE);
211        changeTypes.add(MODIFY_DN);
212        break;
213      case 12:
214        changeTypes.add(MODIFY);
215        changeTypes.add(MODIFY_DN);
216        break;
217      case 13:
218        changeTypes.add(ADD);
219        changeTypes.add(MODIFY);
220        changeTypes.add(MODIFY_DN);
221        break;
222      case 14:
223        changeTypes.add(DELETE);
224        changeTypes.add(MODIFY);
225        changeTypes.add(MODIFY_DN);
226        break;
227      case 15:
228        changeTypes.add(ADD);
229        changeTypes.add(DELETE);
230        changeTypes.add(MODIFY);
231        changeTypes.add(MODIFY_DN);
232        break;
233     default:
234        message = ERR_PSEARCH_CHANGETYPES_INVALID_TYPES.get(intValue);
235        throw new LDAPException(LDAPResultCode.CONSTRAINT_VIOLATION, message);
236    }
237
238    return changeTypes;
239  }
240
241
242
243  /**
244   * Retrieves the integer representation of the provided set of change types.
245   *
246   * @param  changeTypes  The set of change types to be encoded.
247   *
248   * @return  The integer representation of the provided set of change types.
249   */
250  public static int changeTypesToInt(Set<PersistentSearchChangeType>
251                                          changeTypes)
252  {
253    int intValue = 0;
254
255    if (changeTypes.contains(ADD))
256    {
257      intValue |= 1;
258    }
259
260    if (changeTypes.contains(DELETE))
261    {
262      intValue |= 2;
263    }
264
265    if (changeTypes.contains(MODIFY))
266    {
267      intValue |= 4;
268    }
269
270    if (changeTypes.contains(MODIFY_DN))
271    {
272      intValue |= 8;
273    }
274
275    return intValue;
276  }
277
278
279
280  /**
281   * Retrieves a string representation of the provided set of change types.
282   *
283   * @param  changeTypes  The set of change types to encode.
284   *
285   * @return  A string representation of the provided set of change types.
286   */
287  public static String changeTypesToString(Set<PersistentSearchChangeType>
288                                                changeTypes)
289  {
290    StringBuilder buffer = new StringBuilder();
291    changeTypesToString(changeTypes, buffer);
292    return buffer.toString();
293  }
294
295
296
297  /**
298   * Appends a string representation of the specified set of change types to the
299   * provided buffer.
300   *
301   * @param  changeTypes  The set of change types to encode.
302   * @param  buffer       The buffer to which the information should be written.
303   */
304  public static void changeTypesToString(Set<PersistentSearchChangeType>
305                                              changeTypes,
306                                         StringBuilder buffer)
307  {
308    Iterator<PersistentSearchChangeType> iterator = changeTypes.iterator();
309    if (iterator.hasNext())
310    {
311      buffer.append(iterator.next());
312
313      while (iterator.hasNext())
314      {
315        buffer.append("|");
316        buffer.append(iterator.next());
317      }
318    }
319  }
320}
321