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 */
020package org.apache.directory.shared.ldap.codec.osgi;
021
022
023import org.apache.directory.shared.asn1.DecoderException;
024import org.apache.directory.shared.asn1.EncoderException;
025import org.apache.directory.shared.asn1.ber.Asn1Container;
026import org.apache.directory.shared.ldap.codec.BasicControlDecorator;
027import org.apache.directory.shared.ldap.codec.api.ExtendedRequestDecorator;
028import org.apache.directory.shared.ldap.codec.api.ExtendedResponseDecorator;
029import org.apache.directory.shared.ldap.codec.api.LdapMessageContainer;
030import org.apache.directory.shared.ldap.codec.api.CodecControl;
031import org.apache.directory.shared.ldap.codec.api.ControlFactory;
032import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
033import org.apache.directory.shared.ldap.codec.api.LdapApiService;
034import org.apache.directory.shared.ldap.codec.api.MessageDecorator;
035import org.apache.directory.shared.ldap.codec.api.UnsolicitedResponseFactory;
036import org.apache.directory.shared.ldap.codec.controls.cascade.CascadeFactory;
037import org.apache.directory.shared.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
038import org.apache.directory.shared.ldap.codec.controls.search.entryChange.EntryChangeFactory;
039import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
040import org.apache.directory.shared.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
041import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesFactory;
042import org.apache.directory.shared.ldap.model.message.Control;
043import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
044import org.apache.directory.shared.ldap.model.message.ExtendedRequestImpl;
045import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
046import org.apache.directory.shared.ldap.model.message.ExtendedResponseImpl;
047import org.apache.directory.shared.ldap.model.message.Message;
048import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
049import org.apache.directory.shared.util.Strings;
050import org.apache.directory.shared.util.exception.NotImplementedException;
051import org.apache.mina.filter.codec.ProtocolCodecFactory;
052import org.slf4j.Logger;
053import org.slf4j.LoggerFactory;
054
055import java.nio.ByteBuffer;
056import java.util.Collections;
057import java.util.HashMap;
058import java.util.Iterator;
059import java.util.Map;
060
061import javax.naming.NamingException;
062
063
064/**
065 * The default {@link LdapApiService} implementation.
066 *
067 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
068 * @version $Rev$, $Date$
069 */
070public class DefaultLdapCodecService implements LdapApiService
071{
072    /** A logger */
073    private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapCodecService.class );
074
075    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ControlFactory}'s */
076    private Map<String, ControlFactory<?, ?>> controlFactories = new HashMap<String, ControlFactory<?, ?>>();
077
078    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory}'s by request OID */
079    private Map<String, ExtendedRequestFactory<?, ?>> extReqFactories = new HashMap<String, ExtendedRequestFactory<?, ?>>();
080
081    /** The map of registered {@link UnsolicitedResponseFactory}'s by request OID */
082    private Map<String, UnsolicitedResponseFactory<?>> unsolicitedFactories = new HashMap<String, UnsolicitedResponseFactory<?>>();
083
084    /** The registered ProtocolCodecFactory */
085    private ProtocolCodecFactory protocolCodecFactory;
086
087
088    /**
089     * Creates a new instance of DefaultLdapCodecService.
090     */
091    DefaultLdapCodecService()
092    {
093        loadStockControls();
094    }
095
096
097    /**
098     * Loads the Controls implement out of the box in the codec.
099     */
100    private void loadStockControls()
101    {
102        ControlFactory<?, ?> factory = new CascadeFactory( this );
103        controlFactories.put( factory.getOid(), factory );
104        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
105
106        factory = new EntryChangeFactory( this );
107        controlFactories.put( factory.getOid(), factory );
108        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
109
110        factory = new ManageDsaITFactory( this );
111        controlFactories.put( factory.getOid(), factory );
112        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
113
114        factory = new PagedResultsFactory( this );
115        controlFactories.put( factory.getOid(), factory );
116        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
117
118        factory = new PersistentSearchFactory( this );
119        controlFactories.put( factory.getOid(), factory );
120        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
121
122        factory = new SubentriesFactory( this );
123        controlFactories.put( factory.getOid(), factory );
124        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
125    }
126
127
128    //-------------------------------------------------------------------------
129    // LdapCodecService implementation methods
130    //-------------------------------------------------------------------------
131
132    /**
133     * {@inheritDoc}
134     */
135    public ControlFactory<?, ?> registerControl( ControlFactory<?, ?> factory )
136    {
137        return controlFactories.put( factory.getOid(), factory );
138    }
139
140
141    /**
142     * {@inheritDoc}
143     */
144    public ControlFactory<?, ?> unregisterControl( String oid )
145    {
146        return controlFactories.remove( oid );
147    }
148
149
150    /**
151     * {@inheritDoc}
152     */
153    public Iterator<String> registeredControls()
154    {
155        return Collections.unmodifiableSet( controlFactories.keySet() ).iterator();
156    }
157
158
159    /**
160     * {@inheritDoc}
161     */
162    public boolean isControlRegistered( String oid )
163    {
164        return controlFactories.containsKey( oid );
165    }
166
167
168    /**
169     * {@inheritDoc}
170     */
171    public Iterator<String> registeredExtendedRequests()
172    {
173        return Collections.unmodifiableSet( extReqFactories.keySet() ).iterator();
174    }
175
176
177    /**
178     * {@inheritDoc}
179     */
180    public ExtendedRequestFactory<?, ?> registerExtendedRequest( ExtendedRequestFactory<?, ?> factory )
181    {
182        return extReqFactories.put( factory.getOid(), factory );
183    }
184
185
186    /**
187     * {@inheritDoc}
188     */
189    public ProtocolCodecFactory getProtocolCodecFactory()
190    {
191        return protocolCodecFactory;
192    }
193
194
195    public ProtocolCodecFactory registerProtocolCodecFactory( ProtocolCodecFactory protocolCodecFactory )
196    {
197        ProtocolCodecFactory oldFactory = this.protocolCodecFactory;
198        this.protocolCodecFactory = protocolCodecFactory;
199        return oldFactory;
200    }
201
202
203    /**
204     * {@inheritDoc}
205     */
206    public CodecControl<? extends Control> newControl( String oid )
207    {
208        ControlFactory<?, ?> factory = controlFactories.get( oid );
209
210        if ( factory == null )
211        {
212            return new BasicControlDecorator<Control>( this, new OpaqueControl( oid ) );
213        }
214
215        return factory.newCodecControl();
216    }
217
218
219    /**
220     * {@inheritDoc}
221     */
222    @SuppressWarnings("unchecked")
223    public CodecControl<? extends Control> newControl( Control control )
224    {
225        if ( control == null )
226        {
227            throw new NullPointerException( "Control argument was null." );
228        }
229
230        // protect agains being multiply decorated
231        if ( control instanceof CodecControl )
232        {
233            return ( CodecControl<?> ) control;
234        }
235
236        @SuppressWarnings("rawtypes")
237        ControlFactory factory = controlFactories.get( control.getOid() );
238
239        if ( factory == null )
240        {
241            return new BasicControlDecorator<Control>( this, control );
242        }
243
244        return factory.newCodecControl( control );
245    }
246
247
248    /**
249     * {@inheritDoc}
250     */
251    public javax.naming.ldap.Control toJndiControl( Control control ) throws EncoderException
252    {
253        CodecControl<? extends Control> decorator = newControl( control );
254        ByteBuffer bb = ByteBuffer.allocate( decorator.computeLength() );
255        decorator.encode( bb );
256        bb.flip();
257        javax.naming.ldap.BasicControl jndiControl =
258            new javax.naming.ldap.BasicControl( control.getOid(), control.isCritical(), bb.array() );
259        return jndiControl;
260    }
261
262
263    /**
264     * {@inheritDoc}
265     */
266    public Control fromJndiControl( javax.naming.ldap.Control control ) throws DecoderException
267    {
268        @SuppressWarnings("rawtypes")
269        ControlFactory factory = controlFactories.get( control.getID() );
270
271        if ( factory == null )
272        {
273            OpaqueControl ourControl = new OpaqueControl( control.getID() );
274            ourControl.setCritical( control.isCritical() );
275            BasicControlDecorator<Control> decorator =
276                new BasicControlDecorator<Control>( this, ourControl );
277            decorator.setValue( control.getEncodedValue() );
278            return decorator;
279        }
280
281        @SuppressWarnings("unchecked")
282        CodecControl<? extends Control> ourControl = factory.newCodecControl();
283        ourControl.setCritical( control.isCritical() );
284        ourControl.setValue( control.getEncodedValue() );
285        ourControl.decode( control.getEncodedValue() );
286        return ourControl;
287    }
288
289
290    /**
291     * {@inheritDoc}
292     */
293    public Asn1Container newMessageContainer()
294    {
295        return new LdapMessageContainer<MessageDecorator<? extends Message>>( this );
296    }
297
298
299    /**
300     * {@inheritDoc}
301     */
302    public ExtendedRequestFactory<?, ?> unregisterExtendedRequest( String oid )
303    {
304        return extReqFactories.remove( oid );
305    }
306
307
308    /**
309     * {@inheritDoc}
310     */
311    public Iterator<String> registeredUnsolicitedResponses()
312    {
313        return Collections.unmodifiableSet( unsolicitedFactories.keySet() ).iterator();
314    }
315
316
317    /**
318     * {@inheritDoc}
319     */
320    public UnsolicitedResponseFactory<?> registerUnsolicitedResponse( UnsolicitedResponseFactory<?> factory )
321    {
322        return unsolicitedFactories.put( factory.getOid(), factory );
323    }
324
325
326    /**
327     * {@inheritDoc}
328     */
329    public UnsolicitedResponseFactory<?> unregisterUnsolicitedResponse( String oid )
330    {
331        return unsolicitedFactories.remove( oid );
332    }
333
334
335    /**
336     * {@inheritDoc}
337     */
338    public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException
339    {
340        throw new NotImplementedException( "Figure out how to transform" );
341        //        final byte[] encodedValue = new byte[ modelResponse.getEncodedValue().length ];
342        //        System.arraycopy( modelResponse.getEncodedValue(), 0, encodedValue, 0, modelResponse.getEncodedValue().length );
343        //        
344        //        return new javax.naming.ldap.ExtendedResponse()
345        //        {
346        //            private static final long serialVersionUID = 2955142105375495493L;
347        //
348        //            public String getID()
349        //            {
350        //                return modelResponse.getID();
351        //            }
352        //
353        //            public byte[] getEncodedValue()
354        //            {
355        //                return encodedValue;
356        //            }
357        //        };
358    }
359
360
361    /**
362     * {@inheritDoc}
363     */
364    public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException
365    {
366        throw new NotImplementedException( "Figure out how to transform" );
367        //        ExtendedResponse modelResponse;
368        //        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( jndiResponse.getID() );
369        //        UnsolicitedResponseFactory<?> unsolicitedResponseFactory = unsolicitedFactories.get( jndiResponse.getID() );
370        //        
371        //        if ( unsolicitedResponseFactory != null )
372        //        {
373        //            modelResponse = unsolicitedResponseFactory.newResponse( jndiResponse.getEncodedValue() );
374        //        }
375        //        else if ( extendedRequestFactory != null )
376        //        {
377        //            modelResponse = extendedRequestFactory.newResponse( jndiResponse.getEncodedValue() );
378        //        }
379        //        else
380        //        {
381        //            modelResponse = new ExtendedResponseImpl( jndiResponse.getID() );
382        //            modelResponse.setResponseValue( jndiResponse.getEncodedValue() );
383        //        }
384        //        
385        //        return modelResponse;
386    }
387
388
389    /**
390     * {@inheritDoc}
391     */
392    public ExtendedRequest<?> fromJndi( javax.naming.ldap.ExtendedRequest jndiRequest ) throws DecoderException
393    {
394        ExtendedRequestDecorator<?, ?> decorator =
395            ( ExtendedRequestDecorator<?, ?> ) newExtendedRequest( jndiRequest.getID(), jndiRequest.getEncodedValue() );
396        return decorator;
397    }
398
399
400    /**
401     * {@inheritDoc}
402     */
403    public javax.naming.ldap.ExtendedRequest toJndi( final ExtendedRequest<?> modelRequest ) throws EncoderException
404    {
405        final String oid = modelRequest.getRequestName();
406        final byte[] value;
407
408        if ( modelRequest instanceof ExtendedRequestDecorator )
409        {
410            ExtendedRequestDecorator<?, ?> decorator = ( ExtendedRequestDecorator<?, ?> ) modelRequest;
411            value = decorator.getRequestValue();
412        }
413        else
414        {
415            // have to ask the factory to decorate for us - can't do it ourselves
416            ExtendedRequestFactory<?, ?> extendedRequestFactory = extReqFactories.get( modelRequest.getRequestName() );
417            ExtendedRequestDecorator<?, ?> decorator = extendedRequestFactory.decorate( modelRequest );
418            value = decorator.getRequestValue();
419        }
420
421        javax.naming.ldap.ExtendedRequest jndiRequest = new javax.naming.ldap.ExtendedRequest()
422        {
423            private static final long serialVersionUID = -4160980385909987475L;
424
425
426            public String getID()
427            {
428                return oid;
429            }
430
431
432            public byte[] getEncodedValue()
433            {
434                return value;
435            }
436
437
438            public javax.naming.ldap.ExtendedResponse createExtendedResponse( String id, byte[] berValue, int offset,
439                int length ) throws NamingException
440            {
441                ExtendedRequestFactory<?, ?> factory = extReqFactories.get( modelRequest.getRequestName() );
442
443                try
444                {
445                    final ExtendedResponseDecorator<?> resp = ( ExtendedResponseDecorator<?> ) factory
446                        .newResponse( berValue );
447                    javax.naming.ldap.ExtendedResponse jndiResponse = new javax.naming.ldap.ExtendedResponse()
448                    {
449                        private static final long serialVersionUID = -7686354122066100703L;
450
451
452                        public String getID()
453                        {
454                            return oid;
455                        }
456
457
458                        public byte[] getEncodedValue()
459                        {
460                            return resp.getResponseValue();
461                        }
462                    };
463
464                    return jndiResponse;
465                }
466                catch ( DecoderException e )
467                {
468                    NamingException ne = new NamingException( "Unable to decode encoded response value: " +
469                        Strings.dumpBytes( berValue ) );
470                    ne.setRootCause( e );
471                    throw ne;
472                }
473            }
474        };
475
476        return jndiRequest;
477    }
478
479
480    /**
481     * {@inheritDoc}
482     */
483    /**
484     * {@inheritDoc}
485     * @throws DecoderException 
486     */
487    @SuppressWarnings("unchecked")
488    public <E extends ExtendedResponse> E newExtendedResponse( ExtendedRequest<E> req, byte[] serializedResponse )
489        throws DecoderException
490    {
491        ExtendedResponseDecorator<ExtendedResponse> resp;
492
493        ExtendedRequestFactory<?, ?> extendedRequestFactory = extReqFactories.get( req.getRequestName() );
494        if ( extendedRequestFactory != null )
495        {
496            resp = ( ExtendedResponseDecorator<ExtendedResponse> ) extendedRequestFactory
497                .newResponse( serializedResponse );
498        }
499        else
500        {
501            resp = new ExtendedResponseDecorator<ExtendedResponse>( this,
502                new ExtendedResponseImpl( req.getRequestName() ) );
503            resp.setResponseValue( serializedResponse );
504            resp.setResponseName( req.getRequestName() );
505        }
506
507        resp.setMessageId( req.getMessageId() );
508        return ( E ) resp;
509    }
510
511
512    /**
513     * {@inheritDoc}
514     */
515    public ExtendedRequest<?> newExtendedRequest( String oid, byte[] value )
516    {
517        ExtendedRequest<?> req = null;
518
519        ExtendedRequestFactory<?, ?> extendedRequestFactory = extReqFactories.get( oid );
520        if ( extendedRequestFactory != null )
521        {
522            req = extendedRequestFactory.newRequest( value );
523        }
524        else
525        {
526            ExtendedRequestDecorator<ExtendedRequest<ExtendedResponse>, ExtendedResponse> decorator =
527                new ExtendedRequestDecorator<ExtendedRequest<ExtendedResponse>, ExtendedResponse>( this,
528                    new ExtendedRequestImpl() );
529            decorator.setRequestName( oid );
530            decorator.setRequestValue( value );
531            req = decorator;
532        }
533
534        return req;
535    }
536
537
538    /**
539     * {@inheritDoc}
540     */
541    @SuppressWarnings("unchecked")
542    public ExtendedRequestDecorator<?, ?> decorate( ExtendedRequest<?> decoratedMessage )
543    {
544        ExtendedRequestDecorator<?, ?> req = null;
545
546        ExtendedRequestFactory<?, ?> extendedRequestFactory = extReqFactories.get( decoratedMessage.getRequestName() );
547        if ( extendedRequestFactory != null )
548        {
549            req = extendedRequestFactory.decorate( decoratedMessage );
550        }
551        else
552        {
553            req = new ExtendedRequestDecorator<ExtendedRequest<ExtendedResponse>, ExtendedResponse>( this,
554                    ( ExtendedRequest<ExtendedResponse> ) decoratedMessage );
555        }
556
557        return req;
558    }
559
560
561    /**
562     * {@inheritDoc}
563     */
564    public ExtendedResponseDecorator<?> decorate( ExtendedResponse decoratedMessage )
565    {
566        ExtendedResponseDecorator<?> resp = null;
567
568        UnsolicitedResponseFactory<?> unsolicitedResponseFactory = unsolicitedFactories.get( decoratedMessage
569            .getResponseName() );
570        ExtendedRequestFactory<?, ?> extendedRequestFactory = extReqFactories.get( decoratedMessage.getResponseName() );
571        if ( extendedRequestFactory != null )
572        {
573            resp = extendedRequestFactory.decorate( decoratedMessage );
574        }
575        else if ( unsolicitedResponseFactory != null )
576        {
577            resp = unsolicitedResponseFactory.decorate( decoratedMessage );
578        }
579        else
580        {
581            resp = new ExtendedResponseDecorator<ExtendedResponse>( this, decoratedMessage );
582        }
583
584        return resp;
585    }
586
587
588    /**
589     * {@inheritDoc}
590     */
591    public boolean isExtendedOperationRegistered( String oid )
592    {
593        return extReqFactories.containsKey( oid ) || unsolicitedFactories.containsKey( oid );
594    }
595}