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.api;
021
022
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
027import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
028import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
029import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
030import org.apache.directory.shared.ldap.codec.decorators.BindResponseDecorator;
031import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
032import org.apache.directory.shared.ldap.codec.decorators.CompareResponseDecorator;
033import org.apache.directory.shared.ldap.codec.decorators.DeleteRequestDecorator;
034import org.apache.directory.shared.ldap.codec.decorators.DeleteResponseDecorator;
035import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
036import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
037import org.apache.directory.shared.ldap.codec.decorators.ModifyDnResponseDecorator;
038import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
039import org.apache.directory.shared.ldap.codec.decorators.ModifyResponseDecorator;
040import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
041import org.apache.directory.shared.ldap.codec.decorators.SearchResultDoneDecorator;
042import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
043import org.apache.directory.shared.ldap.codec.decorators.SearchResultReferenceDecorator;
044import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
045import org.apache.directory.shared.ldap.model.exception.MessageException;
046import org.apache.directory.shared.ldap.model.message.AbandonRequest;
047import org.apache.directory.shared.ldap.model.message.AddRequest;
048import org.apache.directory.shared.ldap.model.message.AddResponse;
049import org.apache.directory.shared.ldap.model.message.BindRequest;
050import org.apache.directory.shared.ldap.model.message.BindResponse;
051import org.apache.directory.shared.ldap.model.message.CompareRequest;
052import org.apache.directory.shared.ldap.model.message.CompareResponse;
053import org.apache.directory.shared.ldap.model.message.Control;
054import org.apache.directory.shared.ldap.model.message.DeleteRequest;
055import org.apache.directory.shared.ldap.model.message.DeleteResponse;
056import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
057import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
058import org.apache.directory.shared.ldap.model.message.IntermediateResponse;
059import org.apache.directory.shared.ldap.model.message.Message;
060import org.apache.directory.shared.ldap.model.message.MessageTypeEnum;
061import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
062import org.apache.directory.shared.ldap.model.message.ModifyDnResponse;
063import org.apache.directory.shared.ldap.model.message.ModifyRequest;
064import org.apache.directory.shared.ldap.model.message.ModifyResponse;
065import org.apache.directory.shared.ldap.model.message.SearchRequest;
066import org.apache.directory.shared.ldap.model.message.SearchResultDone;
067import org.apache.directory.shared.ldap.model.message.SearchResultEntry;
068import org.apache.directory.shared.ldap.model.message.SearchResultReference;
069import org.apache.directory.shared.ldap.model.message.UnbindRequest;
070
071
072/**
073 * A decorator for the generic LDAP Message
074 *
075 * @TODO make this class abstract, after finishing switch and all types and make default blow an EncoderException
076 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
077 */
078public abstract class MessageDecorator<E extends Message> implements Message, Decorator<E>
079{
080    /** The decorated Control */
081    private final E decoratedMessage;
082
083    /** Map of message controls using OID Strings for keys and Control values */
084    private final Map<String, Control> controls;
085
086    /** The current control */
087    private CodecControl<? extends Control> currentControl;
088
089    /** The encoded Message length */
090    protected int messageLength;
091
092    /** The length of the controls */
093    private int controlsLength;
094    
095    /** The LdapCodecService */
096    private final LdapApiService codec;
097
098    
099    public static MessageDecorator<? extends Message> getDecorator( LdapApiService codec, Message decoratedMessage )
100    {
101        if ( decoratedMessage instanceof MessageDecorator )
102        {
103            return (org.apache.directory.shared.ldap.codec.api.MessageDecorator<?> ) decoratedMessage;
104        }
105        
106        MessageDecorator<?> decorator = null;
107        
108        switch ( decoratedMessage.getType() )
109        {
110            case ABANDON_REQUEST:
111                decorator = new AbandonRequestDecorator( codec, ( AbandonRequest ) decoratedMessage );
112                break;
113
114            case ADD_REQUEST:
115                decorator = new AddRequestDecorator( codec, ( AddRequest ) decoratedMessage );
116                break;
117                
118            case ADD_RESPONSE:
119                decorator = new AddResponseDecorator( codec, ( AddResponse ) decoratedMessage );
120                break;
121                
122            case BIND_REQUEST:
123                decorator = new BindRequestDecorator( codec, ( BindRequest ) decoratedMessage );
124                break;
125                
126            case BIND_RESPONSE:
127                decorator = new BindResponseDecorator( codec, ( BindResponse ) decoratedMessage );
128                break;
129                
130            case COMPARE_REQUEST:
131                decorator = new CompareRequestDecorator( codec, ( CompareRequest ) decoratedMessage );
132                break;
133                
134            case COMPARE_RESPONSE:
135                decorator = new CompareResponseDecorator( codec, ( CompareResponse ) decoratedMessage );
136                break;
137                
138            case DEL_REQUEST:
139                decorator = new DeleteRequestDecorator( codec, ( DeleteRequest ) decoratedMessage );
140                break;
141
142            case DEL_RESPONSE:
143                decorator = new DeleteResponseDecorator( codec, ( DeleteResponse ) decoratedMessage );
144                break;
145                
146            case EXTENDED_REQUEST:
147                decorator = codec.decorate( ( ExtendedRequest<?> ) decoratedMessage );
148                break;
149                
150            case EXTENDED_RESPONSE:
151                decorator = codec.decorate( ( ExtendedResponse ) decoratedMessage );
152                break;
153                
154            case INTERMEDIATE_RESPONSE:
155                decorator = new IntermediateResponseDecorator( codec, ( IntermediateResponse ) decoratedMessage );
156                break;
157                
158            case MODIFY_REQUEST:
159                decorator = new ModifyRequestDecorator( codec, ( ModifyRequest ) decoratedMessage );
160                break;
161                
162            case MODIFY_RESPONSE:
163                decorator = new ModifyResponseDecorator( codec, ( ModifyResponse ) decoratedMessage );
164                break;
165                
166            case MODIFYDN_REQUEST:
167                decorator = new ModifyDnRequestDecorator( codec, ( ModifyDnRequest ) decoratedMessage );
168                break;
169                
170            case MODIFYDN_RESPONSE:
171                decorator = new ModifyDnResponseDecorator( codec, ( ModifyDnResponse ) decoratedMessage );
172                break;
173                
174            case SEARCH_REQUEST:
175                decorator = new SearchRequestDecorator( codec, ( SearchRequest ) decoratedMessage );
176                break;
177                
178            case SEARCH_RESULT_DONE:
179                decorator = new SearchResultDoneDecorator( codec, ( SearchResultDone ) decoratedMessage );
180                break;
181                
182            case SEARCH_RESULT_ENTRY:
183                decorator = new SearchResultEntryDecorator( codec, ( SearchResultEntry ) decoratedMessage );
184                break;
185                
186            case SEARCH_RESULT_REFERENCE:
187                decorator = new SearchResultReferenceDecorator( codec, ( SearchResultReference ) decoratedMessage );
188                break;
189            
190            case UNBIND_REQUEST:
191                decorator = new UnbindRequestDecorator( codec, ( UnbindRequest ) decoratedMessage );
192                break;
193                
194            default :
195                return null;
196        }
197        
198        Map<String, Control> controls = decoratedMessage.getControls();
199        
200        if ( controls != null )
201        {
202            for ( Control control : controls.values() )
203            {
204                decorator.addControl( control );
205            }
206        }
207        
208        return decorator;
209    }
210
211
212    /**
213     * Makes a Message an Decorator object.
214     */
215    protected MessageDecorator( LdapApiService codec, E decoratedMessage )
216    {
217        this.codec = codec;
218        this.decoratedMessage = decoratedMessage;
219        controls = new HashMap<String, Control>();
220    }
221
222
223    /**
224     * @param controlsLength the encoded controls length
225     */
226    public void setControlsLength( int controlsLength )
227    {
228        this.controlsLength = controlsLength;
229    }
230
231
232    /**
233     * @return the encoded controls length
234     */
235    public int getControlsLength()
236    {
237        return controlsLength;
238    }
239
240
241    /**
242     * @param messageLength The encoded message length
243     */
244    public void setMessageLength( int messageLength )
245    {
246        this.messageLength = messageLength;
247    }
248
249
250    /**
251     * @return The encoded message length
252     */
253    public int getMessageLength()
254    {
255        return messageLength;
256    }
257
258
259    /**
260     * Get the current Control Object
261     * 
262     * @return The current Control Object
263     */
264    public CodecControl<? extends Control> getCurrentControl()
265    {
266        return currentControl;
267    }
268
269    
270    //-------------------------------------------------------------------------
271    // The Message methods
272    //-------------------------------------------------------------------------
273    
274    
275    /**
276     * {@inheritDoc}
277     */
278    public MessageTypeEnum getType()
279    {
280        return decoratedMessage.getType();
281    }
282
283
284    /**
285     * {@inheritDoc}
286     */
287    public Map<String, Control> getControls()
288    {
289        return controls;
290    }
291
292
293    /**
294     * {@inheritDoc}
295     */
296    public Control getControl( String oid )
297    {
298        return controls.get( oid );
299    }
300
301
302    /**
303     * {@inheritDoc}
304     */
305    public boolean hasControl( String oid )
306    {
307        return controls.containsKey( oid );
308    }
309
310
311    /**
312     * {@inheritDoc}
313     */
314    @SuppressWarnings("unchecked")
315    public Message addControl( Control control ) throws MessageException
316    {
317        Control decorated;
318        CodecControl<? extends Control> controlDecorator;
319        
320        if ( control instanceof ControlDecorator)
321        {
322            controlDecorator = (org.apache.directory.shared.ldap.codec.api.CodecControl<? extends Control> ) control;
323            decorated = controlDecorator.getDecorated();
324        }
325        else
326        {
327            controlDecorator = codec.newControl( control );
328            decorated = control;
329        }
330        
331        decoratedMessage.addControl( decorated );
332        controls.put( control.getOid(), controlDecorator );
333        currentControl = controlDecorator;
334
335        return this;
336    }
337
338
339    /**
340     * {@inheritDoc}
341     */
342    public Message addAllControls( Control[] controls ) throws MessageException
343    {
344        for ( Control control : controls )
345        {
346            addControl( control );
347        }
348
349        return this;
350    }
351
352
353    /**
354     * {@inheritDoc}
355     */
356    public Message removeControl( Control control ) throws MessageException
357    {
358        decoratedMessage.removeControl( control );
359        controls.remove( control.getOid() );
360
361        return this;
362    }
363
364
365    /**
366     * {@inheritDoc}
367     */
368    public int getMessageId()
369    {
370        return decoratedMessage.getMessageId();
371    }
372
373
374    /**
375     * {@inheritDoc}
376     */
377    public Object get( Object key )
378    {
379        return decoratedMessage.get( key );
380    }
381
382
383    /**
384     * {@inheritDoc}
385     */
386    public Object put( Object key, Object value )
387    {
388        return decoratedMessage.put( key, value );
389    }
390
391
392    /**
393     * {@inheritDoc}
394     */
395    public Message setMessageId( int messageId )
396    {
397        decoratedMessage.setMessageId( messageId );
398        
399        return this;
400    }
401
402
403    /**
404     * Delegates to the toString() method of the decorated Message.
405     */
406    public String toString()
407    {
408        return decoratedMessage.toString();
409    }
410
411
412    /**
413     * {@inheritDoc}
414     */
415    public E getDecorated()
416    {
417        return decoratedMessage;
418    }
419    
420
421    /**
422     * {@inheritDoc}
423     */
424    public LdapApiService getCodecService()
425    {
426        return codec;
427    }
428}