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