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 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.controls; 028import org.forgerock.i18n.LocalizableMessage; 029 030 031 032import java.util.ArrayList; 033import java.io.IOException; 034 035import org.forgerock.opendj.io.*; 036import org.opends.server.types.*; 037import org.forgerock.opendj.ldap.ResultCode; 038import org.forgerock.opendj.ldap.ByteString; 039import org.forgerock.i18n.slf4j.LocalizedLogger; 040import static org.opends.messages.ProtocolMessages.*; 041import static org.opends.server.util.ServerConstants.*; 042import static org.opends.server.util.StaticUtils.*; 043 044 045 046/** 047 * This class implements the matched values control as defined in RFC 3876. It 048 * may be included in a search request to indicate that only attribute values 049 * matching one or more filters contained in the matched values control should 050 * be returned to the client. 051 */ 052public class MatchedValuesControl 053 extends Control 054{ 055 /** 056 * ControlDecoder implementation to decode this control from a ByteString. 057 */ 058 private static final class Decoder 059 implements ControlDecoder<MatchedValuesControl> 060 { 061 /** {@inheritDoc} */ 062 public MatchedValuesControl decode(boolean isCritical, ByteString value) 063 throws DirectoryException 064 { 065 ArrayList<MatchedValuesFilter> filters; 066 if (value == null) 067 { 068 LocalizableMessage message = ERR_MATCHEDVALUES_NO_CONTROL_VALUE.get(); 069 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 070 } 071 072 ASN1Reader reader = ASN1.getReader(value); 073 try 074 { 075 reader.readStartSequence(); 076 if (!reader.hasNextElement()) 077 { 078 LocalizableMessage message = ERR_MATCHEDVALUES_NO_FILTERS.get(); 079 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 080 } 081 082 filters = new ArrayList<>(); 083 while(reader.hasNextElement()) 084 { 085 filters.add(MatchedValuesFilter.decode(reader)); 086 } 087 reader.readEndSequence(); 088 } 089 catch (DirectoryException e) 090 { 091 throw e; 092 } 093 catch (Exception e) 094 { 095 logger.traceException(e); 096 097 LocalizableMessage message = ERR_MATCHEDVALUES_CANNOT_DECODE_VALUE_AS_SEQUENCE.get( 098 getExceptionMessage(e)); 099 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 100 } 101 102 return new MatchedValuesControl(isCritical,filters); 103 } 104 105 106 public String getOID() 107 { 108 return OID_MATCHED_VALUES; 109 } 110 111 } 112 113 /** 114 * The Control Decoder that can be used to decode this control. 115 */ 116 public static final ControlDecoder<MatchedValuesControl> DECODER = 117 new Decoder(); 118 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 119 120 121 122 123 /** The set of matched values filters for this control. */ 124 private final ArrayList<MatchedValuesFilter> filters; 125 126 127 128 /** 129 * Creates a new matched values control using the default OID and the provided 130 * criticality and set of filters. 131 * 132 * @param isCritical Indicates whether this control should be considered 133 * critical to the operation processing. 134 * @param filters The set of filters to use to determine which values to 135 * return. 136 */ 137 public MatchedValuesControl(boolean isCritical, 138 ArrayList<MatchedValuesFilter> filters) 139 { 140 super(OID_MATCHED_VALUES, isCritical); 141 142 143 this.filters = filters; 144 } 145 146 147 148 /** 149 * Writes this control's value to an ASN.1 writer. The value (if any) must be 150 * written as an ASN1OctetString. 151 * 152 * @param writer The ASN.1 output stream to write to. 153 * @throws IOException If a problem occurs while writing to the stream. 154 */ 155 @Override 156 public void writeValue(ASN1Writer writer) throws IOException { 157 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 158 159 writer.writeStartSequence(); 160 for (MatchedValuesFilter f : filters) 161 { 162 f.encode(writer); 163 } 164 writer.writeEndSequence(); 165 166 writer.writeEndSequence(); 167 } 168 169 170 /** 171 * Retrieves the set of filters associated with this matched values control. 172 * 173 * @return The set of filters associated with this matched values control. 174 */ 175 public ArrayList<MatchedValuesFilter> getFilters() 176 { 177 return filters; 178 } 179 180 181 182 /** 183 * Indicates whether any of the filters associated with this matched values 184 * control matches the provided attribute type/value. 185 * 186 * @param type The attribute type with which the value is associated. 187 * @param value The attribute value for which to make the determination. 188 * 189 * @return <CODE>true</CODE> if at least one of the filters associated with 190 * this matched values control does match the provided attribute 191 * value, or <CODE>false</CODE> if none of the filters match. 192 */ 193 public boolean valueMatches(AttributeType type, ByteString value) 194 { 195 for (MatchedValuesFilter f : filters) 196 { 197 try 198 { 199 if (f.valueMatches(type, value)) 200 { 201 return true; 202 } 203 } 204 catch (Exception e) 205 { 206 logger.traceException(e); 207 } 208 } 209 210 return false; 211 } 212 213 214 215 /** 216 * Appends a string representation of this authorization identity response 217 * control to the provided buffer. 218 * 219 * @param buffer The buffer to which the information should be appended. 220 */ 221 @Override 222 public void toString(StringBuilder buffer) 223 { 224 if (filters.size() == 1) 225 { 226 buffer.append("MatchedValuesControl(filter=\""); 227 filters.get(0).toString(buffer); 228 buffer.append("\")"); 229 } 230 else 231 { 232 buffer.append("MatchedValuesControl(filters=\"("); 233 234 for (MatchedValuesFilter f : filters) 235 { 236 f.toString(buffer); 237 } 238 239 buffer.append(")\")"); 240 } 241 } 242} 243