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.decorators;
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.Decorator;
31  import org.apache.directory.api.ldap.codec.api.LdapApiService;
32  import org.apache.directory.api.ldap.codec.api.LdapEncoder;
33  import org.apache.directory.api.ldap.model.message.LdapResult;
34  import org.apache.directory.api.ldap.model.message.Referral;
35  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
36  import org.apache.directory.api.ldap.model.name.Dn;
37  import org.apache.directory.api.util.Strings;
38  
39  
40  /**
41   * A decorator for the LdapResultResponse message
42   *
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   */
45  public class LdapResultDecorator implements LdapResult, Decorator<LdapResult>
46  {
47      /** The decorated LdapResult */
48      private final LdapResult decoratedLdapResult;
49  
50      /** Temporary storage for message bytes */
51      private byte[] errorMessageBytes;
52  
53      /** Temporary storage of the byte[] representing the matchedDN */
54      private byte[] matchedDnBytes;
55  
56      /** The codec responsible for encoding and decoding this object. */
57      private LdapApiService codec;
58  
59      private static final byte[] DEFAULT_SUCCESS = new byte[]
60          { 0x0A, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00 };
61  
62  
63      /**
64       * Makes a LdapResult encodable.
65       *
66       * @param decoratedLdapResult the decorated LdapResult
67       */
68      public LdapResultDecorator( LdapResult decoratedLdapResult )
69      {
70          this.decoratedLdapResult = decoratedLdapResult;
71      }
72  
73  
74      /**
75       * @return The encoded Error message
76       */
77      public byte[] getErrorMessageBytes()
78      {
79          return errorMessageBytes;
80      }
81  
82  
83      /**
84       * Set the encoded message's bytes
85       * @param errorMessageBytes The encoded bytes
86       */
87      public void setErrorMessageBytes( byte[] errorMessageBytes )
88      {
89          this.errorMessageBytes = errorMessageBytes;
90      }
91  
92  
93      /**
94       * Sets the encoded value for MatchedDn
95       *
96       * @param matchedDnBytes The encoded MatchedDN
97       */
98      public void setMatchedDnBytes( byte[] matchedDnBytes )
99      {
100         this.matchedDnBytes = matchedDnBytes;
101     }
102 
103 
104     /**
105      * @return the encoded MatchedDN
106      */
107     public byte[] getMatchedDnBytes()
108     {
109         return matchedDnBytes;
110     }
111 
112 
113     //-------------------------------------------------------------------------
114     // The LdapResult methods
115     //-------------------------------------------------------------------------
116 
117     /**
118      * {@inheritDoc}
119      */
120     public ResultCodeEnum getResultCode()
121     {
122         return decoratedLdapResult.getResultCode();
123     }
124 
125 
126     /**
127      * {@inheritDoc}
128      */
129     public void setResultCode( ResultCodeEnum resultCode )
130     {
131         decoratedLdapResult.setResultCode( resultCode );
132     }
133 
134 
135     /**
136      * {@inheritDoc}
137      */
138     public Dn getMatchedDn()
139     {
140         return decoratedLdapResult.getMatchedDn();
141     }
142 
143 
144     /**
145      * {@inheritDoc}
146      */
147     public void setMatchedDn( Dn dn )
148     {
149         decoratedLdapResult.setMatchedDn( dn );
150     }
151 
152 
153     /**
154      * {@inheritDoc}
155      */
156     public String getDiagnosticMessage()
157     {
158         return decoratedLdapResult.getDiagnosticMessage();
159     }
160 
161 
162     /**
163      * {@inheritDoc}
164      */
165     public void setDiagnosticMessage( String diagnosticMessage )
166     {
167         decoratedLdapResult.setDiagnosticMessage( diagnosticMessage );
168     }
169 
170 
171     /**
172      * {@inheritDoc}
173      */
174     public boolean isReferral()
175     {
176         return decoratedLdapResult.isReferral();
177     }
178 
179 
180     /**
181      * {@inheritDoc}
182      */
183     public Referral getReferral()
184     {
185         return decoratedLdapResult.getReferral();
186     }
187 
188 
189     /**
190      * {@inheritDoc}
191      */
192     public void setReferral( Referral referral )
193     {
194         decoratedLdapResult.setReferral( referral );
195     }
196 
197 
198     /**
199      * {@inheritDoc}
200      */
201     public String toString()
202     {
203         return decoratedLdapResult.toString();
204     }
205 
206 
207     //-------------------------------------------------------------------------
208     // The Decorator methods
209     //-------------------------------------------------------------------------
210     /**
211      * Compute the LdapResult length 
212      * 
213      * LdapResult : 
214      *   0x0A 01 resultCode (0..80)
215      *   0x04 L1 matchedDN (L1 = Length(matchedDN)) 
216      *   0x04 L2 errorMessage (L2 = Length(errorMessage)) 
217      *   [0x83 L3] referrals 
218      *     | 
219      *     +--> 0x04 L4 referral 
220      *     +--> 0x04 L5 referral 
221      *     +--> ... 
222      *     +--> 0x04 Li referral 
223      *     +--> ... 
224      *     +--> 0x04 Ln referral 
225      *     
226      * L1 = Length(matchedDN) 
227      * L2 = Length(errorMessage) 
228      * L3 = n*Length(0x04) + sum(Length(L4) .. Length(Ln)) + sum(L4..Ln) 
229      * L4..n = Length(0x04) + Length(Li) + Li 
230      * Length(LdapResult) = Length(0x0x0A) +
231      *      Length(0x01) + 1 + Length(0x04) + Length(L1) + L1 + Length(0x04) +
232      *      Length(L2) + L2 + Length(0x83) + Length(L3) + L3
233      */
234     public int computeLength()
235     {
236         if ( decoratedLdapResult.isDefaultSuccess() )
237         {
238             // The length of a default success PDU : 0xA0 0x01 0x00 0x04 0x00 0x04 0x00
239             return DEFAULT_SUCCESS.length;
240         }
241 
242         int ldapResultLength = 0;
243 
244         // The result code
245         ldapResultLength = 1 + 1 + BerValue.getNbBytes( getResultCode().getValue() );
246 
247         // The matchedDN length
248         if ( getMatchedDn() == null )
249         {
250             ldapResultLength += 1 + 1;
251         }
252         else
253         {
254             byte[] matchedDNBytes = Strings.getBytesUtf8Ascii( Strings.trimLeft( getMatchedDn().getName() ) );
255             ldapResultLength += 1 + TLV.getNbBytes( matchedDNBytes.length ) + matchedDNBytes.length;
256             setMatchedDnBytes( matchedDNBytes );
257         }
258 
259         // The errorMessage length
260         byte[] errorMessageBytes = Strings.getBytesUtf8Ascii( getDiagnosticMessage() );
261         ldapResultLength += 1 + TLV.getNbBytes( errorMessageBytes.length ) + errorMessageBytes.length;
262         setErrorMessageBytes( errorMessageBytes );
263 
264         int referralLength = LdapEncoder.computeReferralLength( getReferral() );
265 
266         if ( referralLength != 0 )
267         {
268             // The referrals
269             ldapResultLength += 1 + TLV.getNbBytes( referralLength ) + referralLength;
270         }
271 
272         return ldapResultLength;
273     }
274 
275 
276     /**
277      * Encode the LdapResult message to a PDU.
278      * 
279      * @param buffer The buffer where to put the PDU
280      * @return The PDU.
281      */
282     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
283     {
284         if ( buffer == null )
285         {
286             throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
287         }
288 
289         if ( decoratedLdapResult.isDefaultSuccess() )
290         {
291             // The length of a default success PDU : 0xA0 0x01 0x00 0x04 0x00 0x04 0x00
292             buffer.put( DEFAULT_SUCCESS );
293 
294             return buffer;
295         }
296 
297         try
298         {
299             // The result code
300             BerValue.encodeEnumerated( buffer, getResultCode().getValue() );
301         }
302         catch ( BufferOverflowException boe )
303         {
304             throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
305         }
306 
307         // The matchedDN
308         BerValue.encode( buffer, getMatchedDnBytes() );
309 
310         // The error message
311         BerValue.encode( buffer, getErrorMessageBytes() );
312 
313         // The referrals, if any
314         Referral referral = getReferral();
315 
316         if ( referral != null )
317         {
318             LdapEncoder.encodeReferral( buffer, referral );
319         }
320 
321         return buffer;
322     }
323 
324 
325     /**
326      * {@inheritDoc}
327      */
328     public LdapResult getDecorated()
329     {
330         return decoratedLdapResult;
331     }
332 
333 
334     /**
335      * {@inheritDoc}
336      */
337     public LdapApiService getCodecService()
338     {
339         return codec;
340     }
341 
342 
343     /**
344      * {@inheritDoc}
345      */
346     public boolean isDefaultSuccess()
347     {
348         return decoratedLdapResult.isDefaultSuccess();
349     }
350 }