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.api;
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.i18n.I18n;
029import org.apache.directory.shared.ldap.codec.decorators.SingleReplyRequestDecorator;
030import org.apache.directory.shared.ldap.model.exception.MessageException;
031import org.apache.directory.shared.ldap.model.message.Control;
032import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
033import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
034import org.apache.directory.shared.util.Strings;
035
036
037/**
038 * A decorator for the ExtendedRequest message
039 *
040 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
041 */
042public class ExtendedRequestDecorator<Q extends ExtendedRequest<P>, P extends ExtendedResponse> 
043    extends SingleReplyRequestDecorator<Q,P> implements ExtendedRequest<P>
044{
045    /** The extended request length */
046    private int extendedRequestLength;
047
048    /** The OID length */
049    private byte[] requestNameBytes;
050
051    protected byte[] requestValue;
052
053
054    /**
055     * Makes a ExtendedRequest a MessageDecorator.
056     *
057     * @param decoratedMessage the decorated ExtendedRequest
058     */
059    public ExtendedRequestDecorator( LdapApiService codec, Q decoratedMessage )
060    {
061        super( codec, decoratedMessage );
062    }
063
064
065    /**
066     * Stores the encoded length for the ExtendedRequest
067     *
068     * @param extendedRequestLength The encoded length
069     */
070    public void setExtendedRequestLength( int extendedRequestLength )
071    {
072        this.extendedRequestLength = extendedRequestLength;
073    }
074
075
076    /**
077     * @return The encoded ExtendedRequest's length
078     */
079    public int getExtendedRequestLength()
080    {
081        return extendedRequestLength;
082    }
083
084
085    /**
086     * Gets the requestName bytes.
087     *
088     * @return the requestName bytes of the extended request type.
089     */
090    public byte[] getRequestNameBytes()
091    {
092        return requestNameBytes;
093    }
094
095
096    /**
097     * Sets the requestName bytes.
098     *
099     * @param requestNameBytes the OID bytes of the extended request type.
100     */
101    public void setRequestNameBytes( byte[] requestNameBytes )
102    {
103        this.requestNameBytes = requestNameBytes;
104    }
105
106
107    //-------------------------------------------------------------------------
108    // The ExtendedRequest methods
109    //-------------------------------------------------------------------------
110    
111    
112    /**
113     * {@inheritDoc}
114     */
115    public String getRequestName()
116    {
117        return getDecorated().getRequestName();
118    }
119
120
121    /**
122     * {@inheritDoc}
123     */
124    public ExtendedRequest<P> setRequestName( String oid )
125    {
126        getDecorated().setRequestName( oid );
127        
128        return this;
129    }
130
131
132    /**
133     * {@inheritDoc}
134     */
135    public byte[] getRequestValue()
136    {
137        return requestValue;
138    }
139
140
141    /**
142     * {@inheritDoc}
143     */
144    public void setRequestValue( byte[] requestValue )
145    {
146        this.requestValue = requestValue;
147    }
148
149    
150    
151    
152    /**
153     * {@inheritDoc}
154     */
155    public ExtendedRequest<P> setMessageId( int messageId )
156    {
157        super.setMessageId( messageId );
158        
159        return this;
160    }
161
162    
163    /**
164     * {@inheritDoc}
165     */
166    public ExtendedRequest<P> addControl( Control control ) throws MessageException
167    {
168        return (ExtendedRequest<P>)super.addControl( control );
169    }
170    
171    
172    /**
173     * {@inheritDoc}
174     */
175    public ExtendedRequest<P> addAllControls( Control[] controls ) throws MessageException
176    {
177        return (ExtendedRequest<P>)super.addAllControls( controls );
178    }
179    
180    
181    /**
182     * {@inheritDoc}
183     */
184    public ExtendedRequest<P> removeControl( Control control ) throws MessageException
185    {
186        return (ExtendedRequest<P>)super.removeControl( control );
187    }
188    //-------------------------------------------------------------------------
189    // The Decorator methods
190    //-------------------------------------------------------------------------
191    
192    
193    /**
194     * Compute the ExtendedRequest length
195     * 
196     * ExtendedRequest :
197     * 
198     * 0x77 L1
199     *  |
200     *  +--> 0x80 L2 name
201     *  [+--> 0x81 L3 value]
202     * 
203     * L1 = Length(0x80) + Length(L2) + L2
204     *      [+ Length(0x81) + Length(L3) + L3]
205     * 
206     * Length(ExtendedRequest) = Length(0x77) + Length(L1) + L1
207     */
208    public int computeLength()
209    {
210        byte[] requestNameBytes = Strings.getBytesUtf8( getRequestName() );
211
212        setRequestNameBytes( requestNameBytes );
213
214        int extendedRequestLength = 1 + TLV.getNbBytes( requestNameBytes.length ) + requestNameBytes.length;
215
216        if ( getRequestValue() != null )
217        {
218            extendedRequestLength += 1 + TLV.getNbBytes( getRequestValue().length )
219                + getRequestValue().length;
220        }
221
222        setExtendedRequestLength( extendedRequestLength );
223
224        return 1 + TLV.getNbBytes( extendedRequestLength ) + extendedRequestLength;
225    }
226
227
228    /**
229     * Encode the ExtendedRequest message to a PDU. 
230     * 
231     * ExtendedRequest :
232     * 
233     * 0x80 LL resquest name
234     * [0x81 LL request value]
235     * 
236     * @param buffer The buffer where to put the PDU
237     * @return The PDU.
238     */
239    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
240    {
241        try
242        {
243            // The BindResponse Tag
244            buffer.put( LdapConstants.EXTENDED_REQUEST_TAG );
245            buffer.put( TLV.getBytes( getExtendedRequestLength() ) );
246
247            // The requestName, if any
248            if ( getRequestNameBytes() == null )
249            {
250                throw new EncoderException( I18n.err( I18n.ERR_04043 ) );
251            }
252
253            buffer.put( ( byte ) LdapConstants.EXTENDED_REQUEST_NAME_TAG );
254            buffer.put( TLV.getBytes( getRequestNameBytes().length ) );
255
256            if ( getRequestNameBytes().length != 0 )
257            {
258                buffer.put( getRequestNameBytes() );
259            }
260
261            // The requestValue, if any
262            if ( getRequestValue() != null )
263            {
264                buffer.put( ( byte ) LdapConstants.EXTENDED_REQUEST_VALUE_TAG );
265
266                buffer.put( TLV.getBytes( getRequestValue().length ) );
267
268                if ( getRequestValue().length != 0 )
269                {
270                    buffer.put( getRequestValue() );
271                }
272            }
273        }
274        catch ( BufferOverflowException boe )
275        {
276            throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
277        }
278
279        return buffer;
280    }
281}