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.codec.controls.search.persistentSearch;
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.model.message.controls.ChangeType;
036import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
037import org.apache.directory.api.ldap.model.message.controls.PersistentSearchImpl;
038
039
040/**
041 * A persistence search object
042 * 
043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044 */
045public class PersistentSearchDecorator extends ControlDecorator<PersistentSearch> implements PersistentSearch
046{
047    /** A temporary storage for a psearch length */
048    private int psearchSeqLength;
049
050    /** An instance of this decoder */
051    private static final Asn1Decoder DECODER = new Asn1Decoder();
052
053
054    /**
055     * Default constructor creates a PersistentSearch Control automatically
056     * wrapped in a decorator object inside this container.
057     * 
058     * @param codec The LDAP service instance
059     */
060    public PersistentSearchDecorator( LdapApiService codec )
061    {
062        this( codec, new PersistentSearchImpl() );
063    }
064
065
066    /**
067     * Creates a PersistentSearch Control wrapping a supplied PersistentSearch
068     * Control.
069     *
070     * @param codec The LDAP service instance
071     * @param control The PersistentSearch Control to wrap.
072     */
073    public PersistentSearchDecorator( LdapApiService codec, PersistentSearch control )
074    {
075        super( codec, control );
076    }
077
078
079    /**
080     * Compute the PagedSearchControl length, which is the sum
081     * of the control length and the value length.
082     * 
083     * <pre>
084     * PersistentSearchDecorator value length :
085     * 
086     * 0x30 L1 
087     *   | 
088     *   +--&gt; 0x02 0x0(1-4) [0..2^31-1] (changeTypes) 
089     *   +--&gt; 0x01 0x01 [0x00 | 0xFF] (changeOnly) 
090     *   +--&gt; 0x01 0x01 [0x00 | 0xFF] (returnRCs)
091     * </pre>
092     *  
093     * @return the control length.
094     */
095    @Override
096    public int computeLength()
097    {
098        int changeTypesLength = 1 + 1 + BerValue.getNbBytes( getChangeTypes() );
099        int changesOnlyLength = 1 + 1 + 1;
100        int returnRCsLength = 1 + 1 + 1;
101
102        psearchSeqLength = changeTypesLength + changesOnlyLength + returnRCsLength;
103        
104        return 1 + TLV.getNbBytes( psearchSeqLength ) + psearchSeqLength;
105    }
106
107
108    /**
109     * Encodes the persistent search control.
110     * 
111     * @param buffer The encoded sink
112     * @return A ByteBuffer that contains the encoded PDU
113     * @throws EncoderException If anything goes wrong.
114     */
115    @Override
116    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
117    {
118        if ( buffer == null )
119        {
120            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
121        }
122
123        // Now encode the PagedSearch specific part
124        buffer.put( UniversalTag.SEQUENCE.getValue() );
125        buffer.put( TLV.getBytes( psearchSeqLength ) );
126
127        BerValue.encode( buffer, getChangeTypes() );
128        BerValue.encode( buffer, isChangesOnly() );
129        BerValue.encode( buffer, isReturnECs() );
130
131        return buffer;
132    }
133
134
135    /**
136     * {@inheritDoc}
137     */
138    @Override
139    public byte[] getValue()
140    {
141        if ( value == null )
142        {
143            try
144            {
145                valueLength = computeLength();
146                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
147
148                // Now encode the PagedSearch specific part
149                buffer.put( UniversalTag.SEQUENCE.getValue() );
150                buffer.put( TLV.getBytes( psearchSeqLength ) );
151
152                BerValue.encode( buffer, getChangeTypes() );
153                BerValue.encode( buffer, isChangesOnly() );
154                BerValue.encode( buffer, isReturnECs() );
155
156                value = buffer.array();
157            }
158            catch ( EncoderException ee )
159            {
160                return null;
161            }
162        }
163
164        return value;
165    }
166
167
168    private PersistentSearch getPersistentSearch()
169    {
170        return getDecorated();
171    }
172
173
174    /**
175     * {@inheritDoc}
176     */
177    @Override
178    public void setChangesOnly( boolean changesOnly )
179    {
180        getPersistentSearch().setChangesOnly( changesOnly );
181    }
182
183
184    /**
185     * {@inheritDoc}
186     */
187    @Override
188    public boolean isChangesOnly()
189    {
190        return getPersistentSearch().isChangesOnly();
191    }
192
193
194    /**
195     * {@inheritDoc}
196     */
197    @Override
198    public void setReturnECs( boolean returnECs )
199    {
200        getPersistentSearch().setReturnECs( returnECs );
201    }
202
203
204    /**
205     * {@inheritDoc}
206     */
207    @Override
208    public boolean isReturnECs()
209    {
210        return getPersistentSearch().isReturnECs();
211    }
212
213
214    /**
215     * {@inheritDoc}
216     */
217    @Override
218    public void setChangeTypes( int changeTypes )
219    {
220        getPersistentSearch().setChangeTypes( changeTypes );
221    }
222
223
224    /**
225     * {@inheritDoc}
226     */
227    @Override
228    public int getChangeTypes()
229    {
230        return getPersistentSearch().getChangeTypes();
231    }
232
233
234    /**
235     * {@inheritDoc}
236     */
237    @Override
238    public boolean isNotificationEnabled( ChangeType changeType )
239    {
240        return getPersistentSearch().isNotificationEnabled( changeType );
241    }
242
243
244    /**
245     * {@inheritDoc}
246     */
247    @Override
248    public void enableNotification( ChangeType changeType )
249    {
250        getPersistentSearch().enableNotification( changeType );
251    }
252
253
254    /**
255     * {@inheritDoc}
256     */
257    @Override
258    public void disableNotification( ChangeType changeType )
259    {
260        getPersistentSearch().disableNotification( changeType );
261    }
262
263
264    /**
265     * {@inheritDoc}
266     */
267    @Override
268    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
269    {
270        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
271        PersistentSearchContainer container = new PersistentSearchContainer( getCodecService(), this );
272        DECODER.decode( bb, container );
273        return this;
274    }
275}