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    public SyncDoneValueDecorator( LdapApiService codec )
058    {
059        super( codec, new SyncDoneValueImpl() );
060    }
061
062
063    /**
064     * Creates a new instance of SyncDoneValueDecorator.
065     *
066     * @param codec The LDAP codec
067     * @param control The control to be decorated
068     */
069    public SyncDoneValueDecorator( LdapApiService codec, SyncDoneValue control )
070    {
071        super( codec, control );
072    }
073
074
075    /**
076     * Compute the syncDoneValue length.
077     * 0x30 L1
078     * |
079     * +--> 0x04 L2 xkcd!!!...     (cookie)
080     * +--> 0x01 0x01 [0x00|0xFF]  (refreshDeletes)
081     */
082    @Override
083    public int computeLength()
084    {
085        // cookie's length
086        if ( getCookie() != null )
087        {
088            syncDoneValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
089        }
090
091        // the refreshDeletes flag length
092        if ( isRefreshDeletes() )
093        {
094            syncDoneValueLength += 1 + 1 + 1;
095        }
096
097        valueLength = 1 + TLV.getNbBytes( syncDoneValueLength ) + syncDoneValueLength;
098
099        // Call the super class to compute the global control length
100        return valueLength;
101    }
102
103
104    /**
105     * Encode the SyncDoneValue control
106     *
107     * @param buffer The encoded sink
108     * @return A ByteBuffer that contains the encoded PDU
109     * @throws EncoderException If anything goes wrong while encoding.
110     */
111    @Override
112    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
113    {
114        if ( buffer == null )
115        {
116            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
117        }
118
119        // Encode the SEQ
120        buffer.put( UniversalTag.SEQUENCE.getValue() );
121        buffer.put( TLV.getBytes( syncDoneValueLength ) );
122
123        if ( getCookie() != null )
124        {
125            BerValue.encode( buffer, getCookie() );
126        }
127
128        if ( isRefreshDeletes() )
129        {
130            BerValue.encode( buffer, isRefreshDeletes() );
131        }
132
133        return buffer;
134    }
135
136
137    /**
138     * {@inheritDoc}
139     */
140    @Override
141    public byte[] getValue()
142    {
143        if ( value == null )
144        {
145            try
146            {
147                computeLength();
148                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
149
150                // Encode the SEQ
151                buffer.put( UniversalTag.SEQUENCE.getValue() );
152                buffer.put( TLV.getBytes( syncDoneValueLength ) );
153
154                if ( getCookie() != null )
155                {
156                    BerValue.encode( buffer, getCookie() );
157                }
158
159                if ( isRefreshDeletes() )
160                {
161                    BerValue.encode( buffer, isRefreshDeletes() );
162                }
163
164                value = buffer.array();
165            }
166            catch ( Exception e )
167            {
168                return null;
169            }
170        }
171
172        return value;
173    }
174
175
176    /**
177     * {@inheritDoc}
178     */
179    public byte[] getCookie()
180    {
181        return getDecorated().getCookie();
182    }
183
184
185    /**
186     * {@inheritDoc}
187     */
188    public void setCookie( byte[] cookie )
189    {
190        // Copy the bytes
191        if ( !Strings.isEmpty( cookie ) )
192        {
193            byte[] copy = new byte[cookie.length];
194            System.arraycopy( cookie, 0, copy, 0, cookie.length );
195            getDecorated().setCookie( copy );
196        }
197        else
198        {
199            getDecorated().setCookie( null );
200        }
201    }
202
203
204    /**
205     * {@inheritDoc}
206     */
207    public boolean isRefreshDeletes()
208    {
209        return getDecorated().isRefreshDeletes();
210    }
211
212
213    /**
214     * {@inheritDoc}
215     */
216    public void setRefreshDeletes( boolean refreshDeletes )
217    {
218        getDecorated().setRefreshDeletes( refreshDeletes );
219    }
220
221
222    /**
223     * {@inheritDoc}
224     */
225    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
226    {
227        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
228        SyncDoneValueContainer container = new SyncDoneValueContainer( getCodecService(), this );
229        decoder.decode( bb, container );
230        return this;
231    }
232}