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