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.api.ldap.codec.osgi;
021
022
023import java.nio.ByteBuffer;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.Map;
028
029import javax.naming.NamingException;
030import javax.naming.ldap.BasicControl;
031
032import org.apache.directory.api.asn1.DecoderException;
033import org.apache.directory.api.asn1.EncoderException;
034import org.apache.directory.api.asn1.ber.Asn1Container;
035import org.apache.directory.api.ldap.codec.BasicControlDecorator;
036import org.apache.directory.api.ldap.codec.api.CodecControl;
037import org.apache.directory.api.ldap.codec.api.ControlFactory;
038import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
039import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
040import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
041import org.apache.directory.api.ldap.codec.api.LdapApiService;
042import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
043import org.apache.directory.api.ldap.codec.api.MessageDecorator;
044import org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory;
045import org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
046import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory;
047import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
048import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
049import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory;
050import org.apache.directory.api.ldap.model.message.Control;
051import org.apache.directory.api.ldap.model.message.ExtendedRequest;
052import org.apache.directory.api.ldap.model.message.ExtendedRequestImpl;
053import org.apache.directory.api.ldap.model.message.ExtendedResponse;
054import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
055import org.apache.directory.api.ldap.model.message.Message;
056import org.apache.directory.api.ldap.model.message.controls.Cascade;
057import org.apache.directory.api.ldap.model.message.controls.EntryChange;
058import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT;
059import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
060import org.apache.directory.api.ldap.model.message.controls.PagedResults;
061import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
062import org.apache.directory.api.ldap.model.message.controls.Subentries;
063import org.apache.directory.api.util.Strings;
064import org.apache.directory.api.util.exception.NotImplementedException;
065import org.apache.mina.filter.codec.ProtocolCodecFactory;
066import org.slf4j.Logger;
067import org.slf4j.LoggerFactory;
068
069
070/**
071 * The default {@link LdapApiService} implementation.
072 *
073 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
074 * @version $Rev$, $Date$
075 */
076public class DefaultLdapCodecService implements LdapApiService
077{
078    /** A logger */
079    private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapCodecService.class );
080
081    /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ControlFactory}'s */
082    protected Map<String, ControlFactory<? extends Control>> controlFactories = new HashMap<String, ControlFactory<? extends Control>>();
083
084    /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory}'s by request OID */
085    protected Map<String, ExtendedOperationFactory> extendedOperationsFactories = new HashMap<String, ExtendedOperationFactory>();
086
087    /** The registered ProtocolCodecFactory */
088    protected ProtocolCodecFactory protocolCodecFactory;
089
090
091    /**
092     * Creates a new instance of DefaultLdapCodecService.
093     */
094    public DefaultLdapCodecService()
095    {
096        loadStockControls();
097    }
098
099
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}