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.syncrepl_impl;
021
022
023import java.nio.ByteBuffer;
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.syncrepl.syncDone.SyncDoneValue;
036import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValueImpl;
037import org.apache.directory.api.util.Strings;
038
039
040/**
041 * A syncDoneValue object as described in rfc4533.
042 *
043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044 */
045public class SyncDoneValueDecorator extends ControlDecorator<SyncDoneValue> implements SyncDoneValue
046{
047    /** The global length for this control */
048    private int syncDoneValueLength;
049
050    /** An instance of this decoder */
051    private static final Asn1Decoder DECODER = new Asn1Decoder();
052
053
054    /**
055     * Creates a new instance of SyncDoneValueControlCodec.
056     * 
057     * @param codec The LDAP Service to use
058     */
059    public SyncDoneValueDecorator( LdapApiService codec )
060    {
061        super( codec, new SyncDoneValueImpl() );
062    }
063
064
065    /**
066     * Creates a new instance of SyncDoneValueDecorator.
067     *
068     * @param codec The LDAP codec
069     * @param control The control to be decorated
070     */
071    public SyncDoneValueDecorator( LdapApiService codec, SyncDoneValue control )
072    {
073        super( codec, control );
074    }
075
076
077    /**
078     * Compute the syncDoneValue length.
079     * <pre>
080     * 0x30 L1
081     * |
082     * +--&gt; 0x04 L2 xkcd!!!...     (cookie)
083     * +--&gt; 0x01 0x01 [0x00|0xFF]  (refreshDeletes)
084     * </pre>
085     * 
086     * @return The computed length
087     */
088    @Override
089    public int computeLength()
090    {
091        // cookie's length
092        if ( getCookie() != null )
093        {
094            syncDoneValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
095        }
096
097        // the refreshDeletes flag length
098        if ( isRefreshDeletes() )
099        {
100            syncDoneValueLength += 1 + 1 + 1;
101        }
102
103        valueLength = 1 + TLV.getNbBytes( syncDoneValueLength ) + syncDoneValueLength;
104
105        // Call the super class to compute the global control length
106        return valueLength;
107    }
108
109
110    /**
111     * Encode the SyncDoneValue control
112     *
113     * @param buffer The encoded sink
114     * @return A ByteBuffer that contains the encoded PDU
115     * @throws EncoderException If anything goes wrong while encoding.
116     */
117    @Override
118    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
119    {
120        if ( buffer == null )
121        {
122            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
123        }
124
125        // Encode the SEQ
126        buffer.put( UniversalTag.SEQUENCE.getValue() );
127        buffer.put( TLV.getBytes( syncDoneValueLength ) );
128
129        if ( getCookie() != null )
130        {
131            BerValue.encode( buffer, getCookie() );
132        }
133
134        if ( isRefreshDeletes() )
135        {
136            BerValue.encode( buffer, isRefreshDeletes() );
137        }
138
139        return buffer;
140    }
141
142
143    /**
144     * {@inheritDoc}
145     */
146    @Override
147    public byte[] getValue()
148    {
149        if ( value == null )
150        {
151            try
152            {
153                computeLength();
154                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
155
156                // Encode the SEQ
157                buffer.put( UniversalTag.SEQUENCE.getValue() );
158                buffer.put( TLV.getBytes( syncDoneValueLength ) );
159
160                if ( getCookie() != null )
161                {
162                    BerValue.encode( buffer, getCookie() );
163                }
164
165                if ( isRefreshDeletes() )
166                {
167                    BerValue.encode( buffer, isRefreshDeletes() );
168                }
169
170                value = buffer.array();
171            }
172            catch ( Exception e )
173            {
174                return null;
175            }
176        }
177
178        return value;
179    }
180
181
182    /**
183     * {@inheritDoc}
184     */
185    @Override
186    public byte[] getCookie()
187    {
188        return getDecorated().getCookie();
189    }
190
191
192    /**
193     * {@inheritDoc}
194     */
195    @Override
196    public void setCookie( byte[] cookie )
197    {
198        // Copy the bytes
199        if ( !Strings.isEmpty( cookie ) )
200        {
201            byte[] copy = new byte[cookie.length];
202            System.arraycopy( cookie, 0, copy, 0, cookie.length );
203            getDecorated().setCookie( copy );
204        }
205        else
206        {
207            getDecorated().setCookie( null );
208        }
209    }
210
211
212    /**
213     * {@inheritDoc}
214     */
215    @Override
216    public boolean isRefreshDeletes()
217    {
218        return getDecorated().isRefreshDeletes();
219    }
220
221
222    /**
223     * {@inheritDoc}
224     */
225    @Override
226    public void setRefreshDeletes( boolean refreshDeletes )
227    {
228        getDecorated().setRefreshDeletes( refreshDeletes );
229    }
230
231
232    /**
233     * {@inheritDoc}
234     */
235    @Override
236    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
237    {
238        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
239        SyncDoneValueContainer container = new SyncDoneValueContainer( getCodecService(), this );
240        DECODER.decode( bb, container );
241        return this;
242    }
243}