blob: e750411f4780fe1de112a779684d084809c8e758 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.shared.ldap.codec;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import org.apache.directory.shared.asn1.codec.EncoderException;
import org.apache.directory.shared.asn1.codec.stateful.EncoderCallback;
import org.apache.directory.shared.asn1.codec.stateful.EncoderMonitor;
import org.apache.directory.shared.asn1.codec.stateful.StatefulEncoder;
import org.apache.directory.shared.i18n.I18n;
import org.apache.directory.shared.ldap.codec.add.AddRequestCodec;
import org.apache.directory.shared.ldap.message.spi.Provider;
import org.apache.directory.shared.ldap.message.spi.ProviderEncoder;
import org.apache.directory.shared.ldap.message.spi.ProviderException;
import org.apache.directory.shared.ldap.util.StringTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* LDAP BER provider's encoder.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public class LdapEncoder implements ProviderEncoder
{
//TM private static long cumul = 0L;
//TM private static long count = 0L;
//TM private Object lock = new Object();
/** The logger */
private static Logger log = LoggerFactory.getLogger( LdapEncoder.class );
/** A speedup for logger */
private static final boolean IS_DEBUG = log.isDebugEnabled();
/** The associated Provider */
final Provider provider;
/** The callback to call when the encoding is done */
private EncoderCallback encodeCallback;
/**
* Creates an instance of a Ldap Encoder implementation.
*
* @param provider The associated Provider
*/
public LdapEncoder( Provider provider )
{
this.provider = provider;
encodeCallback = new OutputCallback();
}
/**
* Encodes a LdapMessage, and calls the callback.
*
* @param lock Not used...
* @param out Not used ...
* @param obj The LdapMessage to encode
* @throws ProviderException If anything went wrong
*/
public void encodeBlocking( Object lock, OutputStream out, Object obj ) throws ProviderException
{
try
{
if ( IS_DEBUG )
{
log.debug( "Encoding this LdapMessage : " + obj );
}
( ( OutputCallback ) encodeCallback ).attach( out );
encodeCallback.encodeOccurred( null, ( ( LdapMessageCodec ) obj ).encode() );
}
catch ( EncoderException e )
{
log.error( I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
throw pe;
}
}
/**
* Encodes a LdapMessage, and return a ByteBuffer containing the resulting
* PDU
*
* @param obj The LdapMessage to encode
* @return The ByteBuffer containing the PDU
* @throws ProviderException If anything went wrong
*/
public ByteBuffer encodeBlocking( Object obj ) throws ProviderException
{
try
{
if ( IS_DEBUG )
{
log.debug( "Encoding this LdapMessage : " + obj );
}
ByteBuffer pdu = ( ( LdapMessageCodec ) obj ).encode();
if ( IS_DEBUG )
{
log.debug( "Encoded PDU : " + StringTools.dumpBytes( pdu.array() ) );
}
pdu.flip();
return pdu;
}
catch ( EncoderException e )
{
log.error( I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
throw pe;
}
}
/**
* Encodes a LdapMessage, and return a byte array containing the resulting
* PDU
*
* @param obj The LdapMessage to encode
* @return The byte[] containing the PDU
* @throws ProviderException If anything went wrong
*/
public byte[] encodeToArray( Object obj ) throws ProviderException
{
try
{
if ( IS_DEBUG )
{
log.debug( "Encoding this LdapMessage : " + obj );
}
byte[] pdu = ( ( LdapMessageCodec ) obj ).encode().array();
if ( IS_DEBUG )
{
log.debug( "Encoded PDU : " + StringTools.dumpBytes( pdu ) );
}
return pdu;
}
catch ( EncoderException e )
{
log.error( I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
throw pe;
}
}
/**
* Gets the Provider associated with this SPI implementation object.
*
* @return Provider The provider
*/
public Provider getProvider()
{
return provider;
}
/**
* Encodes a LdapMessage, and calls the callback
*
* @param obj The LdapMessage to encode
* @throws EncoderException If anything went wrong
*/
public void encode( Object obj ) throws EncoderException
{
//TM long t0 = System.nanoTime();
ByteBuffer encoded = encodeBlocking( obj );
encodeCallback.encodeOccurred( null, encoded );
//TM long t1 = System.nanoTime();
//TM synchronized (lock)
//TM {
//TM cumul += (t1 - t0);
//TM count++;
//TM
//TM
//TM if ( count % 1000L == 0)
//TM {
//TM System.out.println( "Encode cost : " + (cumul/count) );
//TM cumul = 0L;
//TM }
//TM }
}
/**
* Set the callback called when the encoding is done.
*
* @param cb The callback.
*/
public void setCallback( EncoderCallback cb )
{
encodeCallback = cb;
}
/**
* Not used ...
*
* @deprecated
*/
public void setEncoderMonitor( EncoderMonitor monitor )
{
}
/**
* The inner class used to write the PDU to a channel.
*/
class OutputCallback implements EncoderCallback
{
/** The channel in which the PDU will be written */
private WritableByteChannel channel = null;
/**
* Callback to deliver a fully encoded object.
*
* @param encoder the stateful encoder driving the callback
* @param encoded the object that was encoded
*/
public void encodeOccurred( StatefulEncoder encoder, Object encoded )
{
try
{
( ( ByteBuffer ) encoded ).flip();
channel.write( ( ByteBuffer ) encoded );
}
catch ( IOException e )
{
ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, "", e.getLocalizedMessage() ) );
throw pe;
}
}
/**
* Associate a channel to the callback
*
* @param channel The channel to use to write a PDU
*/
void attach( WritableByteChannel channel )
{
this.channel = channel;
}
/**
* Associate a OutputStream to the callback. A channel will be created.
*
* @param out The OutputStream to use
*/
void attach( OutputStream out )
{
this.channel = Channels.newChannel( out );
}
}
private static ByteBuffer encodeAsn1( AddRequestCodec addRequest )
{
//int length = computeLength( addRequest );
return null;
}
private static ByteBuffer encodeAsn1( LdapMessageCodec message ) throws EncoderException
{
ByteBuffer buffer = null;
switch ( message.getMessageType() )
{
case ABANDON_REQUEST :
return encodeAsn1( message );
case ADD_REQUEST :
case ADD_RESPONSE :
case BIND_REQUEST :
case BIND_RESPONSE :
case COMPARE_REQUEST :
case COMPARE_RESPONSE :
case DEL_REQUEST :
case DEL_RESPONSE :
case EXTENDED_REQUEST :
case EXTENDED_RESPONSE :
case INTERMEDIATE_RESPONSE :
case MODIFY_REQUEST :
case MODIFY_RESPONSE :
case MODIFYDN_REQUEST :
case MODIFYDN_RESPONSE :
case SEARCH_REQUEST :
case SEARCH_RESULT_DONE :
case SEARCH_RESULT_ENTRY :
case SEARCH_RESULT_REFERENCE :
case UNBIND_REQUEST :
}
return buffer;
}
}