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 */
020 package org.apache.directory.shared.ldap.codec;
021
022
023 import java.io.InputStream;
024 import java.nio.ByteBuffer;
025
026 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
027 import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
028 import org.apache.directory.shared.asn1.codec.DecoderException;
029 import org.apache.directory.shared.asn1.codec.stateful.DecoderCallback;
030 import org.apache.directory.shared.asn1.codec.stateful.DecoderMonitor;
031 import org.apache.directory.shared.i18n.I18n;
032 import org.apache.directory.shared.ldap.message.spi.BinaryAttributeDetector;
033 import org.apache.directory.shared.ldap.message.spi.Provider;
034 import org.apache.directory.shared.ldap.message.spi.ProviderDecoder;
035 import org.apache.directory.shared.ldap.message.spi.ProviderException;
036 import org.apache.directory.shared.ldap.util.StringTools;
037 import org.slf4j.Logger;
038 import org.slf4j.LoggerFactory;
039
040
041 /**
042 * The LdapDecoder decodes ASN.1 BER encoded PDUs.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 * @version $Rev: 912399 $, $Date: 2010-02-21 22:52:31 +0200 (Sun, 21 Feb 2010) $,
046 */
047 public class LdapDecoder implements ProviderDecoder
048 {
049 /** The logger */
050 private static Logger log = LoggerFactory.getLogger( LdapDecoder.class );
051
052 /** A speedup for logger */
053 private static final boolean IS_DEBUG = log.isDebugEnabled();
054
055 /** The associated Provider */
056 private final Provider provider;
057
058 /** The message container for this instance */
059 private final LdapMessageContainer ldapMessageContainer;
060
061 /** The Ldap BDER decoder instance */
062 private final Asn1Decoder ldapDecoder;
063
064 /** The callback to call when the decoding is done */
065 private DecoderCallback decoderCallback;
066
067
068 /**
069 * Creates an instance of a Ldap Decoder implementation.
070 *
071 * @param provider the owning provider.
072 * @param binaryAttributeDetector checks for binary attributes
073 * @param maxPDUSize the maximum size a PDU can be
074 */
075 public LdapDecoder( Provider provider, BinaryAttributeDetector binaryAttributeDetector, int maxPDUSize )
076 {
077 this.provider = provider;
078 ldapMessageContainer = new LdapMessageContainer( binaryAttributeDetector );
079 ldapDecoder = new Asn1Decoder();
080
081 ldapMessageContainer.setMaxPDUSize( maxPDUSize );
082 }
083
084
085 /**
086 * Decodes a PDU
087 *
088 * @param encoded The PDU containing the LdapMessage to decode
089 * @throws DecoderException if anything goes wrong
090 */
091 public void decode( Object encoded ) throws DecoderException
092 {
093 ByteBuffer buf;
094 int position = 0;
095
096 if ( encoded instanceof ByteBuffer )
097 {
098 buf = ( ByteBuffer ) encoded;
099 }
100 else if ( encoded instanceof byte[] )
101 {
102 buf = ByteBuffer.wrap( ( byte[] ) encoded );
103 }
104 else
105 {
106 throw new DecoderException( I18n.err( I18n.ERR_04059, encoded.getClass() ) );
107 }
108
109 while ( buf.hasRemaining() )
110 {
111 try
112 {
113 ldapDecoder.decode( buf, ldapMessageContainer );
114
115 if ( IS_DEBUG )
116 {
117 log.debug( "Decoding the PDU : " );
118
119 int size = buf.position();
120 buf.flip();
121
122 byte[] array = new byte[ size - position ];
123
124 for ( int i = position; i < size; i++ )
125 {
126 array[ i ] = buf.get();
127 }
128
129 position = size;
130
131 log.debug( StringTools.dumpBytes( array ) );
132 }
133
134 if ( ldapMessageContainer.getState() == TLVStateEnum.PDU_DECODED )
135 {
136 if ( IS_DEBUG )
137 {
138 log.debug( "Decoded LdapMessage : " + ldapMessageContainer.getLdapMessage() );
139 buf.mark();
140 }
141
142 decoderCallback.decodeOccurred( null, ldapMessageContainer.getLdapMessage() );
143 ldapMessageContainer.clean();
144 }
145 }
146 catch ( DecoderException de )
147 {
148 buf.clear();
149 ldapMessageContainer.clean();
150 throw de;
151 }
152 }
153 }
154
155
156 /**
157 * Feeds the bytes within the input stream to the digester to generate the
158 * resultant decoded Message.
159 *
160 * @param in The InputStream containing the PDU to be decoded
161 * @throws ProviderException If the decoding went wrong
162 */
163 private void digest( InputStream in ) throws ProviderException
164 {
165 byte[] buf;
166
167 try
168 {
169 int amount;
170
171 while ( in.available() > 0 )
172 {
173 buf = new byte[in.available()];
174
175 if ( ( amount = in.read( buf ) ) == -1 )
176 {
177 break;
178 }
179
180 ldapDecoder.decode( ByteBuffer.wrap( buf, 0, amount ), ldapMessageContainer );
181 }
182 }
183 catch ( Exception e )
184 {
185 log.error( I18n.err( I18n.ERR_04060, e.getLocalizedMessage() ) );
186 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04061 ) );
187 pe.addThrowable( e );
188 throw pe;
189 }
190 }
191
192
193 /**
194 * Decodes a PDU from an input stream into a Snickers compiler generated
195 * stub envelope.
196 *
197 * @param lock Lock object used to exclusively read from the input stream
198 * @param in The input stream to read and decode PDU bytes from
199 * @return return decoded stub
200 */
201 public Object decode( Object lock, InputStream in ) throws ProviderException
202 {
203 if ( lock == null )
204 {
205 digest( in );
206
207 if ( ldapMessageContainer.getState() == TLVStateEnum.PDU_DECODED )
208 {
209 if ( IS_DEBUG )
210 {
211 log.debug( "Decoded LdapMessage : " + ldapMessageContainer.getLdapMessage() );
212 }
213
214 return ldapMessageContainer.getLdapMessage();
215 }
216 else
217 {
218 log.error( I18n.err( I18n.ERR_04062 ) );
219 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04061 ) );
220 //noinspection ThrowableInstanceNeverThrown
221 pe.addThrowable( new DecoderException( I18n.err( I18n.ERR_04063 ) ) );
222 throw pe;
223 }
224 }
225 else
226 {
227 try
228 {
229 // Synchronize on the input lock object to prevent concurrent
230 // reads
231 synchronized ( lock )
232 {
233 digest( in );
234
235 // Notify/awaken threads waiting to read from input stream
236 lock.notifyAll();
237 }
238 }
239 catch ( Exception e )
240 {
241 log.error( I18n.err( I18n.ERR_04060, e.getLocalizedMessage() ) );
242 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04061 ) );
243 pe.addThrowable( e );
244 throw pe;
245 }
246
247 if ( ldapMessageContainer.getState() == TLVStateEnum.PDU_DECODED )
248 {
249 if ( IS_DEBUG )
250 {
251 log.debug( "Decoded LdapMessage : " + ldapMessageContainer.getLdapMessage() );
252 }
253
254 return ldapMessageContainer.getLdapMessage();
255 }
256 else
257 {
258 log.error( I18n.err( I18n.ERR_04064 ) );
259 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04062 ) );
260 //noinspection ThrowableInstanceNeverThrown
261 pe.addThrowable( new DecoderException( I18n.err( I18n.ERR_04063 ) ) );
262 throw pe;
263 }
264 }
265 }
266
267
268 /**
269 * Gets the Provider that this Decoder implementation is part of.
270 *
271 * @return the owning provider.
272 */
273 public Provider getProvider()
274 {
275 return provider;
276 }
277
278
279 /**
280 * Not used ...
281 *
282 * @deprecated
283 */
284 public void setDecoderMonitor( DecoderMonitor monitor )
285 {
286 }
287
288
289 /**
290 * Set the callback to call when the PDU has been decoded
291 *
292 * @param cb The callback
293 */
294 public void setCallback( DecoderCallback cb )
295 {
296 decoderCallback = cb;
297 }
298 }