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.controls.ad;
021
022import java.nio.ByteBuffer;
023
024import org.apache.directory.api.asn1.Asn1Object;
025import org.apache.directory.api.asn1.DecoderException;
026import org.apache.directory.api.asn1.EncoderException;
027import org.apache.directory.api.asn1.ber.Asn1Decoder;
028import org.apache.directory.api.asn1.ber.tlv.BerValue;
029import org.apache.directory.api.asn1.ber.tlv.TLV;
030import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
031import org.apache.directory.api.i18n.I18n;
032import org.apache.directory.api.ldap.codec.api.ControlDecorator;
033import org.apache.directory.api.ldap.codec.api.LdapApiService;
034import org.apache.directory.api.util.Strings;
035
036/**
037 * A decorator around AdDirSync control. It will encode and decode this control.
038 * 
039 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040 */
041public class AdDirSyncDecorator extends ControlDecorator<AdDirSync> implements AdDirSync
042{
043    /** The global length for this control */
044    private int adDirSyncLength;
045
046    /** An instance of this decoder */
047    private static final Asn1Decoder decoder = new Asn1Decoder();
048
049
050    /**
051     * Creates a new instance of AdDirSyncControlCodec.
052     */
053    public AdDirSyncDecorator( LdapApiService codec )
054    {
055        super( codec, new AdDirSyncImpl() );
056    }
057
058
059    /**
060     * Creates a new instance of AdDirSyncDecorator.
061     *
062     * @param codec The LDAP codec
063     * @param control The control to be decorated
064     */
065    public AdDirSyncDecorator( LdapApiService codec, AdDirSync control )
066    {
067        super( codec, control );
068    }
069    
070    
071    /**
072     * {@inheritDoc}
073     */
074    public int getParentFirst()
075    {
076        return getDecorated().getParentFirst();
077    }
078
079    
080    /**
081     * {@inheritDoc}
082     */
083    public void setParentFirst( int parentFirst )
084    {
085        getDecorated().setParentFirst( parentFirst );
086    }
087    
088    
089    /**
090     * {@inheritDoc}
091     */
092    public AdDirSyncFlag getFlag()
093    {
094        return getDecorated().getFlag();
095    }
096
097    
098    /**
099     * {@inheritDoc}
100     */
101    public void setFlag( AdDirSyncFlag flag )
102    {
103        getDecorated().setFlag( flag );
104    }
105
106    
107    /**
108     * {@inheritDoc}
109     */
110    public int getMaxReturnLength()
111    {
112        return getDecorated().getMaxReturnLength();
113    }
114
115    
116    /**
117     * {@inheritDoc}
118     */
119    public void setMaxReturnLength( int maxReturnLength )
120    {
121        getDecorated().setMaxReturnLength( maxReturnLength );
122    }
123    
124
125    /**
126     * {@inheritDoc}
127     */
128    public byte[] getCookie()
129    {
130        return getDecorated().getCookie();
131    }
132
133
134    /**
135     * {@inheritDoc}
136     */
137    public void setCookie( byte[] cookie )
138    {
139        // Copy the bytes
140        if ( !Strings.isEmpty( cookie ) )
141        {
142            byte[] copy = new byte[cookie.length];
143            System.arraycopy( cookie, 0, copy, 0, cookie.length );
144            getDecorated().setCookie( copy );
145        }
146        else
147        {
148            getDecorated().setCookie( null );
149        }
150    }
151
152
153    /**
154     * Compute the AdDirSync length. We use the client side control.
155     * 0x30 L1
156     * |
157     * +--> 0x02 0x0(1-4) nnn  (parentFirst)
158     * +--> 0x02 0x0(1-4) nnn  (maxReturnLength)
159     * +--> 0x04 L2 xkcd!!!...     (cookie)
160     */
161    @Override
162    public int computeLength()
163    {
164        // the parentFirst flag length
165        adDirSyncLength = 1 + TLV.getNbBytes( getParentFirst() ) + BerValue.getNbBytes( getParentFirst() );
166
167        // the maxReturnLength length
168        adDirSyncLength += 1 + TLV.getNbBytes( getMaxReturnLength() ) + BerValue.getNbBytes( getMaxReturnLength() );
169
170        // cookie's length
171        byte[] cookie = getCookie();
172        
173        if ( cookie == null )
174        {
175            adDirSyncLength += 1 + 1;
176        }
177        else
178        {
179            adDirSyncLength += 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
180        }
181
182        valueLength = 1 + TLV.getNbBytes( adDirSyncLength ) + adDirSyncLength;
183
184        // Call the super class to compute the global control length
185        return valueLength;
186    }
187
188
189    /**
190     * Encode the AdDirSync control. We use the client side control.
191     *
192     * @param buffer The encoded sink
193     * @return A ByteBuffer that contains the encoded PDU
194     * @throws EncoderException If anything goes wrong while encoding.
195     */
196    @Override
197    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
198    {
199        if ( buffer == null )
200        {
201            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
202        }
203
204        // Encode the SEQ
205        buffer.put( UniversalTag.SEQUENCE.getValue() );
206        buffer.put( TLV.getBytes( adDirSyncLength ) );
207
208        // Encode the ParentFirst flag
209        BerValue.encode( buffer, getParentFirst() );
210
211        // Encode the MaxReturnLength
212        BerValue.encode( buffer, getMaxReturnLength() );
213        
214        // Encode the cookie
215        BerValue.encode( buffer, getCookie() );
216
217        return buffer;
218    }
219
220
221    /**
222     * {@inheritDoc}
223     */
224    @Override
225    public byte[] getValue()
226    {
227        if ( value == null )
228        {
229            try
230            {
231                computeLength();
232                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
233
234                // Encode the SEQ
235                buffer.put( UniversalTag.SEQUENCE.getValue() );
236                buffer.put( TLV.getBytes( adDirSyncLength ) );
237
238                // Encode the ParentFirst flag
239                BerValue.encode( buffer, getParentFirst() );
240
241                // Encode the MaxReturnLength
242                BerValue.encode( buffer, getMaxReturnLength() );
243                
244                // Encode the cookie
245                BerValue.encode( buffer, getCookie() );
246
247                value = buffer.array();
248            }
249            catch ( Exception e )
250            {
251                return null;
252            }
253        }
254
255        return value;
256    }
257    
258    
259    /**
260     * {@inheritDoc}
261     */
262    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
263    {
264        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
265        AdDirSyncContainer container = new AdDirSyncContainer( getCodecService(), this );
266        decoder.decode( bb, container );
267        return this;
268    }
269}