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