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     */
020    
021    package org.apache.directory.shared.ldap.codec.extended.operations.storedProcedure;
022    
023    
024    import java.nio.BufferOverflowException;
025    import java.nio.ByteBuffer;
026    import java.util.ArrayList;
027    import java.util.LinkedList;
028    import java.util.List;
029    
030    import org.apache.directory.shared.asn1.AbstractAsn1Object;
031    import org.apache.directory.shared.asn1.ber.tlv.TLV;
032    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
033    import org.apache.directory.shared.asn1.ber.tlv.Value;
034    import org.apache.directory.shared.asn1.codec.EncoderException;
035    import org.apache.directory.shared.ldap.util.StringTools;
036    
037    
038    /**
039     * Stored Procedure Extended Operation bean
040     * 
041     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042     * @version $Rev$, $Date$, 
043     */
044    public class StoredProcedure extends AbstractAsn1Object
045    {
046        private String language;
047    
048        private byte[] procedure;
049    
050        private List<StoredProcedureParameter> parameters = new ArrayList<StoredProcedureParameter>();
051    
052        private StoredProcedureParameter currentParameter;
053        
054        /** The stored procedure length */
055        private int storedProcedureLength;
056        
057        /** The parameters length */
058        private int parametersLength;
059    
060        /** The list of all parameter lengths */
061        private List<Integer> parameterLength;
062    
063        /** The list of all parameter type lengths */
064        private List<Integer> paramTypeLength;
065    
066        /** The list of all parameter value lengths */
067        private List<Integer> paramValueLength;
068    
069        public String getLanguage()
070        {
071            return language;
072        }
073    
074    
075        public void setLanguage( String language )
076        {
077            this.language = language;
078        }
079    
080    
081        public byte[] getProcedure()
082        {
083            if ( procedure == null )
084            {
085                return null;
086            }
087    
088            final byte[] copy = new byte[ procedure.length ];
089            System.arraycopy( procedure, 0, copy, 0, procedure.length );
090            return copy;
091        }
092    
093    
094        public void setProcedure( byte[] procedure )
095        {
096            if ( procedure != null )
097            {
098                this.procedure = new byte[ procedure.length ];
099                System.arraycopy( procedure, 0, this.procedure, 0, procedure.length );
100            } else {
101                this.procedure = null;
102            }
103        }
104    
105    
106        public List<StoredProcedureParameter> getParameters()
107        {
108            return parameters;
109        }
110    
111    
112        public void addParameter( StoredProcedureParameter parameter )
113        {
114            parameters.add( parameter );
115        }
116    
117    
118        public StoredProcedureParameter getCurrentParameter()
119        {
120            return currentParameter;
121        }
122    
123    
124        public void setCurrentParameter( StoredProcedureParameter currentParameter )
125        {
126            this.currentParameter = currentParameter;
127        }
128        
129    
130        /**
131         * Bean for representing a Stored Procedure Parameter
132         */
133        public static class StoredProcedureParameter
134        {
135            byte[] type;
136    
137            byte[] value;
138    
139    
140            public byte[] getType()
141            {
142                if ( type == null )
143                {
144                    return null;
145                }
146    
147                final byte[] copy = new byte[ type.length ];
148                System.arraycopy( type, 0, copy, 0, type.length );
149                return copy;
150            }
151    
152    
153            public void setType( byte[] type )
154            {
155                if ( type != null )
156                {
157                    this.type = new byte[ type.length ];
158                    System.arraycopy( type, 0, this.type, 0, type.length );
159                } else {
160                    this.type = null;
161                }
162            }
163    
164    
165            public byte[] getValue()
166            {
167                if ( value == null )
168                {
169                    return null;
170                }
171    
172                final byte[] copy = new byte[ value.length ];
173                System.arraycopy( value, 0, copy, 0, value.length );
174                return copy;
175            }
176    
177    
178            public void setValue( byte[] value )
179            {
180                if ( value != null )
181                {
182                    this.value = new byte[ value.length ];
183                    System.arraycopy( value, 0, this.value, 0, value.length );
184                } else {
185                    this.value = null;
186                }
187            }
188        }
189    
190        /**
191         * Compute the StoredProcedure length 
192         * 
193         * 0x30 L1 
194         *   | 
195         *   +--> 0x04 L2 language
196         *   +--> 0x04 L3 procedure
197         *  [+--> 0x30 L4 (parameters)
198         *          |
199         *          +--> 0x30 L5-1 (parameter)
200         *          |      |
201         *          |      +--> 0x04 L6-1 type
202         *          |      +--> 0x04 L7-1 value
203         *          |      
204         *          +--> 0x30 L5-2 (parameter)
205         *          |      |
206         *          |      +--> 0x04 L6-2 type
207         *          |      +--> 0x04 L7-2 value
208         *          |
209         *          +--> ...
210         *          |      
211         *          +--> 0x30 L5-m (parameter)
212         *                 |
213         *                 +--> 0x04 L6-m type
214         *                 +--> 0x04 L7-m value
215         */
216        public int computeLength()
217        {
218            // The language
219            byte[] languageBytes = StringTools.getBytesUtf8( language );
220            
221            int languageLength = 1 + TLV.getNbBytes( languageBytes.length )
222                + languageBytes.length;
223            
224            // The procedure
225            int procedureLength = 1 + TLV.getNbBytes( procedure.length )
226                + procedure.length;
227            
228            // Compute parameters length value
229            if ( parameters != null )
230            {
231                parameterLength = new LinkedList<Integer>();
232                paramTypeLength = new LinkedList<Integer>();
233                paramValueLength = new LinkedList<Integer>();
234                
235                for ( StoredProcedureParameter spParam:parameters )
236                {
237                    int localParameterLength = 0;
238                    int localParamTypeLength = 0;
239                    int localParamValueLength = 0;
240                    
241                    localParamTypeLength = 1 + TLV.getNbBytes( spParam.type.length ) + spParam.type.length;
242                    localParamValueLength = 1 + TLV.getNbBytes( spParam.value.length ) + spParam.value.length;
243                    
244                    localParameterLength = localParamTypeLength + localParamValueLength;
245                    
246                    parametersLength += 1 + TLV.getNbBytes( localParameterLength ) + localParameterLength;
247                    
248                    parameterLength.add( localParameterLength );
249                    paramTypeLength.add( localParamTypeLength );
250                    paramValueLength.add( localParamValueLength );
251                }
252            }
253            
254            int localParametersLength = 1 + TLV.getNbBytes( parametersLength ) + parametersLength; 
255            storedProcedureLength = languageLength + procedureLength + localParametersLength;
256    
257            return 1 + TLV.getNbBytes( storedProcedureLength ) + storedProcedureLength; 
258        }
259    
260        /**
261         * Encode the StoredProcedure message to a PDU. 
262         * 
263         * @param buffer The buffer where to put the PDU
264         * @return The PDU.
265         */
266        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
267        {
268            // Allocate the bytes buffer.
269            ByteBuffer bb = ByteBuffer.allocate( computeLength() );
270    
271            try
272            {
273                // The StoredProcedure Tag
274                bb.put( UniversalTag.SEQUENCE_TAG );
275                bb.put( TLV.getBytes( storedProcedureLength ) );
276    
277                // The language
278                Value.encode( bb, language );
279    
280                // The procedure
281                Value.encode( bb, procedure );
282                
283                // The parameters sequence
284                bb.put( UniversalTag.SEQUENCE_TAG );
285                bb.put( TLV.getBytes( parametersLength ) );
286    
287                // The parameters list
288                if ( ( parameters != null ) && ( parameters.size() != 0 ) )
289                {
290                    int parameterNumber = 0;
291    
292                    for ( StoredProcedureParameter spParam:parameters )
293                    {
294                        // The parameter sequence
295                        bb.put( UniversalTag.SEQUENCE_TAG );
296                        int localParameterLength = parameterLength.get( parameterNumber );
297                        bb.put( TLV.getBytes( localParameterLength ) );
298    
299                        // The parameter type
300                        Value.encode( bb, spParam.type );
301    
302                        // The parameter value
303                        Value.encode( bb, spParam.value );
304    
305                        // Go to the next parameter;
306                        parameterNumber++;
307                    }
308                }
309            }
310            catch ( BufferOverflowException boe )
311            {
312                throw new EncoderException( "The PDU buffer size is too small !" );
313            }
314    
315            return bb;
316        }
317    
318    
319        /**
320         * Returns the StoredProcedure string
321         * 
322         * @return The StoredProcedure string
323         */
324        public String toString()
325        {
326    
327            StringBuffer sb = new StringBuffer();
328    
329            sb.append( "    StoredProcedure\n" );
330            sb.append( "        Language : '" ).append( language ).append( "'\n" );
331            sb.append( "        Procedure\n" ).append( StringTools.utf8ToString( procedure ) ).append( "'\n" );
332    
333            if ( ( parameters == null ) || ( parameters.size() == 0 ) )
334            {
335                sb.append( "        No parameters\n" );
336            }
337            else
338            {
339                sb.append( "        Parameters\n" );
340    
341                int i = 1;
342                
343                for ( StoredProcedureParameter spParam:parameters )
344                {
345                    sb.append( "            type[" ).append( i ) .append( "] : '" ).
346                        append( StringTools.utf8ToString( spParam.type ) ).append( "'\n" );
347                    sb.append( "            value[" ).append( i ) .append( "] : '" ).
348                        append( StringTools.dumpBytes( spParam.value ) ).append( "'\n" );
349                }
350            }
351    
352            return sb.toString();
353        }
354    }