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.standalone;
021
022
023import java.lang.reflect.Constructor;
024import java.nio.ByteBuffer;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.Iterator;
028import java.util.Map;
029
030import javax.naming.NamingException;
031import javax.naming.ldap.BasicControl;
032
033import org.apache.directory.shared.asn1.DecoderException;
034import org.apache.directory.shared.asn1.EncoderException;
035import org.apache.directory.shared.asn1.ber.Asn1Container;
036import org.apache.directory.shared.ldap.codec.BasicControlDecorator;
037import org.apache.directory.shared.ldap.codec.api.CodecControl;
038import org.apache.directory.shared.ldap.codec.api.ControlFactory;
039import org.apache.directory.shared.ldap.codec.api.ExtendedRequestDecorator;
040import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
041import org.apache.directory.shared.ldap.codec.api.ExtendedResponseDecorator;
042import org.apache.directory.shared.ldap.codec.api.LdapApiService;
043import org.apache.directory.shared.ldap.codec.api.LdapMessageContainer;
044import org.apache.directory.shared.ldap.codec.api.MessageDecorator;
045import org.apache.directory.shared.ldap.codec.api.UnsolicitedResponseFactory;
046import org.apache.directory.shared.ldap.model.message.Control;
047import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
048import org.apache.directory.shared.ldap.model.message.ExtendedRequestImpl;
049import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
050import org.apache.directory.shared.ldap.model.message.ExtendedResponseImpl;
051import org.apache.directory.shared.ldap.model.message.Message;
052import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
053import org.apache.directory.shared.util.Strings;
054import org.apache.directory.shared.util.exception.NotImplementedException;
055import org.apache.mina.filter.codec.ProtocolCodecFactory;
056import org.slf4j.Logger;
057import org.slf4j.LoggerFactory;
058
059
060/**
061 * The default {@link org.apache.directory.shared.ldap.codec.api.LdapApiService} implementation.
062 *
063 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
064 * @version $Rev$, $Date$
065 */
066public class StandaloneLdapApiService implements LdapApiService
067{
068    /** A logger */
069    private static final Logger LOG = LoggerFactory.getLogger( StandaloneLdapApiService.class );
070 
071    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ControlFactory}'s */
072    private Map<String,ControlFactory<?,?>> controlFactories = new HashMap<String, ControlFactory<?,?>>();
073
074    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory}'s by request OID */
075    private Map<String,ExtendedRequestFactory<?,?>> extReqFactories = new HashMap<String, ExtendedRequestFactory<?,?>>();
076
077    /** The map of registered {@link UnsolicitedResponseFactory}'s by request OID */
078    private Map<String,UnsolicitedResponseFactory<?>> unsolicitedFactories = new HashMap<String, UnsolicitedResponseFactory<?>>();
079    
080    /** The LDAP {@link ProtocolCodecFactory} implementation used */
081    private ProtocolCodecFactory protocolCodecFactory;
082    
083    /** The list of default controls to load at startup */ 
084    public static String DEFAULT_CONTROLS_LIST = "default.controls";
085
086    /** The list of extra controls to load at startup */ 
087    public static String EXTRA_CONTROLS_LIST = "extra.controls";
088
089    /** The list of default extended operation requests to load at startup */ 
090    public static String DEFAULT_EXTENDED_OPERATION_REQUESTS_LIST = "default.extendedOperation.requests";
091
092    /** The list of default extended operation responses to load at startup */ 
093    public static String DEFAULT_EXTENDED_OPERATION_RESPONSES_LIST = "default.extendedOperation.responses";
094
095    /** The list of extra controls to load at startup */ 
096    public static String EXTRA_EXTENDED_OPERATION_LIST = "extra.extendedOperations";
097
098    /**
099     * Creates a new instance of StandaloneLdapCodecService. Optionally checks for
100     * system property {@link #PLUGIN_DIRECTORY_PROPERTY}. Intended for use by 
101     * unit test running tools like Maven's surefire:
102     * <pre>
103     *   &lt;properties&gt;
104     *     &lt;codec.plugin.directory&gt;${project.build.directory}/pluginDirectory&lt;/codec.plugin.directory&gt;
105     *   &lt;/properties&gt;
106     * 
107     *   &lt;build&gt;
108     *     &lt;plugins&gt;
109     *       &lt;plugin&gt;
110     *         &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
111     *         &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
112     *         &lt;configuration&gt;
113     *           &lt;systemPropertyVariables&gt;
114     *             &lt;workingDirectory&gt;${basedir}/target&lt;/workingDirectory&gt;
115     *             &lt;felix.cache.rootdir&gt;
116     *               ${project.build.directory}
117     *             &lt;/felix.cache.rootdir&gt;
118     *             &lt;felix.cache.locking&gt;
119     *               true
120     *             &lt;/felix.cache.locking&gt;
121     *             &lt;org.osgi.framework.storage.clean&gt;
122     *               onFirstInit
123     *             &lt;/org.osgi.framework.storage.clean&gt;
124     *             &lt;org.osgi.framework.storage&gt;
125     *               osgi-cache
126     *             &lt;/org.osgi.framework.storage&gt;
127     *             &lt;codec.plugin.directory&gt;
128     *               ${codec.plugin.directory}
129     *             &lt;/codec.plugin.directory&gt;
130     *           &lt;/systemPropertyVariables&gt;
131     *         &lt;/configuration&gt;
132     *       &lt;/plugin&gt;
133     *       
134     *       &lt;plugin&gt;
135     *         &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
136     *         &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;
137     *         &lt;executions&gt;
138     *           &lt;execution&gt;
139     *             &lt;id&gt;copy&lt;/id&gt;
140     *             &lt;phase&gt;compile&lt;/phase&gt;
141     *             &lt;goals&gt;
142     *               &lt;goal&gt;copy&lt;/goal&gt;
143     *             &lt;/goals&gt;
144     *             &lt;configuration&gt;
145     *               &lt;artifactItems&gt;
146     *                 &lt;artifactItem&gt;
147     *                   &lt;groupId&gt;${project.groupId}&lt;/groupId&gt;
148     *                   &lt;artifactId&gt;shared-ldap-extras-codec&lt;/artifactId&gt;
149     *                   &lt;version&gt;${project.version}&lt;/version&gt;
150     *                   &lt;outputDirectory&gt;${codec.plugin.directory}&lt;/outputDirectory&gt;
151     *                 &lt;/artifactItem&gt;
152     *               &lt;/artifactItems&gt;
153     *             &lt;/configuration&gt;
154     *           &lt;/execution&gt;
155     *         &lt;/executions&gt;
156     *       &lt;/plugin&gt;
157     *     &lt;/plugins&gt;
158     *   &lt;/build&gt;
159     * </pre>
160     */
161    public StandaloneLdapApiService() throws Exception
162    {
163        // Load the controls
164        loadControls();
165        
166        // Load the extended operations
167        loadExtendedOperations();
168        
169        // Load the schema elements
170        //loadSchemaElements();
171        
172        // Load the network layer
173        //loadNetworkLayer()
174        
175        if ( protocolCodecFactory == null )
176        {
177             try
178             {
179                 @SuppressWarnings("unchecked")
180                 Class<? extends ProtocolCodecFactory> clazz = ( Class<? extends ProtocolCodecFactory> )
181                 Class.forName( DEFAULT_PROTOCOL_CODEC_FACTORY );
182                 protocolCodecFactory = clazz.newInstance();
183             }
184             catch( Exception cause )
185             {
186                 throw new RuntimeException( "Failed to load default codec factory.", cause );
187             }
188        }
189    }
190    
191    
192    /**
193     * Load the controls
194     * 
195     * @throws Exception
196     */
197    private void loadControls() throws Exception
198    {
199        // first load the default controls
200        loadDefaultControls();
201        
202        // The load the extra controls
203        loadExtraControls();
204    }
205    
206    
207    /**
208     * Loads the Controls implemented out of the box in the codec.
209     */
210    private void loadDefaultControls() throws Exception
211    {
212        // Load defaults from command line properties if it exists
213        String defaultControlsList = System.getProperty( DEFAULT_CONTROLS_LIST );
214        
215        if ( Strings.isEmpty( defaultControlsList ) )
216        {
217            return;
218        }
219
220        for ( String control : defaultControlsList.split( "," ) )
221        {
222            Class<?>[] types = new Class<?>[] { LdapApiService.class };
223            Class<? extends ControlFactory<?, ?>> clazz = ( Class<? extends ControlFactory<?, ?>> )Class.forName( control );
224            Constructor<?> constructor = clazz.getConstructor(types);
225            
226            ControlFactory<?, ?> factory = (ControlFactory<?, ?>)constructor.newInstance( new Object[]{ this } );
227            controlFactories.put( factory.getOid(), factory );
228            LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
229        }
230    }
231    
232    
233    /**
234     * Loads the extra Controls
235     */
236    private void loadExtraControls() throws Exception
237    {
238        // Load extra from command line properties if it exists
239        String extraControlsList = System.getProperty( EXTRA_CONTROLS_LIST );
240        
241        if ( Strings.isEmpty( extraControlsList ) )
242        {
243            return;
244        }
245        
246        for ( String control : extraControlsList.split( "," ) )
247        {
248            Class<?>[] types = new Class<?>[] { LdapApiService.class };
249            Class<? extends ControlFactory<?, ?>> clazz = ( Class<? extends ControlFactory<?, ?>> )Class.forName( control );
250            Constructor<?> constructor = clazz.getConstructor(types);
251            
252            ControlFactory<?, ?> factory = (ControlFactory<?, ?>)constructor.newInstance( new Object[]{ this } );
253            controlFactories.put( factory.getOid(), factory );
254            LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
255        }
256    }
257    
258
259    /**
260     * Load the extended operations
261     * 
262     * @throws Exception
263     */
264    private void loadExtendedOperations() throws Exception
265    {
266        loadDefaultExtendedOperationRequests();
267        loadDefaultExtendedOperationResponses();
268        loadExtraExtendedOperations();
269    }
270    
271    
272    /**
273     * Loads the default extended operation requests
274     */
275    private void loadDefaultExtendedOperationRequests() throws Exception
276    {
277        // Load from command line properties if it exists
278        String defaultExtendedOperationsList = System.getProperty( DEFAULT_EXTENDED_OPERATION_REQUESTS_LIST );
279        
280        if ( Strings.isEmpty( defaultExtendedOperationsList ) )
281        {
282            return;
283        }
284        
285        for ( String extendedOperation : defaultExtendedOperationsList.split( "," ) )
286        {
287            Class<?>[] types = new Class<?>[] { LdapApiService.class };
288            Class<? extends ExtendedRequestFactory<?,?>> clazz = ( Class<? extends ExtendedRequestFactory<?,?>> )Class.forName( extendedOperation );
289            Constructor<?> constructor = clazz.getConstructor(types);
290            
291            ExtendedRequestFactory<?,?> factory = (ExtendedRequestFactory<?,?>)constructor.newInstance( new Object[]{ this } );
292            extReqFactories.put( factory.getOid(), factory );
293            LOG.info( "Registered pre-bundled extended operation factory: {}", factory.getOid() );
294        }
295    }
296    
297    
298    /**
299     * Loads the default extended operation responses
300     */
301    private void loadDefaultExtendedOperationResponses() throws Exception
302    {
303        // Load from command line properties if it exists
304        String defaultExtendedOperationsList = System.getProperty( DEFAULT_EXTENDED_OPERATION_RESPONSES_LIST );
305        
306        if ( Strings.isEmpty( defaultExtendedOperationsList ) )
307        {
308            return;
309        }
310        
311        for ( String extendedOperation : defaultExtendedOperationsList.split( "," ) )
312        {
313            Class<?>[] types = new Class<?>[] { LdapApiService.class };
314            Class<? extends UnsolicitedResponseFactory<?>> clazz = ( Class<? extends UnsolicitedResponseFactory<?>> )Class.forName( extendedOperation );
315            Constructor<?> constructor = clazz.getConstructor(types);
316            
317            UnsolicitedResponseFactory<?> factory = (UnsolicitedResponseFactory<?>)constructor.newInstance( new Object[]{ this } );
318            unsolicitedFactories.put( factory.getOid(), factory );
319            LOG.info( "Registered pre-bundled extended operation factory: {}", factory.getOid() );
320        }
321    }
322    
323    
324    /**
325     * Loads the extra extended operations
326     */
327    private void loadExtraExtendedOperations()
328    {
329        
330    }
331    
332    
333    //-------------------------------------------------------------------------
334    // LdapCodecService implementation methods
335    //-------------------------------------------------------------------------
336    /**
337     * {@inheritDoc}
338     */
339    public ControlFactory<?,?> registerControl( ControlFactory<?,?> factory )
340    {
341        return controlFactories.put( factory.getOid(), factory );
342    }
343    
344
345    /**
346     * {@inheritDoc}
347     */
348    public ControlFactory<?,?> unregisterControl( String oid )
349    {
350        return controlFactories.remove( oid );
351    }
352
353    
354    /**
355     * {@inheritDoc}
356     */
357    public Iterator<String> registeredControls()
358    {
359        return Collections.unmodifiableSet( controlFactories.keySet() ).iterator();
360    }
361    
362    
363    /**
364     * {@inheritDoc}
365     */
366    public boolean isControlRegistered( String oid )
367    {
368        return controlFactories.containsKey( oid );
369    }
370    
371
372    /**
373     * {@inheritDoc}
374     */
375    public Iterator<String> registeredExtendedRequests()
376    {
377        return Collections.unmodifiableSet( extReqFactories.keySet() ).iterator();
378    }
379
380    
381    /**
382     * {@inheritDoc}
383     */
384    public ExtendedRequestFactory<?, ?> registerExtendedRequest( ExtendedRequestFactory<?,?> factory )
385    {
386        return extReqFactories.put( factory.getOid(), factory );
387    }
388
389    
390    /**
391     * {@inheritDoc}
392     */
393    public ProtocolCodecFactory getProtocolCodecFactory()
394    {
395        return protocolCodecFactory;
396    }
397
398    
399    /**
400     * {@inheritDoc}
401     */
402    public ProtocolCodecFactory registerProtocolCodecFactory( ProtocolCodecFactory protocolCodecFactory )
403    {
404        ProtocolCodecFactory old = this.protocolCodecFactory;
405        this.protocolCodecFactory = protocolCodecFactory;
406        return old;
407    }
408    
409    
410    /**
411     * {@inheritDoc}
412     */
413    public CodecControl<? extends Control> newControl( String oid )
414    {
415        ControlFactory<?,?> factory = controlFactories.get( oid );
416        
417        if ( factory == null )
418        {
419            return new BasicControlDecorator<Control>( this, new OpaqueControl( oid ) );
420        }
421        
422        return factory.newCodecControl();
423    }
424
425
426    /**
427     * {@inheritDoc}
428     */
429    @SuppressWarnings("unchecked")
430    public CodecControl<? extends Control> newControl( Control control )
431    {
432        if ( control == null )
433        {
434            throw new NullPointerException( "Control argument was null." );
435        }
436        
437        // protect agains being multiply decorated
438        if ( control instanceof CodecControl )
439        {
440            return (org.apache.directory.shared.ldap.codec.api.CodecControl<?> )control;
441        }
442        
443        @SuppressWarnings("rawtypes")
444        ControlFactory factory = controlFactories.get( control.getOid() );
445        
446        if ( factory == null )
447        {
448            return new BasicControlDecorator<Control>( this, control ); 
449        }
450        
451        return factory.newCodecControl( control );
452    }
453
454
455    /**
456     * {@inheritDoc}
457     */
458    public javax.naming.ldap.Control toJndiControl( Control control ) throws EncoderException
459    {
460        CodecControl<? extends Control> decorator = newControl( control );
461        ByteBuffer bb = ByteBuffer.allocate( decorator.computeLength() );
462        decorator.encode( bb );
463        bb.flip();
464        BasicControl jndiControl = 
465            new BasicControl( control.getOid(), control.isCritical(), bb.array() );
466        return jndiControl;
467    }
468
469
470    /**
471     * {@inheritDoc}
472     */
473    public Control fromJndiControl( javax.naming.ldap.Control control ) throws DecoderException
474    {
475        @SuppressWarnings("rawtypes")
476        ControlFactory factory = controlFactories.get( control.getID() );
477        
478        if ( factory == null )
479        {
480            OpaqueControl ourControl = new OpaqueControl( control.getID() );
481            ourControl.setCritical( control.isCritical() );
482            BasicControlDecorator<Control> decorator = 
483                new BasicControlDecorator<Control>( this, ourControl );
484            decorator.setValue( control.getEncodedValue() );
485            return decorator;
486        }
487        
488        @SuppressWarnings("unchecked")
489        CodecControl<? extends Control> ourControl = factory.newCodecControl();
490        ourControl.setCritical( control.isCritical() );
491        ourControl.setValue( control.getEncodedValue() );
492        ourControl.decode( control.getEncodedValue() );
493        
494        return ourControl;
495    }
496
497
498    /**
499     * {@inheritDoc}
500     */
501    public Asn1Container newMessageContainer()
502    {
503        return new LdapMessageContainer<MessageDecorator<? extends Message>>( this );
504    }
505
506
507    /**
508     * {@inheritDoc}
509     */
510    public Iterator<String> registeredUnsolicitedResponses()
511    {
512        return Collections.unmodifiableSet( unsolicitedFactories.keySet() ).iterator();
513    }
514
515
516    /**
517     * {@inheritDoc}
518     */
519    public UnsolicitedResponseFactory<?> registerUnsolicitedResponse( UnsolicitedResponseFactory<?> factory )
520    {
521        return unsolicitedFactories.put( factory.getOid(), factory );
522    }
523
524
525    /**
526     * {@inheritDoc}
527     */
528    public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException
529    {
530        throw new NotImplementedException( "Figure out how to transform" );
531    }
532    
533
534    /**
535     * {@inheritDoc}
536     */
537    public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException
538    {   
539        throw new NotImplementedException( "Figure out how to transform" );
540    }
541
542
543    /**
544     * {@inheritDoc}
545     */
546    public ExtendedRequestFactory<?, ?> unregisterExtendedRequest( String oid )
547    {
548        return extReqFactories.remove( oid );
549    }
550
551
552    /**
553     * {@inheritDoc}
554     */
555    public UnsolicitedResponseFactory<?> unregisterUnsolicitedResponse( String oid )
556    {
557        return unsolicitedFactories.remove( oid );
558    }
559
560
561    /**
562     * {@inheritDoc}
563     */
564    public ExtendedRequest<?> fromJndi( javax.naming.ldap.ExtendedRequest jndiRequest ) throws DecoderException
565    {
566        ExtendedRequestDecorator<?,?> decorator =
567            ( ExtendedRequestDecorator<?, ?> ) newExtendedRequest( jndiRequest.getID(), jndiRequest.getEncodedValue() );
568        return decorator;
569    }
570
571
572    /**
573     * {@inheritDoc}
574     */
575    public javax.naming.ldap.ExtendedRequest toJndi( final ExtendedRequest<?> modelRequest ) throws EncoderException
576    {
577        final String oid = modelRequest.getRequestName();
578        final byte[] value;
579        
580        if ( modelRequest instanceof ExtendedRequestDecorator )
581        {
582            ExtendedRequestDecorator<?, ?> decorator = ( ExtendedRequestDecorator<?, ?> ) modelRequest;
583            value = decorator.getRequestValue();
584        }
585        else
586        {
587            // have to ask the factory to decorate for us - can't do it ourselves
588            ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( modelRequest.getRequestName() );
589            ExtendedRequestDecorator<?, ?> decorator = extendedRequestFactory.decorate( modelRequest );
590            value = decorator.getRequestValue();
591        }
592        
593        
594        javax.naming.ldap.ExtendedRequest jndiRequest = new javax.naming.ldap.ExtendedRequest()
595        {
596            private static final long serialVersionUID = -4160980385909987475L;
597
598            public String getID()
599            {
600                return oid;
601            }
602
603            public byte[] getEncodedValue()
604            {
605                return value;
606            }
607
608            public javax.naming.ldap.ExtendedResponse createExtendedResponse( String id, byte[] berValue, int offset,
609                int length ) throws NamingException
610            {
611                ExtendedRequestFactory<?,?> factory = extReqFactories.get( modelRequest.getRequestName() );
612                
613                try
614                {
615                    final ExtendedResponseDecorator<?> resp = ( ExtendedResponseDecorator<?> ) factory.newResponse( berValue );
616                    javax.naming.ldap.ExtendedResponse jndiResponse = new javax.naming.ldap.ExtendedResponse()
617                    {
618                        private static final long serialVersionUID = -7686354122066100703L;
619
620                        public String getID()
621                        {
622                            return oid;
623                        }
624
625                        public byte[] getEncodedValue()
626                        {
627                            return resp.getResponseValue();
628                        }
629                    };
630                    
631                    return jndiResponse;
632                }
633                catch ( DecoderException e )
634                {
635                    NamingException ne = new NamingException( "Unable to decode encoded response value: " + 
636                        Strings.dumpBytes( berValue ) );
637                    ne.setRootCause( e );
638                    throw ne;
639                }
640            }
641        };
642
643        return jndiRequest;
644    }
645
646
647    /**
648     * {@inheritDoc}
649     * @throws DecoderException 
650     */
651    @SuppressWarnings("unchecked")
652    public <E extends ExtendedResponse> E newExtendedResponse( ExtendedRequest<E> req, byte[] serializedResponse ) throws DecoderException
653    {
654        ExtendedResponseDecorator<ExtendedResponse> resp;
655        
656        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( req.getRequestName() );
657        
658        if ( extendedRequestFactory != null )
659        {
660            resp = ( ExtendedResponseDecorator<ExtendedResponse> ) extendedRequestFactory.newResponse( serializedResponse );
661        }
662        else
663        {
664            resp = new ExtendedResponseDecorator<ExtendedResponse>( this, 
665                new ExtendedResponseImpl( req.getRequestName() ) );
666            resp.setResponseValue( serializedResponse );
667            resp.setResponseName( req.getRequestName() );
668        }
669        
670        resp.setMessageId( req.getMessageId() );
671        
672        return ( E ) resp;
673    }
674
675
676    /**
677     * {@inheritDoc}
678     */
679    public ExtendedRequest<?> newExtendedRequest( String oid, byte[] value )
680    {
681        ExtendedRequest<?> req = null;
682        
683        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( oid );
684        
685        if ( extendedRequestFactory != null )
686        {
687            if ( value == null )
688            {
689                req = extendedRequestFactory.newRequest();
690            }
691            else
692            {
693                req = extendedRequestFactory.newRequest( value );
694            }
695        }
696        else
697        {
698            ExtendedRequestDecorator<ExtendedRequest<ExtendedResponse>, ExtendedResponse> decorator = 
699                new ExtendedRequestDecorator<ExtendedRequest<ExtendedResponse>, ExtendedResponse>( this, 
700                    new ExtendedRequestImpl() );
701            decorator.setRequestName( oid );
702            decorator.setRequestValue( value );
703            req = decorator;
704        }
705        
706        return req;
707    }
708
709
710    /**
711     * {@inheritDoc}
712     */
713    @SuppressWarnings("unchecked")
714    public ExtendedRequestDecorator<?, ?> decorate( ExtendedRequest<?> decoratedMessage )
715    {
716        ExtendedRequestDecorator<?,?> req = null;
717        
718        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( decoratedMessage.getRequestName() );
719        
720        if ( extendedRequestFactory != null )
721        {
722            req = extendedRequestFactory.decorate( decoratedMessage );
723        }
724        else
725        {
726            req = new ExtendedRequestDecorator<ExtendedRequest<ExtendedResponse>, ExtendedResponse>( this, 
727                    ( ExtendedRequest<ExtendedResponse> ) decoratedMessage );
728        }
729        
730        return req;
731    }
732
733
734    /**
735     * {@inheritDoc}
736     */
737    public ExtendedResponseDecorator<?> decorate( ExtendedResponse decoratedMessage )
738    {
739        ExtendedResponseDecorator<?> resp = null;
740        
741        UnsolicitedResponseFactory<?> unsolicitedResponseFactory = unsolicitedFactories.get( decoratedMessage.getResponseName() );
742        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( decoratedMessage.getResponseName() );
743        
744        if ( extendedRequestFactory != null )
745        {
746            resp = extendedRequestFactory.decorate( decoratedMessage );
747        }
748        else if ( unsolicitedResponseFactory != null )
749        {
750            resp = unsolicitedResponseFactory.decorate( decoratedMessage );
751        }
752        else
753        {
754            resp = new ExtendedResponseDecorator<ExtendedResponse>( this, decoratedMessage );
755        }
756        
757        return resp;
758    }
759
760
761    /**
762     * {@inheritDoc}
763     */
764    public boolean isExtendedOperationRegistered( String oid )
765    {
766        return extReqFactories.containsKey( oid ) || unsolicitedFactories.containsKey( oid );
767    }
768}