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