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 */ 020 package org.apache.directory.shared.ldap.message; 021 022 023 import org.apache.directory.shared.asn1.Asn1Object; 024 import org.apache.directory.shared.asn1.codec.DecoderException; 025 import org.apache.directory.shared.asn1.codec.stateful.DecoderCallback; 026 import org.apache.directory.shared.asn1.codec.stateful.DecoderMonitor; 027 import org.apache.directory.shared.asn1.codec.stateful.StatefulDecoder; 028 import org.apache.directory.shared.ldap.codec.ResponseCarryingException; 029 import org.apache.directory.shared.ldap.codec.LdapTransformer; 030 import org.apache.directory.shared.ldap.message.spi.BinaryAttributeDetector; 031 import org.apache.directory.shared.ldap.message.spi.Provider; 032 import org.apache.directory.shared.ldap.message.spi.ProviderDecoder; 033 034 import java.io.InputStream; 035 import java.util.Hashtable; 036 037 038 /** 039 * Decodes a BER encoded LDAPv3 message envelope from an input stream 040 * demarshaling it into a Message instance using a BER library provider. 041 * 042 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 043 * @version $Rev: 903719 $ 044 */ 045 public final class MessageDecoder implements ProviderDecoder 046 { 047 /** the ASN.1 provider */ 048 private final Provider provider; 049 050 /** the ASN.1 provider's decoder */ 051 private final ProviderDecoder decoder; 052 053 /** the Message decode operation callback */ 054 private DecoderCallback cb; 055 056 057 /** 058 * Creates a MessageDecoder using default properties for enabling a BER 059 * library provider. 060 * 061 * @param binaryAttributeDetector detects whether or not an attribute is binary 062 * @throws MessageException if there is a problem creating this decoder. 063 */ 064 public MessageDecoder( BinaryAttributeDetector binaryAttributeDetector ) throws MessageException 065 { 066 this( binaryAttributeDetector, Integer.MAX_VALUE ); 067 } 068 069 070 /** 071 * Creates a MessageDecoder using default properties for enabling a BER 072 * library provider. 073 * 074 * @param binaryAttributeDetector detects whether or not an attribute is binary 075 * @param maxPDUSize the maximum size a PDU can be 076 * @throws MessageException if there is a problem creating this decoder. 077 */ 078 public MessageDecoder( BinaryAttributeDetector binaryAttributeDetector, int maxPDUSize ) throws MessageException 079 { 080 // We need to get the encoder class name 081 Hashtable<Object, Object> providerEnv = Provider.getEnvironment(); 082 083 this.provider = Provider.getProvider( providerEnv ); 084 this.decoder = this.provider.getDecoder( binaryAttributeDetector, maxPDUSize ); 085 this.decoder.setCallback( new DecoderCallback() 086 { 087 public void decodeOccurred( StatefulDecoder decoder, Object decoded ) 088 { 089 if ( decoded instanceof Asn1Object ) 090 { 091 cb.decodeOccurred( decoder, LdapTransformer.transform( decoded ) ); 092 } 093 else 094 { 095 cb.decodeOccurred( decoder, decoded ); 096 } 097 } 098 } ); 099 } 100 101 102 /** 103 * Reads and decodes a BER encoded LDAPv3 ASN.1 message envelope structure 104 * from an input stream to build a fully populated Message object instance. 105 * 106 * @param lock 107 * lock object used to exclusively read from the input stream 108 * @param in 109 * the input stream to read PDU data from. 110 * @return the populated Message representing the PDU envelope. 111 * @throws MessageException 112 * if there is a problem decoding. 113 */ 114 public Object decode( final Object lock, final InputStream in ) throws MessageException 115 { 116 Object providerEnvelope; 117 118 try 119 { 120 if ( lock == null ) 121 { 122 // Complain here somehow first then do the following w/o synch! 123 124 // Call provider decoder to demarshall PDU into berlib specific form 125 providerEnvelope = decoder.decode( lock, in ); 126 } 127 else 128 { 129 synchronized ( lock ) 130 { 131 // Same as above but a synchronized read using valid lock object 132 providerEnvelope = decoder.decode( lock, in ); 133 lock.notifyAll(); 134 } 135 } 136 } 137 catch ( Exception e ) 138 { 139 throw ( MessageException ) e; 140 } 141 142 // Call on transformer to convert stub based PDU into Message based PDU 143 return LdapTransformer.transform( providerEnvelope ); 144 } 145 146 147 /** 148 * Decodes a chunk of stream data returning any resultant decoded PDU via a 149 * callback. 150 * 151 * @param chunk 152 * the chunk to decode 153 * @throws MessageException 154 * if there are failures while decoding the chunk 155 */ 156 public void decode( Object chunk ) throws MessageException 157 { 158 try 159 { 160 decoder.decode( chunk ); 161 } 162 catch ( DecoderException e ) 163 { 164 // transform the DecoderException message to a MessageException 165 if ( e instanceof ResponseCarryingException ) 166 { 167 ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( e.getMessage() ); 168 rcme.setResponse( ((ResponseCarryingException)e).getResponse() ); 169 170 throw rcme; 171 } 172 else 173 { 174 // TODO : this is certainly not the way we should handle such an exception ! 175 throw new ResponseCarryingMessageException( e.getMessage() ); 176 } 177 } 178 } 179 180 181 /** 182 * Sets the callback used to deliver completly decoded PDU's. 183 * 184 * @param cb 185 * the callback to use for decoded PDU delivery 186 */ 187 public void setCallback( DecoderCallback cb ) 188 { 189 this.cb = cb; 190 } 191 192 193 /** 194 * Sets the monitor for this MessageDecoder which receives callbacks for 195 * noteworthy events during decoding. 196 * 197 * @param monitor 198 * the monitor to receive notifications via callback events 199 */ 200 public void setDecoderMonitor( DecoderMonitor monitor ) 201 { 202 decoder.setDecoderMonitor( monitor ); 203 } 204 205 206 public Provider getProvider() 207 { 208 return this.provider; 209 } 210 }