001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.codec.search; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025 026import org.apache.directory.api.asn1.EncoderException; 027import org.apache.directory.api.asn1.ber.tlv.BerValue; 028import org.apache.directory.api.asn1.ber.tlv.TLV; 029import org.apache.directory.api.i18n.I18n; 030import org.apache.directory.api.ldap.codec.api.LdapCodecConstants; 031import org.apache.directory.api.util.Strings; 032 033 034/** 035 * The search request filter Matching Rule assertion 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 */ 039public class ExtensibleMatchFilter extends Filter 040{ 041 /** The expected lenth of the Matching Rule Assertion */ 042 private int expectedMatchingRuleLength; 043 044 /** Matching rule */ 045 private String matchingRule; 046 047 /** Matching rule bytes */ 048 private byte[] matchingRuleBytes; 049 050 /** Matching rule type */ 051 private String type; 052 053 private byte[] typeBytes; 054 055 /** Matching rule value */ 056 private org.apache.directory.api.ldap.model.entry.Value<?> matchValue; 057 058 /** The dnAttributes flag */ 059 private boolean dnAttributes = false; 060 061 /** The extensible match length */ 062 private int extensibleMatchLength; 063 064 065 /** 066 * Creates a new ExtensibleMatchFilter object. The dnAttributes flag 067 * defaults to false. 068 * 069 * @param tlvId The TLV identifier 070 */ 071 public ExtensibleMatchFilter( int tlvId ) 072 { 073 super( tlvId ); 074 } 075 076 077 /** 078 * Creates a new ExtensibleMatchFilter object. The dnAttributes flag 079 * defaults to false. 080 */ 081 public ExtensibleMatchFilter() 082 { 083 super(); 084 } 085 086 087 /** 088 * Get the dnAttributes flag 089 * 090 * @return Returns the dnAttributes. 091 */ 092 public boolean isDnAttributes() 093 { 094 return dnAttributes; 095 } 096 097 098 /** 099 * Set the dnAttributes flag 100 * 101 * @param dnAttributes The dnAttributes to set. 102 */ 103 public void setDnAttributes( boolean dnAttributes ) 104 { 105 this.dnAttributes = dnAttributes; 106 } 107 108 109 /** 110 * Get the matchingRule 111 * 112 * @return Returns the matchingRule. 113 */ 114 public String getMatchingRule() 115 { 116 return matchingRule; 117 } 118 119 120 /** 121 * Set the matchingRule 122 * 123 * @param matchingRule The matchingRule to set. 124 */ 125 public void setMatchingRule( String matchingRule ) 126 { 127 this.matchingRule = matchingRule; 128 } 129 130 131 /** 132 * Get the matchValue 133 * 134 * @return Returns the matchValue. 135 */ 136 public org.apache.directory.api.ldap.model.entry.Value<?> getMatchValue() 137 { 138 return matchValue; 139 } 140 141 142 /** 143 * Set the matchValue 144 * 145 * @param matchValue The matchValue to set. 146 */ 147 public void setMatchValue( org.apache.directory.api.ldap.model.entry.Value<?> matchValue ) 148 { 149 this.matchValue = matchValue; 150 } 151 152 153 /** 154 * Get the type 155 * 156 * @return Returns the type. 157 */ 158 public String getType() 159 { 160 return type; 161 } 162 163 164 /** 165 * Set the type 166 * 167 * @param type The type to set. 168 */ 169 public void setType( String type ) 170 { 171 this.type = type; 172 } 173 174 175 /** 176 * get the expectedMatchingRuleLength 177 * 178 * @return Returns the expectedMatchingRuleLength. 179 */ 180 public int getExpectedMatchingRuleLength() 181 { 182 return expectedMatchingRuleLength; 183 } 184 185 186 /** 187 * Set the expectedMatchingRuleLength 188 * 189 * @param expectedMatchingRuleLength The expectedMatchingRuleLength to set. 190 */ 191 public void setExpectedMatchingRuleLength( int expectedMatchingRuleLength ) 192 { 193 this.expectedMatchingRuleLength = expectedMatchingRuleLength; 194 } 195 196 197 /** 198 * Compute the ExtensibleMatchFilter length 199 * <br> 200 * ExtensibleMatchFilter : 201 * <pre> 202 * 0xA9 L1 203 * | 204 * [+--> 0x81 L3 matchingRule] 205 * [+--> 0x82 L4 type] 206 * [+--> 0x83 L5 matchValue] 207 * [+--> 0x01 0x01 dnAttributes] 208 * </pre> 209 * 210 * @return The encoded length 211 */ 212 @Override 213 public int computeLength() 214 { 215 if ( matchingRule != null ) 216 { 217 matchingRuleBytes = Strings.getBytesUtf8( matchingRule ); 218 extensibleMatchLength = 1 + TLV.getNbBytes( matchingRuleBytes.length ) + matchingRuleBytes.length; 219 } 220 221 if ( type != null ) 222 { 223 typeBytes = Strings.getBytesUtf8( type ); 224 extensibleMatchLength += 1 + TLV.getNbBytes( typeBytes.length ) + typeBytes.length; 225 } 226 227 if ( matchValue != null ) 228 { 229 int bytesLength = matchValue.getBytes().length; 230 extensibleMatchLength += 1 + TLV.getNbBytes( bytesLength ) + bytesLength; 231 } 232 233 if ( dnAttributes ) 234 { 235 extensibleMatchLength += 1 + 1 + 1; 236 } 237 238 return 1 + TLV.getNbBytes( extensibleMatchLength ) + extensibleMatchLength; 239 } 240 241 242 /** 243 * Encode the ExtensibleMatch Filters to a PDU. 244 * <br> 245 * ExtensibleMatch filter : 246 * <pre> 247 * 0xA9 LL 248 * | 0x81 LL matchingRule 249 * | / | 0x82 LL Type 250 * | / | /0x83 LL matchValue 251 * +--+ +-+ 252 * | \ \ 253 * | \ 0x83 LL MatchValue 254 * | 0x82 LL type 255 * | 0x83 LL matchValue 256 * +--[0x84 0x01 dnAttributes] 257 * </pre> 258 * 259 * @param buffer The buffer where to put the PDU 260 * @return The PDU. 261 */ 262 @Override 263 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 264 { 265 if ( buffer == null ) 266 { 267 throw new EncoderException( I18n.err( I18n.ERR_04023 ) ); 268 } 269 270 try 271 { 272 // The ExtensibleMatch Tag 273 buffer.put( ( byte ) LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG ); 274 buffer.put( TLV.getBytes( extensibleMatchLength ) ); 275 276 if ( ( matchingRule == null ) && ( type == null ) ) 277 { 278 throw new EncoderException( I18n.err( I18n.ERR_04056 ) ); 279 } 280 281 // The matching rule 282 if ( matchingRule != null ) 283 { 284 buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_ID_TAG ); 285 buffer.put( TLV.getBytes( matchingRuleBytes.length ) ); 286 buffer.put( matchingRuleBytes ); 287 } 288 289 // The type 290 if ( type != null ) 291 { 292 buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_TYPE_TAG ); 293 buffer.put( TLV.getBytes( typeBytes.length ) ); 294 buffer.put( typeBytes ); 295 } 296 297 // The match value 298 if ( matchValue != null ) 299 { 300 buffer.put( ( byte ) LdapCodecConstants.MATCH_VALUE_TAG ); 301 302 byte[] bytes = matchValue.getBytes(); 303 int bytesLength = bytes.length; 304 buffer.put( TLV.getBytes( bytesLength ) ); 305 306 if ( bytesLength != 0 ) 307 { 308 buffer.put( bytes ); 309 } 310 311 } 312 313 // The dnAttributes flag, if true only 314 if ( dnAttributes ) 315 { 316 buffer.put( ( byte ) LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG ); 317 buffer.put( ( byte ) 1 ); 318 buffer.put( BerValue.TRUE_VALUE ); 319 } 320 } 321 catch ( BufferOverflowException boe ) 322 { 323 throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe ); 324 } 325 326 return buffer; 327 } 328 329 330 /** 331 * Return a String representing an extended filter as of RFC 2254 332 * 333 * @return An Extended Filter String 334 */ 335 @Override 336 public String toString() 337 { 338 339 StringBuilder sb = new StringBuilder(); 340 341 if ( type != null ) 342 { 343 sb.append( type ); 344 } 345 346 if ( dnAttributes ) 347 { 348 sb.append( ":dn" ); 349 } 350 351 if ( matchingRule == null ) 352 { 353 354 if ( type == null ) 355 { 356 return "Extended Filter wrong syntax"; 357 } 358 } 359 else 360 { 361 sb.append( ':' ).append( matchingRule ); 362 } 363 364 sb.append( ":=" ).append( matchValue ); 365 366 return sb.toString(); 367 } 368}