blob: 5d2a54671ad6ddb172a0d4933d5a0d98b8be9744 [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.message;
import org.apache.directory.shared.asn1.Asn1Object;
import org.apache.directory.shared.asn1.codec.DecoderException;
import org.apache.directory.shared.asn1.codec.stateful.DecoderCallback;
import org.apache.directory.shared.asn1.codec.stateful.DecoderMonitor;
import org.apache.directory.shared.asn1.codec.stateful.StatefulDecoder;
import org.apache.directory.shared.ldap.codec.ResponseCarryingException;
import org.apache.directory.shared.ldap.codec.LdapTransformer;
import org.apache.directory.shared.ldap.message.spi.BinaryAttributeDetector;
import org.apache.directory.shared.ldap.message.spi.Provider;
import org.apache.directory.shared.ldap.message.spi.ProviderDecoder;
import java.io.InputStream;
import java.util.Hashtable;
/**
* Decodes a BER encoded LDAPv3 message envelope from an input stream
* demarshaling it into a Message instance using a BER library provider.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public final class MessageDecoder implements ProviderDecoder
{
/** the ASN.1 provider */
private final Provider provider;
/** the ASN.1 provider's decoder */
private final ProviderDecoder decoder;
/** the Message decode operation callback */
private DecoderCallback cb;
/**
* Creates a MessageDecoder using default properties for enabling a BER
* library provider.
*
* @param binaryAttributeDetector detects whether or not an attribute is binary
* @throws MessageException if there is a problem creating this decoder.
*/
public MessageDecoder( BinaryAttributeDetector binaryAttributeDetector ) throws MessageException
{
this( binaryAttributeDetector, Integer.MAX_VALUE );
}
/**
* Creates a MessageDecoder using default properties for enabling a BER
* library provider.
*
* @param binaryAttributeDetector detects whether or not an attribute is binary
* @param maxPDUSize the maximum size a PDU can be
* @throws MessageException if there is a problem creating this decoder.
*/
public MessageDecoder( BinaryAttributeDetector binaryAttributeDetector, int maxPDUSize ) throws MessageException
{
// We need to get the encoder class name
Hashtable<Object, Object> providerEnv = Provider.getEnvironment();
this.provider = Provider.getProvider( providerEnv );
this.decoder = this.provider.getDecoder( binaryAttributeDetector, maxPDUSize );
this.decoder.setCallback( new DecoderCallback()
{
public void decodeOccurred( StatefulDecoder decoder, Object decoded )
{
if ( decoded instanceof Asn1Object )
{
cb.decodeOccurred( decoder, LdapTransformer.transform( decoded ) );
}
else
{
cb.decodeOccurred( decoder, decoded );
}
}
} );
}
/**
* Reads and decodes a BER encoded LDAPv3 ASN.1 message envelope structure
* from an input stream to build a fully populated Message object instance.
*
* @param lock
* lock object used to exclusively read from the input stream
* @param in
* the input stream to read PDU data from.
* @return the populated Message representing the PDU envelope.
* @throws MessageException
* if there is a problem decoding.
*/
public Object decode( final Object lock, final InputStream in ) throws MessageException
{
Object providerEnvelope;
try
{
if ( lock == null )
{
// Complain here somehow first then do the following w/o synch!
// Call provider decoder to demarshall PDU into berlib specific form
providerEnvelope = decoder.decode( lock, in );
}
else
{
synchronized ( lock )
{
// Same as above but a synchronized read using valid lock object
providerEnvelope = decoder.decode( lock, in );
lock.notifyAll();
}
}
}
catch ( Exception e )
{
throw ( MessageException ) e;
}
// Call on transformer to convert stub based PDU into Message based PDU
return LdapTransformer.transform( providerEnvelope );
}
/**
* Decodes a chunk of stream data returning any resultant decoded PDU via a
* callback.
*
* @param chunk
* the chunk to decode
* @throws MessageException
* if there are failures while decoding the chunk
*/
public void decode( Object chunk ) throws MessageException
{
try
{
decoder.decode( chunk );
}
catch ( DecoderException e )
{
// transform the DecoderException message to a MessageException
if ( e instanceof ResponseCarryingException )
{
ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( e.getMessage() );
rcme.setResponse( ((ResponseCarryingException)e).getResponse() );
throw rcme;
}
else
{
// TODO : this is certainly not the way we should handle such an exception !
throw new ResponseCarryingMessageException( e.getMessage() );
}
}
}
/**
* Sets the callback used to deliver completly decoded PDU's.
*
* @param cb
* the callback to use for decoded PDU delivery
*/
public void setCallback( DecoderCallback cb )
{
this.cb = cb;
}
/**
* Sets the monitor for this MessageDecoder which receives callbacks for
* noteworthy events during decoding.
*
* @param monitor
* the monitor to receive notifications via callback events
*/
public void setDecoderMonitor( DecoderMonitor monitor )
{
decoder.setDecoderMonitor( monitor );
}
public Provider getProvider()
{
return this.provider;
}
}