View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.codec.controls.search.entryChange;
21  
22  
23  import java.nio.ByteBuffer;
24  
25  import org.apache.directory.api.asn1.Asn1Object;
26  import org.apache.directory.api.asn1.DecoderException;
27  import org.apache.directory.api.asn1.EncoderException;
28  import org.apache.directory.api.asn1.ber.Asn1Decoder;
29  import org.apache.directory.api.asn1.ber.tlv.BerValue;
30  import org.apache.directory.api.asn1.ber.tlv.TLV;
31  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.codec.api.ControlDecorator;
34  import org.apache.directory.api.ldap.codec.api.LdapApiService;
35  import org.apache.directory.api.ldap.model.message.controls.ChangeType;
36  import org.apache.directory.api.ldap.model.message.controls.EntryChange;
37  import org.apache.directory.api.ldap.model.message.controls.EntryChangeImpl;
38  import org.apache.directory.api.ldap.model.name.Dn;
39  import org.apache.directory.api.util.Strings;
40  
41  
42  /**
43   * An EntryChange implementation, that wraps and decorates the Control with codec
44   * specific functionality.
45   *
46   *
47   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
48   */
49  public class EntryChangeDecorator extends ControlDecorator<EntryChange> implements EntryChange
50  {
51      /** Default value when no change number is provided */
52      public static final int UNDEFINED_CHANGE_NUMBER = -1;
53  
54      /** A temporary storage for the previous Dn */
55      private byte[] previousDnBytes = null;
56  
57      /** The entry change global length */
58      private int eccSeqLength;
59  
60      /** An instance of this decoder */
61      private static final Asn1Decoder DECODER = new Asn1Decoder();
62  
63  
64      /**
65       * Creates a new instance of EntryChangeDecoder wrapping a newly created
66       * EntryChange Control object.
67       * 
68       * @param codec The LDAP service instance
69       */
70      public EntryChangeDecorator( LdapApiService codec )
71      {
72          super( codec, new EntryChangeImpl() );
73      }
74  
75  
76      /**
77       * Creates a new instance of EntryChangeDecorator wrapping the supplied
78       * EntryChange Control.
79       *
80       * @param codec The LDAP service instance
81       * @param control The EntryChange Control to be decorated.
82       */
83      public EntryChangeDecorator( LdapApiService codec, EntryChange control )
84      {
85          super( codec, control );
86      }
87  
88  
89      /**
90       * Internally used to not have to cast the decorated Control.
91       *
92       * @return the decorated Control.
93       */
94      private EntryChange getEntryChange()
95      {
96          return getDecorated();
97      }
98  
99  
100     /**
101      * Compute the EntryChangeControl length 
102      * 
103      * <pre>
104      * 0x30 L1 
105      *   | 
106      *   +--&gt; 0x0A 0x0(1-4) [1|2|4|8] (changeType) 
107      *  [+--&gt; 0x04 L2 previousDN] 
108      *  [+--&gt; 0x02 0x0(1-4) [0..2^63-1] (changeNumber)]
109      *  </pre>
110      *  
111      * @return the control length.
112      */
113     @Override
114     public int computeLength()
115     {
116         int changeTypesLength = 1 + 1 + 1;
117 
118         int previousDnLength = 0;
119         int changeNumberLength = 0;
120 
121         if ( getPreviousDn() != null )
122         {
123             previousDnBytes = Strings.getBytesUtf8( getPreviousDn().getName() );
124             previousDnLength = 1 + TLV.getNbBytes( previousDnBytes.length ) + previousDnBytes.length;
125         }
126 
127         if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
128         {
129             changeNumberLength = 1 + 1 + BerValue.getNbBytes( getChangeNumber() );
130         }
131 
132         eccSeqLength = changeTypesLength + previousDnLength + changeNumberLength;
133         valueLength = 1 + TLV.getNbBytes( eccSeqLength ) + eccSeqLength;
134 
135         return valueLength;
136     }
137 
138 
139     /**
140      * Encodes the entry change control.
141      * 
142      * @param buffer The encoded sink
143      * @return A ByteBuffer that contains the encoded PDU
144      * @throws EncoderException If anything goes wrong.
145      */
146     @Override
147     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
148     {
149         if ( buffer == null )
150         {
151             throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
152         }
153 
154         buffer.put( UniversalTag.SEQUENCE.getValue() );
155         buffer.put( TLV.getBytes( eccSeqLength ) );
156 
157         buffer.put( UniversalTag.ENUMERATED.getValue() );
158         buffer.put( ( byte ) 1 );
159         buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
160 
161         if ( getPreviousDn() != null )
162         {
163             BerValue.encode( buffer, previousDnBytes );
164         }
165 
166         if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
167         {
168             BerValue.encode( buffer, getChangeNumber() );
169         }
170 
171         return buffer;
172     }
173 
174 
175     /**
176      * {@inheritDoc}
177      */
178     @Override
179     public byte[] getValue()
180     {
181         if ( value == null )
182         {
183             try
184             {
185                 computeLength();
186                 ByteBuffer buffer = ByteBuffer.allocate( valueLength );
187 
188                 buffer.put( UniversalTag.SEQUENCE.getValue() );
189                 buffer.put( TLV.getBytes( eccSeqLength ) );
190 
191                 buffer.put( UniversalTag.ENUMERATED.getValue() );
192                 buffer.put( ( byte ) 1 );
193                 buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
194 
195                 if ( getPreviousDn() != null )
196                 {
197                     BerValue.encode( buffer, previousDnBytes );
198                 }
199 
200                 if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
201                 {
202                     BerValue.encode( buffer, getChangeNumber() );
203                 }
204 
205                 value = buffer.array();
206             }
207             catch ( Exception e )
208             {
209                 return null;
210             }
211         }
212 
213         return value;
214     }
215 
216 
217     /**
218      * {@inheritDoc}
219      */
220     @Override
221     public ChangeType getChangeType()
222     {
223         return getEntryChange().getChangeType();
224     }
225 
226 
227     /**
228      * {@inheritDoc}
229      */
230     @Override
231     public void setChangeType( ChangeType changeType )
232     {
233         getEntryChange().setChangeType( changeType );
234     }
235 
236 
237     /**
238      * {@inheritDoc}
239      */
240     @Override
241     public Dn getPreviousDn()
242     {
243         return getEntryChange().getPreviousDn();
244     }
245 
246 
247     /**
248      * {@inheritDoc}
249      */
250     @Override
251     public void setPreviousDn( Dn previousDn )
252     {
253         getEntryChange().setPreviousDn( previousDn );
254     }
255 
256 
257     /**
258      * {@inheritDoc}
259      */
260     @Override
261     public long getChangeNumber()
262     {
263         return getEntryChange().getChangeNumber();
264     }
265 
266 
267     /**
268      * {@inheritDoc}
269      */
270     @Override
271     public void setChangeNumber( long changeNumber )
272     {
273         getEntryChange().setChangeNumber( changeNumber );
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         EntryChangeContainer container = new EntryChangeContainer( getCodecService(), this );
285         DECODER.decode( bb, container );
286         return this;
287     }
288 }