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.api.ldap.extras.extended.ads_impl.storedProcedure;
021
022
023import java.nio.BufferOverflowException;
024import java.nio.ByteBuffer;
025import java.util.LinkedList;
026import java.util.List;
027
028import org.apache.directory.api.asn1.EncoderException;
029import org.apache.directory.api.asn1.ber.tlv.BerValue;
030import org.apache.directory.api.asn1.ber.tlv.TLV;
031import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
032import org.apache.directory.api.i18n.I18n;
033import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
034import org.apache.directory.api.ldap.codec.api.LdapApiService;
035import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureParameter;
036import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequest;
037import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequestImpl;
038import org.apache.directory.api.util.Strings;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042
043/**
044 * A Decorator for stored procedure extended operation requests.
045 *
046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047 */
048public class StoredProcedureRequestDecorator extends ExtendedRequestDecorator<StoredProcedureRequest>
049    implements StoredProcedureRequest
050{
051    private static final Logger LOG = LoggerFactory.getLogger( StoredProcedureRequestDecorator.class );
052
053    private StoredProcedureParameter currentParameter;
054
055    /** The stored procedure length */
056    private int storedProcedureLength;
057
058    /** The parameters length */
059    private int parametersLength;
060
061    /** The list of all parameter lengths */
062    private List<Integer> parameterLength;
063
064    /** The list of all parameter type lengths */
065    private List<Integer> paramTypeLength;
066
067    /** The list of all parameter value lengths */
068    private List<Integer> paramValueLength;
069
070
071    public StoredProcedureRequestDecorator( LdapApiService codec )
072    {
073        super( codec, new StoredProcedureRequestImpl() );
074    }
075
076
077    public StoredProcedureRequestDecorator( LdapApiService codec, StoredProcedureRequest decoratedRequest )
078    {
079        super( codec, decoratedRequest );
080        if ( decoratedRequest == null )
081        {
082            throw new NullPointerException( "decorated stored procedulre request is null" );
083        }
084    }
085
086
087    public StoredProcedureParameter getCurrentParameter()
088    {
089        return currentParameter;
090    }
091
092
093    public void setCurrentParameter( StoredProcedureParameter currentParameter )
094    {
095        this.currentParameter = currentParameter;
096    }
097
098
099    /**
100     * Compute the StoredProcedure length 
101     * <pre>
102     * 0x30 L1 
103     *   | 
104     *   +--> 0x04 L2 language
105     *   +--> 0x04 L3 procedure
106     *  [+--> 0x30 L4 (parameters)
107     *          |
108     *          +--> 0x30 L5-1 (parameter)
109     *          |      |
110     *          |      +--> 0x04 L6-1 type
111     *          |      +--> 0x04 L7-1 value
112     *          |      
113     *          +--> 0x30 L5-2 (parameter)
114     *          |      |
115     *          |      +--> 0x04 L6-2 type
116     *          |      +--> 0x04 L7-2 value
117     *          |
118     *          +--> ...
119     *          |      
120     *          +--> 0x30 L5-m (parameter)
121     *                 |
122     *                 +--> 0x04 L6-m type
123     *                 +--> 0x04 L7-m value
124     * </pre>
125     */
126    /* no qualifier */ int computeLengthInternal()
127    {
128        // The language
129        byte[] languageBytes = Strings.getBytesUtf8( getDecorated().getLanguage() );
130
131        int languageLength = 1 + TLV.getNbBytes( languageBytes.length )
132            + languageBytes.length;
133
134        byte[] procedure = getDecorated().getProcedure();
135
136        // The procedure
137        int procedureLength = 1 + TLV.getNbBytes( procedure.length )
138            + procedure.length;
139
140        // Compute parameters length value
141        if ( getDecorated().getParameters() != null )
142        {
143            parameterLength = new LinkedList<Integer>();
144            paramTypeLength = new LinkedList<Integer>();
145            paramValueLength = new LinkedList<Integer>();
146
147            for ( StoredProcedureParameter spParam : getDecorated().getParameters() )
148            {
149                int localParameterLength = 0;
150                int localParamTypeLength = 0;
151                int localParamValueLength = 0;
152
153                localParamTypeLength = 1 + TLV.getNbBytes( spParam.getType().length ) + spParam.getType().length;
154                localParamValueLength = 1 + TLV.getNbBytes( spParam.getValue().length ) + spParam.getValue().length;
155
156                localParameterLength = localParamTypeLength + localParamValueLength;
157
158                parametersLength += 1 + TLV.getNbBytes( localParameterLength ) + localParameterLength;
159
160                parameterLength.add( localParameterLength );
161                paramTypeLength.add( localParamTypeLength );
162                paramValueLength.add( localParamValueLength );
163            }
164        }
165
166        int localParametersLength = 1 + TLV.getNbBytes( parametersLength ) + parametersLength;
167        storedProcedureLength = languageLength + procedureLength + localParametersLength;
168
169        return 1 + TLV.getNbBytes( storedProcedureLength ) + storedProcedureLength;
170    }
171
172
173    /**
174     * Encodes the StoredProcedure extended operation.
175     * 
176     * @return A ByteBuffer that contains the encoded PDU
177     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
178     */
179    /* no qualifier */ ByteBuffer encodeInternal() throws EncoderException
180    {
181        // Allocate the bytes buffer.
182        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
183
184        try
185        {
186            // The StoredProcedure Tag
187            bb.put( UniversalTag.SEQUENCE.getValue() );
188            bb.put( TLV.getBytes( storedProcedureLength ) );
189
190            // The language
191            BerValue.encode( bb, getDecorated().getLanguage() );
192
193            // The procedure
194            BerValue.encode( bb, getDecorated().getProcedure() );
195
196            // The parameters sequence
197            bb.put( UniversalTag.SEQUENCE.getValue() );
198            bb.put( TLV.getBytes( parametersLength ) );
199
200            // The parameters list
201            if ( ( getDecorated().getParameters() != null ) && ( getDecorated().getParameters().size() != 0 ) )
202            {
203                int parameterNumber = 0;
204
205                for ( StoredProcedureParameter spParam : getDecorated().getParameters() )
206                {
207                    // The parameter sequence
208                    bb.put( UniversalTag.SEQUENCE.getValue() );
209                    int localParameterLength = parameterLength.get( parameterNumber );
210                    bb.put( TLV.getBytes( localParameterLength ) );
211
212                    // The parameter type
213                    BerValue.encode( bb, spParam.getType() );
214
215                    // The parameter value
216                    BerValue.encode( bb, spParam.getValue() );
217
218                    // Go to the next parameter;
219                    parameterNumber++;
220                }
221            }
222        }
223        catch ( BufferOverflowException boe )
224        {
225            throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
226        }
227
228        return bb;
229    }
230
231
232    /**
233     * Returns the StoredProcedure string
234     * 
235     * @return The StoredProcedure string
236     */
237    public String toString()
238    {
239
240        StringBuffer sb = new StringBuffer();
241
242        sb.append( "    StoredProcedure\n" );
243        sb.append( "        Language : '" ).append( getDecorated().getLanguage() ).append( "'\n" );
244        sb.append( "        Procedure\n" ).append( getDecorated().getProcedureSpecification() ).append( "'\n" );
245
246        if ( ( getDecorated().getParameters() == null ) || ( getDecorated().getParameters().size() == 0 ) )
247        {
248            sb.append( "        No parameters\n" );
249        }
250        else
251        {
252            sb.append( "        Parameters\n" );
253
254            int i = 1;
255
256            for ( StoredProcedureParameter spParam : getDecorated().getParameters() )
257            {
258                sb.append( "            type[" ).append( i ).append( "] : '" ).
259                    append( Strings.utf8ToString( spParam.getType() ) ).append( "'\n" );
260                sb.append( "            value[" ).append( i ).append( "] : '" ).
261                    append( Strings.dumpBytes( spParam.getValue() ) ).append( "'\n" );
262            }
263        }
264
265        return sb.toString();
266    }
267
268
269    public void setProcedure( byte[] procedure )
270    {
271        getDecorated().setProcedure( procedure );
272    }
273
274
275    /**
276     * {@inheritDoc}
277     */
278    public void setRequestValue( byte[] payload )
279    {
280        StoredProcedureDecoder decoder = new StoredProcedureDecoder();
281        StoredProcedureContainer container = new StoredProcedureContainer();
282
283        container.setStoredProcedure( this );
284
285        try
286        {
287            decoder.decode( ByteBuffer.wrap( payload ), container );
288        }
289        catch ( Exception e )
290        {
291            LOG.error( I18n.err( I18n.ERR_04165 ), e );
292            throw new RuntimeException( e );
293        }
294    }
295
296
297    /**
298     * {@inheritDoc}
299     */
300    public byte[] getRequestValue()
301    {
302        if ( requestValue == null )
303        {
304            try
305            {
306                requestValue = encodeInternal().array();
307            }
308            catch ( EncoderException e )
309            {
310                LOG.error( I18n.err( I18n.ERR_04174 ), e );
311                throw new RuntimeException( e );
312            }
313        }
314
315        return requestValue;
316    }
317
318
319    /**
320     * {@inheritDoc}
321     */
322    public String getLanguage()
323    {
324        return getDecorated().getLanguage();
325    }
326
327
328    /**
329     * {@inheritDoc}
330     */
331    public void setLanguage( String language )
332    {
333        getDecorated().setLanguage( language );
334    }
335
336
337    /**
338     * {@inheritDoc}
339     */
340    public String getProcedureSpecification()
341    {
342        return getDecorated().getProcedureSpecification();
343    }
344
345
346    /**
347     * {@inheritDoc}
348     */
349    public int size()
350    {
351        return getDecorated().size();
352    }
353
354
355    /**
356     * {@inheritDoc}
357     */
358    public Object getParameterType( int index )
359    {
360        return getDecorated().getParameterType( index );
361    }
362
363
364    /**
365     * {@inheritDoc}
366     */
367
368    public Class<?> getJavaParameterType( int index )
369    {
370        return getDecorated().getJavaParameterType( index );
371    }
372
373
374    /**
375     * {@inheritDoc}
376     */
377
378    public Object getParameterValue( int index )
379    {
380        return getDecorated().getParameterValue( index );
381    }
382
383
384    /**
385     * {@inheritDoc}
386     */
387    public Object getJavaParameterValue( int index )
388    {
389        return getDecorated().getJavaParameterValue( index );
390    }
391
392
393    /**
394     * {@inheritDoc}
395     */
396    public void addParameter( Object type, Object value )
397    {
398        getDecorated().addParameter( type, value );
399    }
400
401
402    /**
403     * {@inheritDoc}
404     */
405    public byte[] getProcedure()
406    {
407        return getDecorated().getProcedure();
408    }
409
410
411    /**
412     * {@inheritDoc}
413     */
414    public List<StoredProcedureParameter> getParameters()
415    {
416        return getDecorated().getParameters();
417    }
418
419
420    /**
421     * {@inheritDoc}
422     */
423    public void addParameter( StoredProcedureParameter parameter )
424    {
425        getDecorated().addParameter( parameter );
426    }
427}