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.codec;
021
022
023 import java.io.IOException;
024 import java.io.OutputStream;
025 import java.nio.ByteBuffer;
026 import java.nio.channels.Channels;
027 import java.nio.channels.WritableByteChannel;
028
029 import org.apache.directory.shared.asn1.codec.EncoderException;
030 import org.apache.directory.shared.asn1.codec.stateful.EncoderCallback;
031 import org.apache.directory.shared.asn1.codec.stateful.EncoderMonitor;
032 import org.apache.directory.shared.asn1.codec.stateful.StatefulEncoder;
033 import org.apache.directory.shared.i18n.I18n;
034 import org.apache.directory.shared.ldap.codec.add.AddRequestCodec;
035 import org.apache.directory.shared.ldap.message.spi.Provider;
036 import org.apache.directory.shared.ldap.message.spi.ProviderEncoder;
037 import org.apache.directory.shared.ldap.message.spi.ProviderException;
038 import org.apache.directory.shared.ldap.util.StringTools;
039 import org.slf4j.Logger;
040 import org.slf4j.LoggerFactory;
041
042
043 /**
044 * LDAP BER provider's encoder.
045 *
046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047 * @version $Rev: 912399 $
048 */
049 public class LdapEncoder implements ProviderEncoder
050 {
051 //TM private static long cumul = 0L;
052 //TM private static long count = 0L;
053 //TM private Object lock = new Object();
054
055 /** The logger */
056 private static Logger log = LoggerFactory.getLogger( LdapEncoder.class );
057
058 /** A speedup for logger */
059 private static final boolean IS_DEBUG = log.isDebugEnabled();
060
061 /** The associated Provider */
062 final Provider provider;
063
064 /** The callback to call when the encoding is done */
065 private EncoderCallback encodeCallback;
066
067
068 /**
069 * Creates an instance of a Ldap Encoder implementation.
070 *
071 * @param provider The associated Provider
072 */
073 public LdapEncoder( Provider provider )
074 {
075 this.provider = provider;
076 encodeCallback = new OutputCallback();
077 }
078
079
080 /**
081 * Encodes a LdapMessage, and calls the callback.
082 *
083 * @param lock Not used...
084 * @param out Not used ...
085 * @param obj The LdapMessage to encode
086 * @throws ProviderException If anything went wrong
087 */
088 public void encodeBlocking( Object lock, OutputStream out, Object obj ) throws ProviderException
089 {
090 try
091 {
092 if ( IS_DEBUG )
093 {
094 log.debug( "Encoding this LdapMessage : " + obj );
095 }
096
097 ( ( OutputCallback ) encodeCallback ).attach( out );
098 encodeCallback.encodeOccurred( null, ( ( LdapMessageCodec ) obj ).encode() );
099 }
100 catch ( EncoderException e )
101 {
102 log.error( I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
103 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
104 throw pe;
105 }
106 }
107
108
109 /**
110 * Encodes a LdapMessage, and return a ByteBuffer containing the resulting
111 * PDU
112 *
113 * @param obj The LdapMessage to encode
114 * @return The ByteBuffer containing the PDU
115 * @throws ProviderException If anything went wrong
116 */
117 public ByteBuffer encodeBlocking( Object obj ) throws ProviderException
118 {
119 try
120 {
121 if ( IS_DEBUG )
122 {
123 log.debug( "Encoding this LdapMessage : " + obj );
124 }
125
126 ByteBuffer pdu = ( ( LdapMessageCodec ) obj ).encode();
127
128 if ( IS_DEBUG )
129 {
130 log.debug( "Encoded PDU : " + StringTools.dumpBytes( pdu.array() ) );
131 }
132
133 pdu.flip();
134 return pdu;
135 }
136 catch ( EncoderException e )
137 {
138 log.error( I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
139 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
140 throw pe;
141 }
142 }
143
144
145 /**
146 * Encodes a LdapMessage, and return a byte array containing the resulting
147 * PDU
148 *
149 * @param obj The LdapMessage to encode
150 * @return The byte[] containing the PDU
151 * @throws ProviderException If anything went wrong
152 */
153 public byte[] encodeToArray( Object obj ) throws ProviderException
154 {
155 try
156 {
157 if ( IS_DEBUG )
158 {
159 log.debug( "Encoding this LdapMessage : " + obj );
160 }
161
162 byte[] pdu = ( ( LdapMessageCodec ) obj ).encode().array();
163
164 if ( IS_DEBUG )
165 {
166 log.debug( "Encoded PDU : " + StringTools.dumpBytes( pdu ) );
167 }
168
169 return pdu;
170 }
171 catch ( EncoderException e )
172 {
173 log.error( I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
174 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, obj, e.getLocalizedMessage() ) );
175 throw pe;
176 }
177 }
178
179
180 /**
181 * Gets the Provider associated with this SPI implementation object.
182 *
183 * @return Provider The provider
184 */
185 public Provider getProvider()
186 {
187 return provider;
188 }
189
190
191 /**
192 * Encodes a LdapMessage, and calls the callback
193 *
194 * @param obj The LdapMessage to encode
195 * @throws EncoderException If anything went wrong
196 */
197 public void encode( Object obj ) throws EncoderException
198 {
199 //TM long t0 = System.nanoTime();
200 ByteBuffer encoded = encodeBlocking( obj );
201 encodeCallback.encodeOccurred( null, encoded );
202 //TM long t1 = System.nanoTime();
203
204 //TM synchronized (lock)
205 //TM {
206 //TM cumul += (t1 - t0);
207 //TM count++;
208 //TM
209 //TM
210 //TM if ( count % 1000L == 0)
211 //TM {
212 //TM System.out.println( "Encode cost : " + (cumul/count) );
213 //TM cumul = 0L;
214 //TM }
215 //TM }
216 }
217
218
219 /**
220 * Set the callback called when the encoding is done.
221 *
222 * @param cb The callback.
223 */
224 public void setCallback( EncoderCallback cb )
225 {
226 encodeCallback = cb;
227 }
228
229
230 /**
231 * Not used ...
232 *
233 * @deprecated
234 */
235 public void setEncoderMonitor( EncoderMonitor monitor )
236 {
237 }
238
239 /**
240 * The inner class used to write the PDU to a channel.
241 */
242 class OutputCallback implements EncoderCallback
243 {
244 /** The channel in which the PDU will be written */
245 private WritableByteChannel channel = null;
246
247
248 /**
249 * Callback to deliver a fully encoded object.
250 *
251 * @param encoder the stateful encoder driving the callback
252 * @param encoded the object that was encoded
253 */
254 public void encodeOccurred( StatefulEncoder encoder, Object encoded )
255 {
256 try
257 {
258 ( ( ByteBuffer ) encoded ).flip();
259 channel.write( ( ByteBuffer ) encoded );
260 }
261 catch ( IOException e )
262 {
263 ProviderException pe = new ProviderException( provider, I18n.err( I18n.ERR_04065, "", e.getLocalizedMessage() ) );
264 throw pe;
265 }
266 }
267
268
269 /**
270 * Associate a channel to the callback
271 *
272 * @param channel The channel to use to write a PDU
273 */
274 void attach( WritableByteChannel channel )
275 {
276 this.channel = channel;
277 }
278
279
280 /**
281 * Associate a OutputStream to the callback. A channel will be created.
282 *
283 * @param out The OutputStream to use
284 */
285 void attach( OutputStream out )
286 {
287 this.channel = Channels.newChannel( out );
288 }
289 }
290
291
292 private static ByteBuffer encodeAsn1( AddRequestCodec addRequest )
293 {
294 //int length = computeLength( addRequest );
295 return null;
296 }
297
298
299 private static ByteBuffer encodeAsn1( LdapMessageCodec message ) throws EncoderException
300 {
301 ByteBuffer buffer = null;
302
303 switch ( message.getMessageType() )
304 {
305 case ABANDON_REQUEST :
306 return encodeAsn1( message );
307
308 case ADD_REQUEST :
309 case ADD_RESPONSE :
310 case BIND_REQUEST :
311 case BIND_RESPONSE :
312 case COMPARE_REQUEST :
313 case COMPARE_RESPONSE :
314 case DEL_REQUEST :
315 case DEL_RESPONSE :
316 case EXTENDED_REQUEST :
317 case EXTENDED_RESPONSE :
318 case INTERMEDIATE_RESPONSE :
319 case MODIFY_REQUEST :
320 case MODIFY_RESPONSE :
321 case MODIFYDN_REQUEST :
322 case MODIFYDN_RESPONSE :
323 case SEARCH_REQUEST :
324 case SEARCH_RESULT_DONE :
325 case SEARCH_RESULT_ENTRY :
326 case SEARCH_RESULT_REFERENCE :
327 case UNBIND_REQUEST :
328
329 }
330
331 return buffer;
332 }
333 }