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 * https://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.api.ldap.codec.protocol.mina; 021 022 023import java.nio.ByteBuffer; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.apache.directory.api.asn1.DecoderException; 028import org.apache.directory.api.asn1.ber.Asn1Decoder; 029import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum; 030import org.apache.directory.api.i18n.I18n; 031import org.apache.directory.api.ldap.codec.api.LdapDecoder; 032import org.apache.directory.api.ldap.codec.api.LdapMessageContainer; 033import org.apache.directory.api.ldap.codec.api.ResponseCarryingException; 034import org.apache.directory.api.ldap.model.constants.Loggers; 035import org.apache.directory.api.ldap.model.exception.ResponseCarryingMessageException; 036import org.apache.directory.api.ldap.model.message.AbstractMessage; 037import org.apache.directory.api.ldap.model.message.Message; 038import org.apache.directory.api.util.Strings; 039import org.apache.mina.core.buffer.IoBuffer; 040import org.apache.mina.core.session.IoSession; 041import org.apache.mina.filter.codec.ProtocolDecoder; 042import org.apache.mina.filter.codec.ProtocolDecoderOutput; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046 047/** 048 * A LDAP message decoder. It is based on api-ldap decoder. 049 * 050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 051 */ 052public class LdapProtocolDecoder implements ProtocolDecoder 053{ 054 /** The logger */ 055 private static final Logger CODEC_LOG = LoggerFactory.getLogger( Loggers.CODEC_LOG.getName() ); 056 057 /** 058 * Creates a new instance of LdapProtocolEncoder. 059 */ 060 public LdapProtocolDecoder() 061 { 062 } 063 064 065 /** 066 * {@inheritDoc} 067 */ 068 @Override 069 public void decode( IoSession session, IoBuffer in, ProtocolDecoderOutput out ) throws Exception 070 { 071 @SuppressWarnings("unchecked") 072 LdapMessageContainer<AbstractMessage> messageContainer = 073 ( LdapMessageContainer<AbstractMessage> ) 074 session.getAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR ); 075 076 if ( session.containsAttribute( LdapDecoder.MAX_PDU_SIZE_ATTR ) ) 077 { 078 int maxPDUSize = ( Integer ) session.getAttribute( LdapDecoder.MAX_PDU_SIZE_ATTR ); 079 080 messageContainer.setMaxPDUSize( maxPDUSize ); 081 } 082 083 List<Message> decodedMessages = new ArrayList<>(); 084 ByteBuffer buf = in.buf(); 085 086 decode( buf, messageContainer, decodedMessages ); 087 088 for ( Message message : decodedMessages ) 089 { 090 out.write( message ); 091 } 092 } 093 094 095 /** 096 * Decode an incoming buffer into LDAP messages. The result can be 0, 1 or many 097 * LDAP messages, which will be stored into the array the caller has created. 098 * 099 * @param buffer The incoming byte buffer 100 * @param messageContainer The LdapMessageContainer which will be used to store the 101 * message being decoded. If the message is not fully decoded, the ucrrent state 102 * is stored into this container 103 * @param decodedMessages The list of decoded messages 104 * @throws DecoderException If the decoding failed 105 */ 106 private void decode( ByteBuffer buffer, LdapMessageContainer<AbstractMessage> messageContainer, 107 List<Message> decodedMessages ) throws DecoderException 108 { 109 buffer.mark(); 110 111 while ( buffer.hasRemaining() ) 112 { 113 try 114 { 115 if ( CODEC_LOG.isDebugEnabled() ) 116 { 117 CODEC_LOG.debug( I18n.msg( I18n.MSG_14000_DECODING_PDU ) ); 118 119 int size = buffer.limit(); 120 int position = buffer.position(); 121 int pduLength = size - position; 122 123 byte[] array = new byte[pduLength]; 124 125 System.arraycopy( buffer.array(), position, array, 0, pduLength ); 126 127 if ( array.length == 0 ) 128 { 129 CODEC_LOG.debug( I18n.msg( I18n.MSG_14001_NULL_BUFFER ) ); 130 } 131 else 132 { 133 CODEC_LOG.debug( Strings.dumpBytes( array ) ); 134 } 135 } 136 137 Asn1Decoder.decode( buffer, messageContainer ); 138 139 if ( messageContainer.getState() == TLVStateEnum.PDU_DECODED ) 140 { 141 if ( CODEC_LOG.isDebugEnabled() ) 142 { 143 CODEC_LOG.debug( I18n.msg( I18n.MSG_14002_DECODED_LDAP_MESSAGE, messageContainer.getMessage() ) ); 144 } 145 146 Message message = messageContainer.getMessage(); 147 148 decodedMessages.add( message ); 149 150 messageContainer.clean(); 151 } 152 } 153 catch ( ResponseCarryingException rce ) 154 { 155 buffer.clear(); 156 messageContainer.clean(); 157 158 // Transform the DecoderException message to a MessageException 159 ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( rce.getMessage(), rce ); 160 rcme.setResponse( rce.getResponse() ); 161 162 throw rcme; 163 } 164 catch ( DecoderException de ) 165 { 166 buffer.clear(); 167 messageContainer.clean(); 168 169 // TODO : This is certainly not the way we should handle such an exception ! 170 throw new ResponseCarryingException( de.getMessage(), de ); 171 } 172 } 173 } 174 175 176 /** 177 * {@inheritDoc} 178 */ 179 @Override 180 public void finishDecode( IoSession session, ProtocolDecoderOutput out ) throws Exception 181 { 182 // Nothing to do 183 } 184 185 186 /** 187 * {@inheritDoc} 188 */ 189 @Override 190 public void dispose( IoSession session ) throws Exception 191 { 192 // Nothing to do 193 } 194}