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.ldap.message.spi.Provider;
034 import org.apache.directory.shared.ldap.message.spi.ProviderEncoder;
035 import org.apache.directory.shared.ldap.message.spi.ProviderException;
036 import org.apache.directory.shared.ldap.util.StringTools;
037 import org.slf4j.Logger;
038 import org.slf4j.LoggerFactory;
039
040
041 /**
042 * Twix LDAP BER provider's encoder.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 * @version $Rev: 764131 $
046 */
047 public class TwixEncoder implements ProviderEncoder
048 {
049 //TM private static long cumul = 0L;
050 //TM private static long count = 0L;
051 //TM private Object lock = new Object();
052
053 /** The logger */
054 private static Logger log = LoggerFactory.getLogger( TwixEncoder.class );
055
056 /** A speedup for logger */
057 private static final boolean IS_DEBUG = log.isDebugEnabled();
058
059 /** The associated Provider */
060 final Provider provider;
061
062 /** The callback to call when the encoding is done */
063 private EncoderCallback encodeCallback;
064
065
066 /**
067 * Creates an instance of a Twix Encoder implementation.
068 *
069 * @param provider The associated Provider
070 */
071 public TwixEncoder( Provider provider )
072 {
073 this.provider = provider;
074 encodeCallback = new OutputCallback();
075 }
076
077
078 /**
079 * Encodes a LdapMessage, and calls the callback.
080 *
081 * @param lock Not used...
082 * @param out Not used ...
083 * @param obj The LdapMessage to encode
084 * @throws ProviderException If anything went wrong
085 */
086 public void encodeBlocking( Object lock, OutputStream out, Object obj ) throws ProviderException
087 {
088 try
089 {
090 if ( IS_DEBUG )
091 {
092 log.debug( "Encoding this LdapMessage : " + obj );
093 }
094
095 ( ( OutputCallback ) encodeCallback ).attach( out );
096 encodeCallback.encodeOccurred( null, ( ( LdapMessageCodec ) obj ).encode( null ) );
097 }
098 catch ( EncoderException e )
099 {
100 log.error( "Twix encoder failed to encode object: " + obj + ", error : " + e.getMessage() );
101 ProviderException pe = new ProviderException( provider, "Twix encoder failed to encode object: " + obj
102 + ", error : " + e.getMessage() );
103 throw pe;
104 }
105 }
106
107
108 /**
109 * Encodes a LdapMessage, and return a ByteBuffer containing the resulting
110 * PDU
111 *
112 * @param obj The LdapMessage to encode
113 * @return The ByteBuffer containing the PDU
114 * @throws ProviderException If anything went wrong
115 */
116 public ByteBuffer encodeBlocking( Object obj ) throws ProviderException
117 {
118 try
119 {
120 if ( IS_DEBUG )
121 {
122 log.debug( "Encoding this LdapMessage : " + obj );
123 }
124
125 ByteBuffer pdu = ( ( LdapMessageCodec ) obj ).encode( null );
126
127 if ( IS_DEBUG )
128 {
129 log.debug( "Encoded PDU : " + StringTools.dumpBytes( pdu.array() ) );
130 }
131
132 pdu.flip();
133 return pdu;
134 }
135 catch ( EncoderException e )
136 {
137 log.error( "Twix encoder failed to encode object: " + obj + ", error : " + e.getMessage() );
138 ProviderException pe = new ProviderException( provider, "Twix encoder failed to encode object: " + obj
139 + ", error : " + e.getMessage() );
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( null ).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( "Twix encoder failed to encode object: " + obj + ", error : " + e.getMessage() );
174 ProviderException pe = new ProviderException( provider, "Twix encoder failed to encode object: " + obj
175 + ", error : " + e.getMessage() );
176 throw pe;
177 }
178 }
179
180
181 /**
182 * Gets the Provider associated with this SPI implementation object.
183 *
184 * @return Provider The provider
185 */
186 public Provider getProvider()
187 {
188 return provider;
189 }
190
191
192 /**
193 * Encodes a LdapMessage, and calls the callback
194 *
195 * @param obj The LdapMessage to encode
196 * @throws EncoderException If anything went wrong
197 */
198 public void encode( Object obj ) throws EncoderException
199 {
200 //TM long t0 = System.nanoTime();
201 ByteBuffer encoded = encodeBlocking( obj );
202 encodeCallback.encodeOccurred( null, encoded );
203 //TM long t1 = System.nanoTime();
204
205 //TM synchronized (lock)
206 //TM {
207 //TM cumul += (t1 - t0);
208 //TM count++;
209 //TM
210 //TM
211 //TM if ( count % 1000L == 0)
212 //TM {
213 //TM System.out.println( "Encode cost : " + (cumul/count) );
214 //TM cumul = 0L;
215 //TM }
216 //TM }
217 }
218
219
220 /**
221 * Set the callback called when the encoding is done.
222 *
223 * @param cb The callback.
224 */
225 public void setCallback( EncoderCallback cb )
226 {
227 encodeCallback = cb;
228 }
229
230
231 /**
232 * Not used ...
233 *
234 * @deprecated
235 */
236 public void setEncoderMonitor( EncoderMonitor monitor )
237 {
238 }
239
240 /**
241 * The inner class used to write the PDU to a channel.
242 */
243 class OutputCallback implements EncoderCallback
244 {
245 /** The channel in which the PDU will be written */
246 private WritableByteChannel channel = null;
247
248
249 /**
250 * Callback to deliver a fully encoded object.
251 *
252 * @param encoder the stateful encoder driving the callback
253 * @param encoded the object that was encoded
254 */
255 public void encodeOccurred( StatefulEncoder encoder, Object encoded )
256 {
257 try
258 {
259 ( ( ByteBuffer ) encoded ).flip();
260 channel.write( ( ByteBuffer ) encoded );
261 }
262 catch ( IOException e )
263 {
264 ProviderException pe = new ProviderException( provider,
265 "Twix encoder failed to encode object, error : " + e.getMessage() );
266 throw pe;
267 }
268 }
269
270
271 /**
272 * Associate a channel to the callback
273 *
274 * @param channel The channel to use to write a PDU
275 */
276 void attach( WritableByteChannel channel )
277 {
278 this.channel = channel;
279 }
280
281
282 /**
283 * Associate a OutputStream to the callback. A channel will be created.
284 *
285 * @param out The OutputStream to use
286 */
287 void attach( OutputStream out )
288 {
289 this.channel = Channels.newChannel( out );
290 }
291 }
292 }