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.shared.ldap.codec.api; 021 022 023import java.io.InputStream; 024import java.nio.ByteBuffer; 025import java.util.List; 026 027import org.apache.directory.shared.asn1.DecoderException; 028import org.apache.directory.shared.asn1.ber.Asn1Decoder; 029import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum; 030import org.apache.directory.shared.i18n.I18n; 031import org.apache.directory.shared.ldap.model.exception.ResponseCarryingMessageException; 032import org.apache.directory.shared.ldap.model.message.Message; 033import org.apache.directory.shared.util.Strings; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037 038/** 039 * The LdapDecoder decodes ASN.1 BER encoded PDUs into LDAP messages 040 * 041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 042 */ 043public class LdapDecoder 044{ 045 /** The logger */ 046 private static Logger LOG = LoggerFactory.getLogger( LdapDecoder.class ); 047 048 /** A speedup for logger */ 049 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 050 051 /** The ASN 1 decoder instance */ 052 private Asn1Decoder asn1Decoder; 053 054 /** 055 * Creates an instance of a Ldap Decoder implementation. 056 */ 057 public LdapDecoder() 058 { 059 asn1Decoder = new Asn1Decoder(); 060 } 061 062 063 /** 064 * Decodes a PDU from an input stream into a Ldap message container. We can only 065 * decode one complete message. 066 * 067 * @param in The input stream to read and decode PDU bytes from 068 * @return return The decoded message 069 */ 070 public Message decode( InputStream in, LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException 071 { 072 try 073 { 074 int amount; 075 076 while ( in.available() > 0 ) 077 { 078 byte[]buf = new byte[in.available()]; 079 080 if ( ( amount = in.read( buf ) ) == -1 ) 081 { 082 break; 083 } 084 085 asn1Decoder.decode( ByteBuffer.wrap( buf, 0, amount ), container ); 086 } 087 } 088 catch ( Exception e ) 089 { 090 String message = I18n.err( I18n.ERR_04060, e.getLocalizedMessage() ); 091 LOG.error( message ); 092 throw new DecoderException( message, e ); 093 } 094 095 if ( container.getState() == TLVStateEnum.PDU_DECODED ) 096 { 097 if ( IS_DEBUG ) 098 { 099 LOG.debug( "Decoded LdapMessage : " + container ); 100 } 101 102 return container.getMessage(); 103 } 104 else 105 { 106 LOG.error( I18n.err( I18n.ERR_04062 ) ); 107 throw new DecoderException( I18n.err( I18n.ERR_04063 ) ); 108 } 109 } 110 111 112 /** 113 * Decode an incoming buffer into LDAP messages. The result can be 0, 1 or many 114 * LDAP messages, which will be stored into the array the caller has created. 115 * 116 * @param buffer The incoming byte buffer 117 * @param messageContainer The LdapMessageContainer which will be used to store the 118 * message being decoded. If the message is not fully decoded, the ucrrent state 119 * is stored into this container 120 * @param decodedMessages The list of decoded messages 121 * @throws Exception If the decoding failed 122 */ 123 public void decode( ByteBuffer buffer, LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer, List<Message> decodedMessages ) throws DecoderException 124 { 125 buffer.mark(); 126 127 while ( buffer.hasRemaining() ) 128 { 129 try 130 { 131 if ( IS_DEBUG ) 132 { 133 LOG.debug( "Decoding the PDU : " ); 134 135 int size = buffer.limit(); 136 int position = buffer.position(); 137 int pduLength = size - position; 138 139 byte[] array = new byte[pduLength]; 140 141 System.arraycopy(buffer.array(), position, array, 0, pduLength); 142 143 buffer.position( size ); 144 145 if ( array.length == 0 ) 146 { 147 LOG.debug( "NULL buffer, what the HELL ???" ); 148 } 149 else 150 { 151 LOG.debug( Strings.dumpBytes(array) ); 152 } 153 154 buffer.reset(); 155 } 156 157 asn1Decoder.decode( buffer, messageContainer ); 158 159 if ( messageContainer.getState() == TLVStateEnum.PDU_DECODED ) 160 { 161 if ( IS_DEBUG ) 162 { 163 LOG.debug( "Decoded LdapMessage : " + messageContainer.getMessage() ); 164 } 165 166 Message message = messageContainer.getMessage(); 167 168 decodedMessages.add( message ); 169 170 messageContainer.clean(); 171 } 172 } 173 catch ( DecoderException de ) 174 { 175 buffer.clear(); 176 messageContainer.clean(); 177 178 if ( de instanceof ResponseCarryingException ) 179 { 180 // Transform the DecoderException message to a MessageException 181 ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( de.getMessage() ); 182 rcme.setResponse( ( ( ResponseCarryingException ) de ).getResponse() ); 183 184 throw rcme; 185 } 186 else 187 { 188 // TODO : This is certainly not the way we should handle such an exception ! 189 throw new ResponseCarryingException( de.getMessage() ); 190 } 191 } 192 } 193 } 194}