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