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   *    http://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.util.Strings;
32  
33  
34  /**
35   * The search request filter Matching Rule assertion
36   * 
37   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
38   */
39  public class ExtensibleMatchFilter extends Filter
40  {
41      /** The expected lenth of the Matching Rule Assertion */
42      private int expectedMatchingRuleLength;
43  
44      /** Matching rule */
45      private String matchingRule;
46  
47      /** Matching rule bytes */
48      private byte[] matchingRuleBytes;
49  
50      /** Matching rule type */
51      private String type;
52  
53      private byte[] typeBytes;
54  
55      /** Matching rule value */
56      private org.apache.directory.api.ldap.model.entry.Value<?> matchValue;
57  
58      /** The dnAttributes flag */
59      private boolean dnAttributes = false;
60  
61      /** The extensible match length */
62      private int extensibleMatchLength;
63  
64  
65      /**
66       * Creates a new ExtensibleMatchFilter object. The dnAttributes flag
67       * defaults to false.
68       * 
69       * @param tlvId The TLV identifier
70       */
71      public ExtensibleMatchFilter( int tlvId )
72      {
73          super( tlvId );
74      }
75  
76  
77      /**
78       * Creates a new ExtensibleMatchFilter object. The dnAttributes flag
79       * defaults to false.
80       */
81      public ExtensibleMatchFilter()
82      {
83          super();
84      }
85  
86  
87      /**
88       * Get the dnAttributes flag
89       * 
90       * @return Returns the dnAttributes.
91       */
92      public boolean isDnAttributes()
93      {
94          return dnAttributes;
95      }
96  
97  
98      /**
99       * 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      *  [+--&gt; 0x81 L3 matchingRule] 
205      *  [+--&gt; 0x82 L4 type] 
206      *  [+--&gt; 0x83 L5 matchValue]
207      *  [+--&gt; 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 }