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  
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      public EntryChangeDecorator( LdapApiService codec )
69      {
70          super( codec, new EntryChangeImpl() );
71      }
72  
73  
74      /**
75       * Creates a new instance of EntryChangeDecorator wrapping the supplied
76       * EntryChange Control.
77       *
78       * @param control The EntryChange Control to be decorated.
79       */
80      public EntryChangeDecorator( LdapApiService codec, EntryChange control )
81      {
82          super( codec, control );
83      }
84  
85  
86      /**
87       * Internally used to not have to cast the decorated Control.
88       *
89       * @return the decorated Control.
90       */
91      private EntryChange getEntryChange()
92      {
93          return ( EntryChange ) getDecorated();
94      }
95  
96  
97      /**
98       * Compute the EntryChangeControl length 
99       * 
100      * 0x30 L1 
101      *   | 
102      *   +--> 0x0A 0x0(1-4) [1|2|4|8] (changeType) 
103      *  [+--> 0x04 L2 previousDN] 
104      *  [+--> 0x02 0x0(1-4) [0..2^63-1] (changeNumber)]
105      */
106     public int computeLength()
107     {
108         int changeTypesLength = 1 + 1 + 1;
109 
110         int previousDnLength = 0;
111         int changeNumberLength = 0;
112 
113         if ( getPreviousDn() != null )
114         {
115             previousDnBytes = Strings.getBytesUtf8( getPreviousDn().getName() );
116             previousDnLength = 1 + TLV.getNbBytes( previousDnBytes.length ) + previousDnBytes.length;
117         }
118 
119         if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
120         {
121             changeNumberLength = 1 + 1 + BerValue.getNbBytes( getChangeNumber() );
122         }
123 
124         eccSeqLength = changeTypesLength + previousDnLength + changeNumberLength;
125         valueLength = 1 + TLV.getNbBytes( eccSeqLength ) + eccSeqLength;
126 
127         return valueLength;
128     }
129 
130 
131     /**
132      * Encodes the entry change control.
133      * 
134      * @param buffer The encoded sink
135      * @return A ByteBuffer that contains the encoded PDU
136      * @throws EncoderException If anything goes wrong.
137      */
138     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
139     {
140         if ( buffer == null )
141         {
142             throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
143         }
144 
145         buffer.put( UniversalTag.SEQUENCE.getValue() );
146         buffer.put( TLV.getBytes( eccSeqLength ) );
147 
148         buffer.put( UniversalTag.ENUMERATED.getValue() );
149         buffer.put( ( byte ) 1 );
150         buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
151 
152         if ( getPreviousDn() != null )
153         {
154             BerValue.encode( buffer, previousDnBytes );
155         }
156 
157         if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
158         {
159             BerValue.encode( buffer, getChangeNumber() );
160         }
161 
162         return buffer;
163     }
164 
165 
166     /**
167      * {@inheritDoc}
168      */
169     public byte[] getValue()
170     {
171         if ( value == null )
172         {
173             try
174             {
175                 computeLength();
176                 ByteBuffer buffer = ByteBuffer.allocate( valueLength );
177 
178                 buffer.put( UniversalTag.SEQUENCE.getValue() );
179                 buffer.put( TLV.getBytes( eccSeqLength ) );
180 
181                 buffer.put( UniversalTag.ENUMERATED.getValue() );
182                 buffer.put( ( byte ) 1 );
183                 buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
184 
185                 if ( getPreviousDn() != null )
186                 {
187                     BerValue.encode( buffer, previousDnBytes );
188                 }
189 
190                 if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
191                 {
192                     BerValue.encode( buffer, getChangeNumber() );
193                 }
194 
195                 value = buffer.array();
196             }
197             catch ( Exception e )
198             {
199                 return null;
200             }
201         }
202 
203         return value;
204     }
205 
206 
207     /**
208      * {@inheritDoc}
209      */
210     public ChangeType getChangeType()
211     {
212         return getEntryChange().getChangeType();
213     }
214 
215 
216     /**
217      * {@inheritDoc}
218      */
219     public void setChangeType( ChangeType changeType )
220     {
221         getEntryChange().setChangeType( changeType );
222     }
223 
224 
225     /**
226      * {@inheritDoc}
227      */
228     public Dn getPreviousDn()
229     {
230         return getEntryChange().getPreviousDn();
231     }
232 
233 
234     /**
235      * {@inheritDoc}
236      */
237     public void setPreviousDn( Dn previousDn )
238     {
239         getEntryChange().setPreviousDn( previousDn );
240     }
241 
242 
243     /**
244      * {@inheritDoc}
245      */
246     public long getChangeNumber()
247     {
248         return getEntryChange().getChangeNumber();
249     }
250 
251 
252     /**
253      * {@inheritDoc}
254      */
255     public void setChangeNumber( long changeNumber )
256     {
257         getEntryChange().setChangeNumber( changeNumber );
258     }
259 
260 
261     /**
262      * {@inheritDoc}
263      */
264     public Asn1Object decode( byte[] controlBytes ) throws DecoderException
265     {
266         ByteBuffer bb = ByteBuffer.wrap( controlBytes );
267         EntryChangeContainer container = new EntryChangeContainer( getCodecService(), this );
268         decoder.decode( bb, container );
269         return this;
270     }
271 }