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.shared.ldap.codec.decorators;
021
022
023import java.nio.BufferOverflowException;
024import java.nio.ByteBuffer;
025
026import org.apache.directory.shared.asn1.EncoderException;
027import org.apache.directory.shared.asn1.ber.tlv.TLV;
028import org.apache.directory.shared.asn1.ber.tlv.Value;
029import org.apache.directory.shared.i18n.I18n;
030import org.apache.directory.shared.ldap.codec.api.Decorator;
031import org.apache.directory.shared.ldap.codec.api.LdapApiService;
032import org.apache.directory.shared.ldap.codec.api.LdapEncoder;
033import org.apache.directory.shared.ldap.model.message.LdapResult;
034import org.apache.directory.shared.ldap.model.message.Referral;
035import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
036import org.apache.directory.shared.ldap.model.name.Dn;
037import org.apache.directory.shared.util.Strings;
038
039
040/**
041 * A decorator for the LdapResultResponse message
042 *
043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044 */
045public class LdapResultDecorator implements LdapResult, Decorator<LdapResult>
046{
047    /** The decorated LdapResult */
048    private final LdapResult decoratedLdapResult;
049
050    /** Temporary storage for message bytes */
051    private byte[] errorMessageBytes;
052
053    /** Temporary storage of the byte[] representing the matchedDN */
054    private byte[] matchedDnBytes;
055    
056    /** The codec responsible for encoding and decoding this object. */
057    private LdapApiService codec;
058
059
060    /**
061     * Makes a LdapResult encodable.
062     *
063     * @param decoratedLdapResult the decorated LdapResult
064     */
065    public LdapResultDecorator( LdapResult decoratedLdapResult )
066    {
067        this.decoratedLdapResult = decoratedLdapResult;
068    }
069
070
071    /**
072     * @return The encoded Error message
073     */
074    public  byte[] getErrorMessageBytes()
075    {
076        return errorMessageBytes;
077    }
078
079
080    /**
081     * Set the encoded message's bytes
082     * @param errorMessageBytes The encoded bytes
083     */
084    public void setErrorMessageBytes( byte[] errorMessageBytes )
085    {
086        this.errorMessageBytes = errorMessageBytes;
087    }
088
089
090    /**
091     * Sets the encoded value for MatchedDn
092     *
093     * @param matchedDnBytes The encoded MatchedDN
094     */
095    public void setMatchedDnBytes( byte[] matchedDnBytes )
096    {
097        this.matchedDnBytes = matchedDnBytes;
098    }
099
100
101    /**
102     * @return the encoded MatchedDN
103     */
104    public byte[] getMatchedDnBytes()
105    {
106        return matchedDnBytes;
107    }
108
109
110    //-------------------------------------------------------------------------
111    // The LdapResult methods
112    //-------------------------------------------------------------------------
113    
114    
115    /**
116     * {@inheritDoc}
117     */
118    public ResultCodeEnum getResultCode()
119    {
120        return decoratedLdapResult.getResultCode();
121    }
122
123
124    /**
125     * {@inheritDoc}
126     */
127    public void setResultCode( ResultCodeEnum resultCode )
128    {
129        decoratedLdapResult.setResultCode( resultCode );
130    }
131
132
133    /**
134     * {@inheritDoc}
135     */
136    public Dn getMatchedDn()
137    {
138        return decoratedLdapResult.getMatchedDn();
139    }
140
141
142    /**
143     * {@inheritDoc}
144     */
145    public void setMatchedDn( Dn dn )
146    {
147        decoratedLdapResult.setMatchedDn( dn );
148    }
149
150
151    /**
152     * {@inheritDoc}
153     */
154    public String getDiagnosticMessage()
155    {
156        return decoratedLdapResult.getDiagnosticMessage();
157    }
158
159
160    /**
161     * {@inheritDoc}
162     */
163    public void setDiagnosticMessage( String diagnosticMessage )
164    {
165        decoratedLdapResult.setDiagnosticMessage( diagnosticMessage );
166    }
167
168
169    /**
170     * {@inheritDoc}
171     */
172    public boolean isReferral()
173    {
174        return decoratedLdapResult.isReferral();
175    }
176
177
178    /**
179     * {@inheritDoc}
180     */
181    public Referral getReferral()
182    {
183        return decoratedLdapResult.getReferral();
184    }
185
186
187    /**
188     * {@inheritDoc}
189     */
190    public void setReferral( Referral referral )
191    {
192        decoratedLdapResult.setReferral( referral );
193    }
194
195    
196    /**
197     * {@inheritDoc}
198     */
199    public String toString()
200    {
201        return decoratedLdapResult.toString();
202    }
203    
204    
205    //-------------------------------------------------------------------------
206    // The Decorator methods
207    //-------------------------------------------------------------------------
208    /**
209     * Compute the LdapResult length 
210     * 
211     * LdapResult : 
212     * 0x0A 01 resultCode (0..80)
213     *   0x04 L1 matchedDN (L1 = Length(matchedDN)) 
214     *   0x04 L2 errorMessage (L2 = Length(errorMessage)) 
215     *   [0x83 L3] referrals 
216     *     | 
217     *     +--> 0x04 L4 referral 
218     *     +--> 0x04 L5 referral 
219     *     +--> ... 
220     *     +--> 0x04 Li referral 
221     *     +--> ... 
222     *     +--> 0x04 Ln referral 
223     *     
224     * L1 = Length(matchedDN) 
225     * L2 = Length(errorMessage) 
226     * L3 = n*Length(0x04) + sum(Length(L4) .. Length(Ln)) + sum(L4..Ln) 
227     * L4..n = Length(0x04) + Length(Li) + Li 
228     * Length(LdapResult) = Length(0x0x0A) +
229     *      Length(0x01) + 1 + Length(0x04) + Length(L1) + L1 + Length(0x04) +
230     *      Length(L2) + L2 + Length(0x83) + Length(L3) + L3
231     */
232    public int computeLength()
233    {
234        int ldapResultLength = 0;
235
236        // The result code
237        ldapResultLength = 1 + 1 + Value.getNbBytes( getResultCode().getValue() );
238
239        // The matchedDN length
240        if ( getMatchedDn() == null )
241        {
242            ldapResultLength += 1 + 1;
243        }
244        else
245        {
246            byte[] matchedDNBytes = Strings.getBytesUtf8( Strings .trimLeft( getMatchedDn().getName() ) );
247            ldapResultLength += 1 + TLV.getNbBytes( matchedDNBytes.length ) + matchedDNBytes.length;
248            setMatchedDnBytes( matchedDNBytes );
249        }
250
251        // The errorMessage length
252        byte[] errorMessageBytes = Strings.getBytesUtf8( getDiagnosticMessage() );
253        ldapResultLength += 1 + TLV.getNbBytes( errorMessageBytes.length ) + errorMessageBytes.length;
254        setErrorMessageBytes( errorMessageBytes );
255
256        int referralLength = LdapEncoder.computeReferralLength( getReferral() );
257
258        if ( referralLength != 0 )
259        {
260            // The referrals
261            ldapResultLength += 1 + TLV.getNbBytes( referralLength ) + referralLength;
262        }
263
264        return ldapResultLength;
265    }
266
267
268    /**
269     * Encode the LdapResult message to a PDU.
270     * 
271     * @param buffer The buffer where to put the PDU
272     * @return The PDU.
273     */
274    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
275    {
276        if ( buffer == null )
277        {
278            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
279        }
280
281        try
282        {
283            // The result code
284            Value.encodeEnumerated( buffer, getResultCode().getValue() );
285        }
286        catch ( BufferOverflowException boe )
287        {
288            throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
289        }
290
291        // The matchedDN
292        Value.encode( buffer, getMatchedDnBytes() );
293
294        // The error message
295        Value.encode( buffer, getErrorMessageBytes() );
296
297        // The referrals, if any
298        Referral referral = getReferral();
299
300        if ( referral != null )
301        {
302            LdapEncoder.encodeReferral( buffer, referral );
303        }
304
305        return buffer;
306    }
307
308
309    /**
310     * {@inheritDoc}
311     */
312    public LdapResult getDecorated()
313    {
314        return decoratedLdapResult;
315    }
316
317
318    /**
319     * {@inheritDoc}
320     */
321    public LdapApiService getCodecService()
322    {
323        return codec;
324    }
325}