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