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.api;
021
022
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.directory.api.asn1.Asn1Object;
027import org.apache.directory.api.ldap.codec.decorators.AbandonRequestDecorator;
028import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
029import org.apache.directory.api.ldap.codec.decorators.AddResponseDecorator;
030import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
031import org.apache.directory.api.ldap.codec.decorators.BindResponseDecorator;
032import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
033import org.apache.directory.api.ldap.codec.decorators.CompareResponseDecorator;
034import org.apache.directory.api.ldap.codec.decorators.DeleteRequestDecorator;
035import org.apache.directory.api.ldap.codec.decorators.DeleteResponseDecorator;
036import org.apache.directory.api.ldap.codec.decorators.IntermediateResponseDecorator;
037import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
038import org.apache.directory.api.ldap.codec.decorators.ModifyDnResponseDecorator;
039import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
040import org.apache.directory.api.ldap.codec.decorators.ModifyResponseDecorator;
041import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
042import org.apache.directory.api.ldap.codec.decorators.SearchResultDoneDecorator;
043import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
044import org.apache.directory.api.ldap.codec.decorators.SearchResultReferenceDecorator;
045import org.apache.directory.api.ldap.codec.decorators.UnbindRequestDecorator;
046import org.apache.directory.api.ldap.model.message.AbandonRequest;
047import org.apache.directory.api.ldap.model.message.AddRequest;
048import org.apache.directory.api.ldap.model.message.AddResponse;
049import org.apache.directory.api.ldap.model.message.BindRequest;
050import org.apache.directory.api.ldap.model.message.BindResponse;
051import org.apache.directory.api.ldap.model.message.CompareRequest;
052import org.apache.directory.api.ldap.model.message.CompareResponse;
053import org.apache.directory.api.ldap.model.message.Control;
054import org.apache.directory.api.ldap.model.message.DeleteRequest;
055import org.apache.directory.api.ldap.model.message.DeleteResponse;
056import org.apache.directory.api.ldap.model.message.ExtendedRequest;
057import org.apache.directory.api.ldap.model.message.ExtendedResponse;
058import org.apache.directory.api.ldap.model.message.IntermediateResponse;
059import org.apache.directory.api.ldap.model.message.Message;
060import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
061import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
062import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
063import org.apache.directory.api.ldap.model.message.ModifyRequest;
064import org.apache.directory.api.ldap.model.message.ModifyResponse;
065import org.apache.directory.api.ldap.model.message.SearchRequest;
066import org.apache.directory.api.ldap.model.message.SearchResultDone;
067import org.apache.directory.api.ldap.model.message.SearchResultEntry;
068import org.apache.directory.api.ldap.model.message.SearchResultReference;
069import org.apache.directory.api.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>, Asn1Object
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 ( 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     * {@inheritDoc}
276     */
277    public MessageTypeEnum getType()
278    {
279        return decoratedMessage.getType();
280    }
281
282
283    /**
284     * {@inheritDoc}
285     */
286    public Map<String, Control> getControls()
287    {
288        return controls;
289    }
290
291
292    /**
293     * {@inheritDoc}
294     */
295    public Control getControl( String oid )
296    {
297        return controls.get( oid );
298    }
299
300
301    /**
302     * {@inheritDoc}
303     */
304    public boolean hasControl( String oid )
305    {
306        return controls.containsKey( oid );
307    }
308
309
310    /**
311     * {@inheritDoc}
312     */
313    @SuppressWarnings("unchecked")
314    public Message addControl( Control control )
315    {
316        Control decorated;
317        CodecControl<? extends Control> controlDecorator;
318
319        if ( control instanceof ControlDecorator )
320        {
321            controlDecorator = ( org.apache.directory.api.ldap.codec.api.CodecControl<? extends Control> ) control;
322            decorated = controlDecorator.getDecorated();
323        }
324        else
325        {
326            controlDecorator = codec.newControl( control );
327            decorated = control;
328        }
329
330        decoratedMessage.addControl( decorated );
331        controls.put( control.getOid(), controlDecorator );
332        currentControl = controlDecorator;
333
334        return this;
335    }
336
337
338    /**
339     * {@inheritDoc}
340     */
341    public Message addAllControls( Control[] controls )
342    {
343        for ( Control control : controls )
344        {
345            addControl( control );
346        }
347
348        return this;
349    }
350
351
352    /**
353     * {@inheritDoc}
354     */
355    public Message removeControl( Control control )
356    {
357        decoratedMessage.removeControl( control );
358        controls.remove( control.getOid() );
359
360        return this;
361    }
362
363
364    /**
365     * {@inheritDoc}
366     */
367    public int getMessageId()
368    {
369        return decoratedMessage.getMessageId();
370    }
371
372
373    /**
374     * {@inheritDoc}
375     */
376    public Object get( Object key )
377    {
378        return decoratedMessage.get( key );
379    }
380
381
382    /**
383     * {@inheritDoc}
384     */
385    public Object put( Object key, Object value )
386    {
387        return decoratedMessage.put( key, value );
388    }
389
390
391    /**
392     * {@inheritDoc}
393     */
394    public Message setMessageId( int messageId )
395    {
396        decoratedMessage.setMessageId( messageId );
397
398        return this;
399    }
400
401
402    /**
403     * Delegates to the toString() method of the decorated Message.
404     */
405    public String toString()
406    {
407        return decoratedMessage.toString();
408    }
409
410
411    /**
412     * {@inheritDoc}
413     */
414    public E getDecorated()
415    {
416        return decoratedMessage;
417    }
418
419
420    /**
421     * {@inheritDoc}
422     */
423    public LdapApiService getCodecService()
424    {
425        return codec;
426    }
427}