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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.controls;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    
034    import org.opends.server.protocols.asn1.ASN1Element;
035    import org.opends.server.protocols.asn1.ASN1OctetString;
036    import org.opends.server.protocols.asn1.ASN1Sequence;
037    import org.opends.server.protocols.ldap.LDAPResultCode;
038    import org.opends.server.types.AttributeType;
039    import org.opends.server.types.AttributeValue;
040    import org.opends.server.types.Control;
041    import org.opends.server.types.DebugLogLevel;
042    import org.opends.server.types.LDAPException;
043    
044    import static org.opends.server.loggers.debug.DebugLogger.*;
045    import org.opends.server.loggers.debug.DebugTracer;
046    import static org.opends.messages.ProtocolMessages.*;
047    import static org.opends.server.util.ServerConstants.*;
048    import static org.opends.server.util.StaticUtils.*;
049    
050    
051    
052    /**
053     * This class implements the matched values control as defined in RFC 3876.  It
054     * may be included in a search request to indicate that only attribute values
055     * matching one or more filters contained in the matched values control should
056     * be returned to the client.
057     */
058    public class MatchedValuesControl
059           extends Control
060    {
061      /**
062       * The tracer object for the debug logger.
063       */
064      private static final DebugTracer TRACER = getTracer();
065    
066    
067    
068    
069      // The set of matched values filters for this control.
070      ArrayList<MatchedValuesFilter> filters;
071    
072    
073    
074      /**
075       * Creates a new matched values control using the default OID and the provided
076       * criticality and set of filters.
077       *
078       * @param  isCritical  Indicates whether this control should be considered
079       *                     critical to the operation processing.
080       * @param  filters     The set of filters to use to determine which values to
081       *                     return.
082       */
083      public MatchedValuesControl(boolean isCritical,
084                                  ArrayList<MatchedValuesFilter> filters)
085      {
086        super(OID_MATCHED_VALUES, isCritical, encodeValue(filters));
087    
088    
089        this.filters = filters;
090      }
091    
092    
093    
094      /**
095       * Creates a new matched values control using the default OID and the provided
096       * criticality and set of filters.
097       *
098       * @param  oid         The OID for this matched values control.
099       * @param  isCritical  Indicates whether this control should be considered
100       *                     critical to the operation processing.
101       * @param  filters     The set of filters to use to determine which values to
102       *                     return.
103       */
104      public MatchedValuesControl(String oid, boolean isCritical,
105                                  ArrayList<MatchedValuesFilter> filters)
106      {
107        super(oid, isCritical, encodeValue(filters));
108    
109    
110        this.filters = filters;
111      }
112    
113    
114    
115      /**
116       * Creates a new matched values control using the default OID and the provided
117       * criticality and set of filters.
118       *
119       * @param  oid           The OID for this matched values control.
120       * @param  isCritical    Indicates whether this control should be considered
121       *                       critical to the operation processing.
122       * @param  filters       The set of filters to use to determine which values
123       *                       to return.
124       * @param  encodedValue  The pre-encoded value for this matched values
125       *                       control.
126       */
127      private MatchedValuesControl(String oid, boolean isCritical,
128                                   ArrayList<MatchedValuesFilter> filters,
129                                   ASN1OctetString encodedValue)
130      {
131        super(oid, isCritical, encodedValue);
132    
133    
134        this.filters = filters;
135      }
136    
137    
138    
139      /**
140       * Encodes the provided information into an ASN.1 octet string suitable for
141       * use as the control value.
142       *
143       * @param  filters  The set of filters to include in the control value.
144       *
145       * @return  An ASN.1 octet string containing the encoded information.
146       */
147      private static ASN1OctetString
148                          encodeValue(ArrayList<MatchedValuesFilter> filters)
149      {
150        ArrayList<ASN1Element> elements =
151             new ArrayList<ASN1Element>(filters.size());
152        for (MatchedValuesFilter f : filters)
153        {
154          elements.add(f.encode());
155        }
156    
157    
158        return new ASN1OctetString(new ASN1Sequence(elements).encode());
159      }
160    
161    
162    
163      /**
164       * Creates a new matched values control from the contents of the provided
165       * control.
166       *
167       * @param  control  The generic control containing the information to use to
168       *                  create this matched values control.
169       *
170       * @return  The matched values control decoded from the provided control.
171       *
172       * @throws  LDAPException  If this control cannot be decoded as a valid
173       *                         matched values control.
174       */
175      public static MatchedValuesControl decodeControl(Control control)
176             throws LDAPException
177      {
178        if (! control.hasValue())
179        {
180          Message message = ERR_MATCHEDVALUES_NO_CONTROL_VALUE.get();
181          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
182        }
183    
184    
185        ArrayList<ASN1Element> elements;
186        try
187        {
188          elements =
189               ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
190        }
191        catch (Exception e)
192        {
193          if (debugEnabled())
194          {
195            TRACER.debugCaught(DebugLogLevel.ERROR, e);
196          }
197    
198          Message message = ERR_MATCHEDVALUES_CANNOT_DECODE_VALUE_AS_SEQUENCE.get(
199              getExceptionMessage(e));
200          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
201        }
202    
203    
204        if (elements.isEmpty())
205        {
206          Message message = ERR_MATCHEDVALUES_NO_FILTERS.get();
207          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
208        }
209    
210    
211        ArrayList<MatchedValuesFilter> filters =
212             new ArrayList<MatchedValuesFilter>(elements.size());
213        for (ASN1Element e : elements)
214        {
215          filters.add(MatchedValuesFilter.decode(e));
216        }
217    
218    
219        return new MatchedValuesControl(control.getOID(), control.isCritical(),
220                                        filters, control.getValue());
221      }
222    
223    
224    
225      /**
226       * Retrieves the set of filters associated with this matched values control.
227       *
228       * @return  The set of filters associated with this matched values control.
229       */
230      public ArrayList<MatchedValuesFilter> getFilters()
231      {
232        return filters;
233      }
234    
235    
236    
237      /**
238       * Indicates whether any of the filters associated with this matched values
239       * control matches the provided attribute type/value.
240       *
241       * @param  type   The attribute type with which the value is associated.
242       * @param  value  The attribute value for which to make the determination.
243       *
244       * @return  <CODE>true</CODE> if at least one of the filters associated with
245       *          this matched values control does match the provided attribute
246       *          value, or <CODE>false</CODE> if none of the filters match.
247       */
248      public boolean valueMatches(AttributeType type, AttributeValue value)
249      {
250        for (MatchedValuesFilter f : filters)
251        {
252          try
253          {
254            if (f.valueMatches(type, value))
255            {
256              return true;
257            }
258          }
259          catch (Exception e)
260          {
261            if (debugEnabled())
262            {
263              TRACER.debugCaught(DebugLogLevel.ERROR, e);
264            }
265          }
266        }
267    
268        return false;
269      }
270    
271    
272    
273      /**
274       * Retrieves a string representation of this authorization identity response
275       * control.
276       *
277       * @return  A string representation of this authorization identity response
278       *          control.
279       */
280      public String toString()
281      {
282        StringBuilder buffer = new StringBuilder();
283        toString(buffer);
284        return buffer.toString();
285      }
286    
287    
288    
289      /**
290       * Appends a string representation of this authorization identity response
291       * control to the provided buffer.
292       *
293       * @param  buffer  The buffer to which the information should be appended.
294       */
295      public void toString(StringBuilder buffer)
296      {
297        if (filters.size() == 1)
298        {
299          buffer.append("MatchedValuesControl(filter=\"");
300          filters.get(0).toString(buffer);
301          buffer.append("\")");
302        }
303        else
304        {
305          buffer.append("MatchedValuesControl(filters=\"(");
306    
307          for (MatchedValuesFilter f : filters)
308          {
309            f.toString(buffer);
310          }
311    
312          buffer.append(")\")");
313        }
314      }
315    }
316