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