| /* |
| * 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> |
| * @version $Rev$ |
| */ |
| 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; |
| } |
| } |