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    package org.apache.directory.shared.ldap.codec.controls;
021    
022    
023    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    
026    import org.apache.directory.shared.asn1.AbstractAsn1Object;
027    import org.apache.directory.shared.asn1.ber.tlv.TLV;
028    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
029    import org.apache.directory.shared.asn1.ber.tlv.Value;
030    import org.apache.directory.shared.asn1.codec.EncoderException;
031    import org.apache.directory.shared.i18n.I18n;
032    import org.apache.directory.shared.ldap.message.control.Control;
033    import org.apache.directory.shared.ldap.util.StringTools;
034    
035    
036    /**
037     * A Asn1Object to store a Control.
038     * 
039     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040     * @version $Rev: 912399 $, $Date: 2010-02-21 21:52:31 +0100 (Sun, 21 Feb 2010) $, 
041     */
042    public abstract class AbstractControl extends AbstractAsn1Object implements Control, CodecControl
043    {
044        // ~ Instance fields
045        // ----------------------------------------------------------------------------
046        /** The control type */
047        private String oid;
048    
049        /** The criticality (default value is false) */
050        private boolean criticality = false;
051    
052        /** Optional control value */
053        protected byte[] value;
054        
055        /** The encoded value length */
056        protected int valueLength;
057    
058        /** The control length */
059        private int controlLength;
060        
061        protected ControlDecoder decoder;
062    
063        // ~ Methods
064        // ------------------------------------------------------------------------------------
065    
066        /**
067         * Default constructor.
068         */
069        public AbstractControl( String oid )
070        {
071            this.oid = oid;
072        }
073    
074        /**
075         * Get the OID
076         * 
077         * @return A string which represent the control oid
078         */
079        public String getOid()
080        {
081            return oid == null ? "" : oid;
082        }
083    
084    
085        /**
086         * Get the control value
087         * 
088         * @return The control value
089         */
090        public byte[] getValue()
091        {
092            return value;
093        }
094    
095    
096        /**
097         * Set the encoded control value
098         * 
099         * @param encodedValue The encoded control value to store
100         */
101        public void setValue( byte[] value )
102        {
103            if ( value != null )
104            {
105                this.value = new byte[ value.length ];
106                System.arraycopy( value, 0, this.value, 0, value.length );
107            } 
108            else 
109            {
110                this.value = null;
111            }
112        }
113    
114    
115        /**
116         * Get the criticality
117         * 
118         * @return <code>true</code> if the criticality flag is true.
119         */
120        public boolean isCritical()
121        {
122            return criticality;
123        }
124    
125    
126        /**
127         * Set the criticality
128         * 
129         * @param criticality The criticality value
130         */
131        public void setCritical( boolean criticality )
132        {
133            this.criticality = criticality;
134        }
135    
136        
137        /**
138         * {@inheritDoc}
139         */
140        public int computeLength()
141        {
142            return 0;
143        }
144    
145    
146        /**
147         * {@inheritDoc}
148         */
149        public int computeLength( int valueLength )
150        {
151            // The OID
152            int oidLengh = StringTools.getBytesUtf8( oid ).length;
153            controlLength = 1 + TLV.getNbBytes( oidLengh ) + oidLengh;
154    
155            // The criticality, only if true
156            if ( criticality )
157            {
158                controlLength += 1 + 1 + 1; // Always 3 for a boolean
159            }
160    
161            this.valueLength = valueLength;
162            
163            if ( valueLength != 0 )
164            {
165                controlLength += 1 + TLV.getNbBytes( valueLength ) + valueLength;
166            }
167            
168            return 1 + TLV.getNbBytes( controlLength ) + controlLength;
169        }
170    
171    
172        /**
173         * {@inheritDoc}
174         */
175        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
176        {
177            if ( buffer == null )
178            {
179                throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
180            }
181    
182            try
183            {
184                // The LdapMessage Sequence
185                buffer.put( UniversalTag.SEQUENCE_TAG );
186    
187                // The length has been calculated by the computeLength method
188                buffer.put( TLV.getBytes( controlLength ) );
189            }
190            catch ( BufferOverflowException boe )
191            {
192                throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
193            }
194    
195            // The control type
196            Value.encode( buffer, getOid().getBytes() );
197    
198            // The control criticality, if true
199            if ( criticality )
200            {
201                Value.encode( buffer, criticality );
202            }
203    
204            return buffer;
205        }
206        
207        
208        /**
209         * {@inheritDoc}
210         */
211        public boolean hasValue()
212        {
213            return value != null;
214        }
215        
216        
217        public ControlDecoder getDecoder()
218        {
219            return decoder;
220        }
221    
222    
223        /**
224         * Return a String representing a Control
225         */
226        public String toString()
227        {
228            StringBuffer sb = new StringBuffer();
229    
230            sb.append( "    Control\n" );
231            sb.append( "        Control oid : '" ).append( oid ).append(
232                "'\n" );
233            sb.append( "        Criticality : '" ).append( criticality ).append( "'\n" );
234    
235            if ( value != null )
236            {
237                sb.append( "        Control value : '" ).append( StringTools.dumpBytes( value ) )
238                    .append( "'\n" );
239            }
240    
241            return sb.toString();
242        }
243    }