View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.api.ldap.codec.osgi;
21  
22  
23  import java.nio.ByteBuffer;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.Map;
28  
29  import javax.naming.NamingException;
30  import javax.naming.ldap.BasicControl;
31  
32  import org.apache.directory.api.asn1.DecoderException;
33  import org.apache.directory.api.asn1.EncoderException;
34  import org.apache.directory.api.asn1.ber.Asn1Container;
35  import org.apache.directory.api.ldap.codec.BasicControlDecorator;
36  import org.apache.directory.api.ldap.codec.api.CodecControl;
37  import org.apache.directory.api.ldap.codec.api.ControlFactory;
38  import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
39  import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
40  import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
41  import org.apache.directory.api.ldap.codec.api.LdapApiService;
42  import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
43  import org.apache.directory.api.ldap.codec.api.MessageDecorator;
44  import org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory;
45  import org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
46  import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory;
47  import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
48  import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
49  import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory;
50  import org.apache.directory.api.ldap.model.message.Control;
51  import org.apache.directory.api.ldap.model.message.ExtendedRequest;
52  import org.apache.directory.api.ldap.model.message.ExtendedRequestImpl;
53  import org.apache.directory.api.ldap.model.message.ExtendedResponse;
54  import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
55  import org.apache.directory.api.ldap.model.message.Message;
56  import org.apache.directory.api.ldap.model.message.controls.Cascade;
57  import org.apache.directory.api.ldap.model.message.controls.EntryChange;
58  import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT;
59  import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
60  import org.apache.directory.api.ldap.model.message.controls.PagedResults;
61  import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
62  import org.apache.directory.api.ldap.model.message.controls.Subentries;
63  import org.apache.directory.api.util.Strings;
64  import org.apache.directory.api.util.exception.NotImplementedException;
65  import org.apache.mina.filter.codec.ProtocolCodecFactory;
66  import org.slf4j.Logger;
67  import org.slf4j.LoggerFactory;
68  
69  
70  /**
71   * The default {@link LdapApiService} implementation.
72   *
73   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
74   * @version $Rev$, $Date$
75   */
76  public class DefaultLdapCodecService implements LdapApiService
77  {
78      /** A logger */
79      private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapCodecService.class );
80  
81      /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ControlFactory}'s */
82      protected Map<String, ControlFactory<? extends Control>> controlFactories = new HashMap<String, ControlFactory<? extends Control>>();
83  
84      /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory}'s by request OID */
85      protected Map<String, ExtendedOperationFactory> extendedOperationsFactories = new HashMap<String, ExtendedOperationFactory>();
86  
87      /** The registered ProtocolCodecFactory */
88      protected ProtocolCodecFactory protocolCodecFactory;
89  
90  
91      /**
92       * Creates a new instance of DefaultLdapCodecService.
93       */
94      public DefaultLdapCodecService()
95      {
96          loadStockControls();
97      }
98  
99  
100     /**
101      * Loads the Controls implement out of the box in the codec.
102      */
103     private void loadStockControls()
104     {
105         ControlFactory<Cascade> cascadeFactory = new CascadeFactory( this );
106         controlFactories.put( cascadeFactory.getOid(), cascadeFactory );
107         LOG.info( "Registered pre-bundled control factory: {}", cascadeFactory.getOid() );
108 
109         ControlFactory<EntryChange> entryChangeFactory = new EntryChangeFactory( this );
110         controlFactories.put( entryChangeFactory.getOid(), entryChangeFactory );
111         LOG.info( "Registered pre-bundled control factory: {}", entryChangeFactory.getOid() );
112 
113         ControlFactory<ManageDsaIT> manageDsaItFactory = new ManageDsaITFactory( this );
114         controlFactories.put( manageDsaItFactory.getOid(), manageDsaItFactory );
115         LOG.info( "Registered pre-bundled control factory: {}", manageDsaItFactory.getOid() );
116 
117         ControlFactory<PagedResults> pageResultsFactory = new PagedResultsFactory( this );
118         controlFactories.put( pageResultsFactory.getOid(), pageResultsFactory );
119         LOG.info( "Registered pre-bundled control factory: {}", pageResultsFactory.getOid() );
120 
121         ControlFactory<PersistentSearch> persistentSearchFactory = new PersistentSearchFactory( this );
122         controlFactories.put( persistentSearchFactory.getOid(), persistentSearchFactory );
123         LOG.info( "Registered pre-bundled control factory: {}", persistentSearchFactory.getOid() );
124 
125         ControlFactory<Subentries> subentriesFactory = new SubentriesFactory( this );
126         controlFactories.put( subentriesFactory.getOid(), subentriesFactory );
127         LOG.info( "Registered pre-bundled control factory: {}", subentriesFactory.getOid() );
128     }
129 
130 
131     //-------------------------------------------------------------------------
132     // LdapCodecService implementation methods
133     //-------------------------------------------------------------------------
134 
135     /**
136      * {@inheritDoc}
137      */
138     public ControlFactory<?> registerControl( ControlFactory<?> factory )
139     {
140         return controlFactories.put( factory.getOid(), factory );
141     }
142 
143 
144     /**
145      * {@inheritDoc}
146      */
147     public ControlFactory<?> unregisterControl( String oid )
148     {
149         return controlFactories.remove( oid );
150     }
151 
152 
153     /**
154      * {@inheritDoc}
155      */
156     public Iterator<String> registeredControls()
157     {
158         return Collections.unmodifiableSet( controlFactories.keySet() ).iterator();
159     }
160 
161 
162     /**
163      * {@inheritDoc}
164      */
165     public boolean isControlRegistered( String oid )
166     {
167         return controlFactories.containsKey( oid );
168     }
169 
170 
171     /**
172      * {@inheritDoc}
173      */
174     public Iterator<String> registeredExtendedRequests()
175     {
176         return Collections.unmodifiableSet( extendedOperationsFactories.keySet() ).iterator();
177     }
178 
179 
180     /**
181      * {@inheritDoc}
182      */
183     public ExtendedOperationFactory registerExtendedRequest( ExtendedOperationFactory factory )
184     {
185         return extendedOperationsFactories.put( factory.getOid(), factory );
186     }
187 
188 
189     /**
190      * {@inheritDoc}
191      */
192     public ProtocolCodecFactory getProtocolCodecFactory()
193     {
194         return protocolCodecFactory;
195     }
196 
197 
198     public ProtocolCodecFactory registerProtocolCodecFactory( ProtocolCodecFactory protocolCodecFactory )
199     {
200         ProtocolCodecFactory oldFactory = this.protocolCodecFactory;
201         this.protocolCodecFactory = protocolCodecFactory;
202         return oldFactory;
203     }
204 
205 
206     /**
207      * {@inheritDoc}
208      */
209     public CodecControl<? extends Control> newControl( String oid )
210     {
211         ControlFactory<?> factory = controlFactories.get( oid );
212 
213         if ( factory == null )
214         {
215             return new BasicControlDecorator<Control>( this, new OpaqueControl( oid ) );
216         }
217 
218         return factory.newCodecControl();
219     }
220 
221 
222     /**
223      * {@inheritDoc}
224      */
225     @SuppressWarnings("unchecked")
226     public CodecControl<? extends Control> newControl( Control control )
227     {
228         if ( control == null )
229         {
230             throw new NullPointerException( "Control argument was null." );
231         }
232 
233         // protect agains being multiply decorated
234         if ( control instanceof CodecControl )
235         {
236             return ( CodecControl<?> ) control;
237         }
238 
239         @SuppressWarnings("rawtypes")
240         ControlFactory factory = controlFactories.get( control.getOid() );
241 
242         if ( factory == null )
243         {
244             return new BasicControlDecorator<Control>( this, control );
245         }
246 
247         return factory.newCodecControl( control );
248     }
249 
250 
251     /**
252      * {@inheritDoc}
253      */
254     public javax.naming.ldap.Control toJndiControl( Control control ) throws EncoderException
255     {
256         CodecControl<? extends Control> decorator = newControl( control );
257         ByteBuffer bb = ByteBuffer.allocate( decorator.computeLength() );
258         decorator.encode( bb );
259         bb.flip();
260         BasicControl jndiControl =
261             new BasicControl( control.getOid(), control.isCritical(), bb.array() );
262         return jndiControl;
263     }
264 
265 
266     /**
267      * {@inheritDoc}
268      */
269     public Control fromJndiControl( javax.naming.ldap.Control control ) throws DecoderException
270     {
271         @SuppressWarnings("rawtypes")
272         ControlFactory factory = controlFactories.get( control.getID() );
273 
274         if ( factory == null )
275         {
276             OpaqueControl ourControl = new OpaqueControl( control.getID() );
277             ourControl.setCritical( control.isCritical() );
278             BasicControlDecorator<Control> decorator =
279                 new BasicControlDecorator<Control>( this, ourControl );
280             decorator.setValue( control.getEncodedValue() );
281             return decorator;
282         }
283 
284         @SuppressWarnings("unchecked")
285         CodecControl<? extends Control> ourControl = factory.newCodecControl();
286         ourControl.setCritical( control.isCritical() );
287         ourControl.setValue( control.getEncodedValue() );
288         ourControl.decode( control.getEncodedValue() );
289 
290         return ourControl;
291     }
292 
293 
294     /**
295      * {@inheritDoc}
296      */
297     public Asn1Container newMessageContainer()
298     {
299         return new LdapMessageContainer<MessageDecorator<? extends Message>>( this );
300     }
301 
302 
303     /**
304      * {@inheritDoc}
305      */
306     public ExtendedOperationFactory unregisterExtendedRequest( String oid )
307     {
308         return extendedOperationsFactories.remove( oid );
309     }
310 
311 
312     /**
313      * {@inheritDoc}
314      */
315     public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException
316     {
317         throw new NotImplementedException( "Figure out how to transform" );
318     }
319 
320 
321     /**
322      * {@inheritDoc}
323      */
324     public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException
325     {
326         throw new NotImplementedException( "Figure out how to transform" );
327     }
328 
329 
330     /**
331      * {@inheritDoc}
332      */
333     public ExtendedRequest fromJndi( javax.naming.ldap.ExtendedRequest jndiRequest ) throws DecoderException
334     {
335         ExtendedRequestDecorator<?> decorator =
336             ( ExtendedRequestDecorator<?> ) newExtendedRequest( jndiRequest.getID(), jndiRequest.getEncodedValue() );
337         return decorator;
338     }
339 
340 
341     /**
342      * {@inheritDoc}
343      */
344     public javax.naming.ldap.ExtendedRequest toJndi( final ExtendedRequest modelRequest ) throws EncoderException
345     {
346         final String oid = modelRequest.getRequestName();
347         final byte[] value;
348 
349         if ( modelRequest instanceof ExtendedRequestDecorator )
350         {
351             ExtendedRequestDecorator<?> decorator = ( ExtendedRequestDecorator<?> ) modelRequest;
352             value = decorator.getRequestValue();
353         }
354         else
355         {
356             // have to ask the factory to decorate for us - can't do it ourselves
357             ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( modelRequest
358                 .getRequestName() );
359             ExtendedRequestDecorator<?> decorator = ( ExtendedRequestDecorator<?> ) extendedRequestFactory
360                 .decorate( modelRequest );
361             value = decorator.getRequestValue();
362         }
363 
364         javax.naming.ldap.ExtendedRequest jndiRequest = new javax.naming.ldap.ExtendedRequest()
365         {
366             private static final long serialVersionUID = -4160980385909987475L;
367 
368 
369             public String getID()
370             {
371                 return oid;
372             }
373 
374 
375             public byte[] getEncodedValue()
376             {
377                 return value;
378             }
379 
380 
381             public javax.naming.ldap.ExtendedResponse createExtendedResponse( String id, byte[] berValue, int offset,
382                 int length ) throws NamingException
383             {
384                 ExtendedOperationFactory factory = extendedOperationsFactories
385                     .get( modelRequest.getRequestName() );
386 
387                 try
388                 {
389                     final ExtendedResponseDecorator<?> resp = ( ExtendedResponseDecorator<?> ) factory
390                         .newResponse( berValue );
391                     javax.naming.ldap.ExtendedResponse jndiResponse = new javax.naming.ldap.ExtendedResponse()
392                     {
393                         private static final long serialVersionUID = -7686354122066100703L;
394 
395 
396                         public String getID()
397                         {
398                             return oid;
399                         }
400 
401 
402                         public byte[] getEncodedValue()
403                         {
404                             return resp.getResponseValue();
405                         }
406                     };
407 
408                     return jndiResponse;
409                 }
410                 catch ( DecoderException e )
411                 {
412                     NamingException ne = new NamingException( "Unable to decode encoded response value: " +
413                         Strings.dumpBytes( berValue ) );
414                     ne.setRootCause( e );
415                     throw ne;
416                 }
417             }
418         };
419 
420         return jndiRequest;
421     }
422 
423 
424     /**
425      * {@inheritDoc}
426      * @throws DecoderException 
427      */
428     @SuppressWarnings("unchecked")
429     public <E extends ExtendedResponse> E newExtendedResponse( String responseName, int messageId,
430         byte[] serializedResponse )
431         throws DecoderException
432     {
433         ExtendedResponseDecorator<ExtendedResponse> resp;
434 
435         ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( responseName );
436 
437         if ( extendedRequestFactory != null )
438         {
439             resp = ( ExtendedResponseDecorator<ExtendedResponse> ) extendedRequestFactory
440                 .newResponse( serializedResponse );
441         }
442         else
443         {
444             resp = new ExtendedResponseDecorator<ExtendedResponse>( this,
445                 new ExtendedResponseImpl( responseName ) );
446             resp.setResponseValue( serializedResponse );
447             resp.setResponseName( responseName );
448         }
449 
450         resp.setMessageId( messageId );
451 
452         return ( E ) resp;
453     }
454 
455 
456     /**
457      * {@inheritDoc}
458      */
459     public ExtendedRequest newExtendedRequest( String oid, byte[] value )
460     {
461         ExtendedRequest req = null;
462 
463         ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( oid );
464 
465         if ( extendedRequestFactory != null )
466         {
467             req = extendedRequestFactory.newRequest( value );
468         }
469         else
470         {
471             ExtendedRequestDecorator<ExtendedRequest> decorator =
472                 new ExtendedRequestDecorator<ExtendedRequest>( this,
473                     new ExtendedRequestImpl() );
474             decorator.setRequestName( oid );
475             decorator.setRequestValue( value );
476             req = decorator;
477         }
478 
479         return req;
480     }
481 
482 
483     /**
484      * {@inheritDoc}
485      */
486     public ExtendedRequestDecorator<?> decorate( ExtendedRequest decoratedMessage )
487     {
488         ExtendedRequestDecorator<?> req = null;
489 
490         ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( decoratedMessage
491             .getRequestName() );
492 
493         if ( extendedRequestFactory != null )
494         {
495             req = ( ExtendedRequestDecorator<?> ) extendedRequestFactory.decorate( decoratedMessage );
496         }
497         else
498         {
499             req = new ExtendedRequestDecorator<ExtendedRequest>( this, decoratedMessage );
500         }
501 
502         return req;
503     }
504 
505 
506     /**
507      * {@inheritDoc}
508      */
509     public ExtendedResponseDecorator<?> decorate( ExtendedResponse decoratedMessage )
510     {
511         ExtendedResponseDecorator<?> resp = null;
512 
513         ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( decoratedMessage
514             .getResponseName() );
515 
516         if ( extendedRequestFactory != null )
517         {
518             resp = ( ExtendedResponseDecorator<?> ) extendedRequestFactory.decorate( decoratedMessage );
519         }
520         else
521         {
522             resp = new ExtendedResponseDecorator<ExtendedResponse>( this, decoratedMessage );
523         }
524 
525         return resp;
526     }
527 
528 
529     /**
530      * {@inheritDoc}
531      */
532     public boolean isExtendedOperationRegistered( String oid )
533     {
534         return extendedOperationsFactories.containsKey( oid );
535     }
536 }