View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.codec.search;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  
26  import org.apache.directory.api.asn1.EncoderException;
27  import org.apache.directory.api.asn1.ber.tlv.BerValue;
28  import org.apache.directory.api.asn1.ber.tlv.TLV;
29  import org.apache.directory.api.i18n.I18n;
30  import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
31  import org.apache.directory.api.ldap.model.entry.Value;
32  import org.apache.directory.api.util.Strings;
33  
34  
35  /**
36   * The search request filter Matching Rule assertion
37   * 
38   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
39   */
40  public class ExtensibleMatchFilter extends Filter
41  {
42      /** The expected lenth of the Matching Rule Assertion */
43      private int expectedMatchingRuleLength;
44  
45      /** Matching rule */
46      private String matchingRule;
47  
48      /** Matching rule bytes */
49      private byte[] matchingRuleBytes;
50  
51      /** Matching rule type */
52      private String type;
53  
54      private byte[] typeBytes;
55  
56      /** Matching rule value */
57      private Value matchValue;
58  
59      /** The dnAttributes flag */
60      private boolean dnAttributes = false;
61  
62      /** The extensible match length */
63      private int extensibleMatchLength;
64  
65  
66      /**
67       * Creates a new ExtensibleMatchFilter object. The dnAttributes flag
68       * defaults to false.
69       * 
70       * @param tlvId The TLV identifier
71       */
72      public ExtensibleMatchFilter( int tlvId )
73      {
74          super( tlvId );
75      }
76  
77  
78      /**
79       * Creates a new ExtensibleMatchFilter object. The dnAttributes flag
80       * defaults to false.
81       */
82      public ExtensibleMatchFilter()
83      {
84          super();
85      }
86  
87  
88      /**
89       * Get the dnAttributes flag
90       * 
91       * @return Returns the dnAttributes.
92       */
93      public boolean isDnAttributes()
94      {
95          return dnAttributes;
96      }
97  
98  
99      /**
100      * Set the dnAttributes flag
101      * 
102      * @param dnAttributes The dnAttributes to set.
103      */
104     public void setDnAttributes( boolean dnAttributes )
105     {
106         this.dnAttributes = dnAttributes;
107     }
108 
109 
110     /**
111      * Get the matchingRule
112      * 
113      * @return Returns the matchingRule.
114      */
115     public String getMatchingRule()
116     {
117         return matchingRule;
118     }
119 
120 
121     /**
122      * Set the matchingRule
123      * 
124      * @param matchingRule The matchingRule to set.
125      */
126     public void setMatchingRule( String matchingRule )
127     {
128         this.matchingRule = matchingRule;
129     }
130 
131 
132     /**
133      * Get the matchValue
134      * 
135      * @return Returns the matchValue.
136      */
137     public Value getMatchValue()
138     {
139         return matchValue;
140     }
141 
142 
143     /**
144      * Set the matchValue
145      * 
146      * @param matchValue The matchValue to set.
147      */
148     public void setMatchValue( Value matchValue )
149     {
150         this.matchValue = matchValue;
151     }
152 
153 
154     /**
155      * Get the type
156      * 
157      * @return Returns the type.
158      */
159     public String getType()
160     {
161         return type;
162     }
163 
164 
165     /**
166      * Set the type
167      * 
168      * @param type The type to set.
169      */
170     public void setType( String type )
171     {
172         this.type = type;
173     }
174 
175 
176     /**
177      * get the expectedMatchingRuleLength
178      * 
179      * @return Returns the expectedMatchingRuleLength.
180      */
181     public int getExpectedMatchingRuleLength()
182     {
183         return expectedMatchingRuleLength;
184     }
185 
186 
187     /**
188      * Set the expectedMatchingRuleLength
189      * 
190      * @param expectedMatchingRuleLength The expectedMatchingRuleLength to set.
191      */
192     public void setExpectedMatchingRuleLength( int expectedMatchingRuleLength )
193     {
194         this.expectedMatchingRuleLength = expectedMatchingRuleLength;
195     }
196 
197 
198     /**
199      * Compute the ExtensibleMatchFilter length 
200      * <br>
201      * ExtensibleMatchFilter :
202      * <pre> 
203      * 0xA9 L1 
204      *   |
205      *  [+--&gt; 0x81 L3 matchingRule] 
206      *  [+--&gt; 0x82 L4 type] 
207      *  [+--&gt; 0x83 L5 matchValue]
208      *  [+--&gt; 0x01 0x01 dnAttributes]
209      * </pre>
210      * 
211      * @return The encoded length
212      */
213     @Override
214     public int computeLength()
215     {
216         if ( matchingRule != null )
217         {
218             matchingRuleBytes = Strings.getBytesUtf8( matchingRule );
219             extensibleMatchLength = 1 + TLV.getNbBytes( matchingRuleBytes.length ) + matchingRuleBytes.length;
220         }
221 
222         if ( type != null )
223         {
224             typeBytes = Strings.getBytesUtf8( type );
225             extensibleMatchLength += 1 + TLV.getNbBytes( typeBytes.length ) + typeBytes.length;
226         }
227 
228         if ( matchValue != null )
229         {
230             int bytesLength = matchValue.getBytes().length;
231             extensibleMatchLength += 1 + TLV.getNbBytes( bytesLength ) + bytesLength;
232         }
233 
234         if ( dnAttributes )
235         {
236             extensibleMatchLength += 1 + 1 + 1;
237         }
238 
239         return 1 + TLV.getNbBytes( extensibleMatchLength ) + extensibleMatchLength;
240     }
241 
242 
243     /**
244      * Encode the ExtensibleMatch Filters to a PDU. 
245      * <br>
246      * ExtensibleMatch filter :
247      * <pre>
248      * 0xA9 LL 
249      *  |     0x81 LL matchingRule
250      *  |    / |   0x82 LL Type  
251      *  |   /  |  /0x83 LL matchValue
252      *  +--+   +-+
253      *  |   \     \
254      *  |    \     0x83 LL MatchValue
255      *  |     0x82 LL type
256      *  |     0x83 LL matchValue
257      *  +--[0x84 0x01 dnAttributes]
258      * </pre>
259      * 
260      * @param buffer The buffer where to put the PDU
261      * @return The PDU.
262      */
263     @Override
264     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
265     {
266         if ( buffer == null )
267         {
268             throw new EncoderException( I18n.err( I18n.ERR_08000_CANNOT_PUT_A_PDU_IN_NULL_BUFFER ) );
269         }
270 
271         try
272         {
273             // The ExtensibleMatch Tag
274             buffer.put( ( byte ) LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG );
275             buffer.put( TLV.getBytes( extensibleMatchLength ) );
276 
277             if ( ( matchingRule == null ) && ( type == null ) )
278             {
279                 throw new EncoderException( I18n.err( I18n.ERR_05500_NULL_MATCHING_RULE_AND_TYPE ) );
280             }
281 
282             // The matching rule
283             if ( matchingRule != null )
284             {
285                 buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_ID_TAG );
286                 buffer.put( TLV.getBytes( matchingRuleBytes.length ) );
287                 buffer.put( matchingRuleBytes );
288             }
289 
290             // The type
291             if ( type != null )
292             {
293                 buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_TYPE_TAG );
294                 buffer.put( TLV.getBytes( typeBytes.length ) );
295                 buffer.put( typeBytes );
296             }
297 
298             // The match value
299             if ( matchValue != null )
300             {
301                 buffer.put( ( byte ) LdapCodecConstants.MATCH_VALUE_TAG );
302 
303                 byte[] bytes = matchValue.getBytes();
304                 int bytesLength = bytes.length;
305                 buffer.put( TLV.getBytes( bytesLength ) );
306 
307                 if ( bytesLength != 0 )
308                 {
309                     buffer.put( bytes );
310                 }
311 
312             }
313 
314             // The dnAttributes flag, if true only
315             if ( dnAttributes )
316             {
317                 buffer.put( ( byte ) LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG );
318                 buffer.put( ( byte ) 1 );
319                 buffer.put( BerValue.TRUE_VALUE );
320             }
321         }
322         catch ( BufferOverflowException boe )
323         {
324             throw new EncoderException( I18n.err( I18n.ERR_08212_PDU_BUFFER_TOO_SMALL ), boe );
325         }
326 
327         return buffer;
328     }
329 
330 
331     /**
332      * Return a String representing an extended filter as of RFC 2254
333      * 
334      * @return An Extended Filter String
335      */
336     @Override
337     public String toString()
338     {
339 
340         StringBuilder sb = new StringBuilder();
341 
342         if ( type != null )
343         {
344             sb.append( type );
345         }
346 
347         if ( dnAttributes )
348         {
349             sb.append( ":dn" );
350         }
351 
352         if ( matchingRule == null )
353         {
354 
355             if ( type == null )
356             {
357                 return "Extended Filter wrong syntax";
358             }
359         }
360         else
361         {
362             sb.append( ':' ).append( matchingRule );
363         }
364 
365         sb.append( ":=" ).append( matchValue );
366 
367         return sb.toString();
368     }
369 }