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 21:52:31 +0100 (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 }