View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.ldap.codec.api;
21  
22  
23  import org.apache.directory.api.asn1.DecoderException;
24  import org.apache.directory.api.asn1.ber.AbstractContainer;
25  import org.apache.directory.api.asn1.ber.tlv.TLV;
26  import org.apache.directory.api.ldap.codec.LdapMessageGrammar;
27  import org.apache.directory.api.ldap.codec.LdapStatesEnum;
28  import org.apache.directory.api.ldap.codec.search.ConnectorFilter;
29  import org.apache.directory.api.ldap.codec.search.Filter;
30  import org.apache.directory.api.ldap.codec.search.PresentFilter;
31  import org.apache.directory.api.ldap.model.entry.Attribute;
32  import org.apache.directory.api.ldap.model.entry.Modification;
33  import org.apache.directory.api.ldap.model.message.Control;
34  import org.apache.directory.api.ldap.model.message.ExtendedResponse;
35  import org.apache.directory.api.ldap.model.message.LdapResult;
36  import org.apache.directory.api.ldap.model.message.Message;
37  import org.apache.directory.api.ldap.model.message.ResultResponse;
38  import org.apache.directory.api.ldap.model.name.DnFactory;
39  
40  
41  /**
42   * The LdapMessage container stores all the messages decoded by the Asn1Decoder.
43   * When dealing with an encoding PDU, we will obtain a LdapMessage in the
44   * container.
45   *
46   * @param <E> The decorated message
47   * 
48   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
49   */
50  public class LdapMessageContainer<E extends Message> extends AbstractContainer
51  {
52      /** The Message being decoded */
53      private E message;
54  
55      /** checks if attribute is binary */
56      private BinaryAttributeDetector binaryAttributeDetector;
57  
58      /** The message ID */
59      private int messageId;
60  
61      /** The current control */
62      private Control currentControl;
63      
64      /** The current control factory, if any */
65      private ControlFactory<?> controlFactory;
66      
67      /** The DN Factory used to speed up Ldap Message DN decoding */
68      private DnFactory dnFactory;
69      
70      /** The current Intermediate response factory */
71      private IntermediateOperationFactory intermediateFactory;
72      
73      /** The current Extended operation factory */
74      private ExtendedOperationFactory extendedFactory;
75  
76      /** The codec service */
77      private final LdapApiService codec;
78      
79      /** The current LdapResult for a response */
80      private LdapResult ldapResult;
81      
82      /** The current attribute being decoded */
83      private Attribute currentAttribute;
84  
85      /** A local storage for the MODIFY operation */
86      private Modification currentModification;
87      
88      /** The SearchRequest TLV id */
89      private int tlvId;
90  
91      /** A temporary storage for a terminal Filter */
92      private Filter terminalFilter;
93  
94      /** The current filter. This is used while decoding a PDU */
95      private Filter currentFilter;
96  
97      /** The global filter. This is used while decoding a PDU */
98      private Filter topFilter;
99  
100 
101     /**
102      * Creates a new LdapMessageContainer object. We will store ten grammars,
103      * it's enough ...
104      * 
105      * @param codec The LDAP service instance
106      */
107     public LdapMessageContainer( LdapApiService codec )
108     {
109         this( codec, new DefaultConfigurableBinaryAttributeDetector() );
110     }
111 
112 
113     /**
114      * Creates a new LdapMessageContainer object. 
115      *
116      * @param codec The LDAP service instance
117      * @param binaryAttributeDetector checks if an attribute is binary
118      */
119     public LdapMessageContainer( LdapApiService codec, BinaryAttributeDetector binaryAttributeDetector )
120     {
121         super();
122         this.codec = codec;
123         setGrammar( LdapMessageGrammar.getInstance() );
124         this.binaryAttributeDetector = binaryAttributeDetector;
125         setTransition( LdapStatesEnum.START_STATE );
126     }
127 
128 
129     /**
130      * Gets the {@link LdapApiService} associated with this Container.
131      *
132      * @return The LDAP service instance
133      */
134     public LdapApiService getLdapCodecService()
135     {
136         return codec;
137     }
138 
139 
140     /**
141      * @return Returns the ldapMessage.
142      */
143     public E getMessage()
144     {
145         return message;
146     }
147 
148 
149     /**
150      * Set a Message Object into the container. It will be completed by the
151      * ldapDecoder.
152      *
153      * @param message The message to set.
154      */
155     public void setMessage( E message )
156     {
157         this.message = message;
158     }
159 
160 
161     /**
162      * {@inheritDoc}
163      */
164     @Override
165     public void clean()
166     {
167         super.clean();
168 
169         messageId = -1;
170         tlvId = -1;
171         message = null;
172         ldapResult = null;
173         currentControl = null;
174         currentAttribute = null;
175         currentFilter = null;
176         terminalFilter = null;
177         topFilter = null;
178         controlFactory = null;
179         intermediateFactory = null;
180         extendedFactory = null;
181         setDecodedBytes( 0 );
182     }
183 
184 
185     /**
186      * @return Returns true if the attribute is binary.
187      * @param id checks if an attribute id is binary
188      */
189     public boolean isBinary( String id )
190     {
191         return binaryAttributeDetector.isBinary( id );
192     }
193 
194 
195     /**
196      * @return The message ID
197      */
198     public int getMessageId()
199     {
200         return messageId;
201     }
202 
203 
204     /**
205      * Set the message ID
206      * @param messageId the id of the message
207      */
208     public void setMessageId( int messageId )
209     {
210         this.messageId = messageId;
211     }
212 
213 
214     /**
215      * @return the current control being created
216      */
217     public Control getCurrentControl()
218     {
219         return currentControl;
220     }
221 
222 
223     /**
224      * Store a newly created control
225      * @param currentControl The control to store
226      */
227     public void setCurrentControl( Control currentControl )
228     {
229         this.currentControl = currentControl;
230     }
231 
232 
233     /**
234      * Sets the binary attribute detector
235      * 
236      * @param binaryAttributeDetector the binary attribute detector
237      */
238     public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
239     {
240         this.binaryAttributeDetector = binaryAttributeDetector;
241     }
242 
243 
244     /**
245      * @return the binary attribute detector
246      */
247     public BinaryAttributeDetector getBinaryAttributeDetector()
248     {
249         return binaryAttributeDetector;
250     }
251 
252 
253     /**
254      * @return the ldapResult
255      */
256     public LdapResult getLdapResult()
257     {
258         return ldapResult;
259     }
260 
261 
262     /**
263      * @param ldapResult the ldapResult to set
264      */
265     public void setLdapResult( LdapResult ldapResult )
266     {
267         this.ldapResult = ldapResult;
268     }
269 
270 
271     /**
272      * @return the controlFactory
273      */
274     public ControlFactory<?> getControlFactory()
275     {
276         return controlFactory;
277     }
278 
279 
280     /**
281      * @param controlFactory the controlFactory to set
282      */
283     public void setControlFactory( ControlFactory<?> controlFactory )
284     {
285         this.controlFactory = controlFactory;
286     }
287 
288 
289     /**
290      * @return the currentAttribute
291      */
292     public Attribute getCurrentAttribute()
293     {
294         return currentAttribute;
295     }
296 
297 
298     /**
299      * @param currentAttribute the currentAttribute to set
300      */
301     public void setCurrentAttribute( Attribute currentAttribute )
302     {
303         this.currentAttribute = currentAttribute;
304     }
305 
306 
307     /**
308      * @return the currentModification
309      */
310     public Modification getCurrentModification()
311     {
312         return currentModification;
313     }
314 
315 
316     /**
317      * @param currentModification the currentModification to set
318      */
319     public void setCurrentModification( Modification currentModification )
320     {
321         this.currentModification = currentModification;
322     }
323 
324 
325     /**
326      * Set the SearchRequest PDU TLV's Id
327      * @param tlvId The TLV id
328      */
329     public void setTlvId( int tlvId )
330     {
331         this.tlvId = tlvId;
332     }
333 
334 
335     /**
336      * @return the terminalFilter
337      */
338     public Filter getTerminalFilter()
339     {
340         return terminalFilter;
341     }
342 
343 
344     /**
345      * @param terminalFilter the terminalFilter to set
346      */
347     public void setTerminalFilter( Filter terminalFilter )
348     {
349         this.terminalFilter = terminalFilter;
350     }
351 
352 
353     /**
354      * @return the currentFilter
355      */
356     public Filter getCurrentFilter()
357     {
358         return currentFilter;
359     }
360 
361 
362     /**
363      * @param currentFilter the currentFilter to set
364      */
365     public void setCurrentFilter( Filter currentFilter )
366     {
367         this.currentFilter = currentFilter;
368     }
369 
370 
371     /**
372      * Add a current filter. We have two cases :
373      * - there is no previous current filter : the filter
374      * is the top level filter
375      * - there is a previous current filter : the filter is added
376      * to the currentFilter set, and the current filter is changed
377      *
378      * In any case, the previous current filter will always be a
379      * ConnectorFilter when this method is called.
380      *
381      * @param localFilter The filter to set.
382      * @throws DecoderException If the filter is invalid
383      */
384     public void addCurrentFilter( Filter localFilter ) throws DecoderException
385     {
386         if ( currentFilter != null )
387         {
388             // Ok, we have a parent. The new Filter will be added to
389             // this parent, and will become the currentFilter if it's a connector.
390             ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
391             localFilter.setParent( currentFilter, currentFilter.getTlvId() );
392 
393             if ( localFilter instanceof ConnectorFilter )
394             {
395                 currentFilter = localFilter;
396             }
397         }
398         else
399         {
400             // No parent. This Filter will become the root.
401             currentFilter = localFilter;
402             currentFilter.setParent( null, tlvId );
403             topFilter = localFilter;
404         }
405     }
406 
407 
408     /**
409      * This method is used to clear the filter's stack for terminated elements. An element
410      * is considered as terminated either if :
411      *  - it's a final element (ie an element which cannot contains a Filter)
412      *  - its current length equals its expected length.
413      */
414     public void unstackFilters()
415     {
416         TLV tlv = getCurrentTLV();
417         TLV localParent = tlv.getParent();
418         Filter localFilter = terminalFilter;
419 
420         // The parent has been completed, so fold it
421         while ( ( localParent != null ) && ( localParent.getExpectedLength() == 0 ) )
422         {
423             int parentTlvId = localFilter.getParent() != null ? localFilter.getParent().getTlvId() : localFilter
424                 .getParentTlvId();
425 
426             if ( localParent.getId() != parentTlvId )
427             {
428                 localParent = localParent.getParent();
429             }
430             else
431             {
432                 Filter filterParent = localFilter.getParent();
433 
434                 // We have a special case with PresentFilter, which has not been
435                 // pushed on the stack, so we need to get its parent's parent
436                 if ( localFilter instanceof PresentFilter )
437                 {
438                     if ( filterParent == null )
439                     {
440                         // We don't have parent, get out
441                         break;
442                     }
443 
444                     filterParent = filterParent.getParent();
445                 }
446                 else
447                 {
448                     filterParent = filterParent.getParent();
449                 }
450 
451                 if ( filterParent != null )
452                 {
453                     // The parent is a filter ; it will become the new currentFilter
454                     // and we will loop again.
455                     localFilter = currentFilter;
456                     currentFilter = filterParent;
457                     localParent = localParent.getParent();
458                 }
459                 else
460                 {
461                     // We can stop the recursion, we have reached the searchResult Object
462                     break;
463                 }
464             }
465         }
466     }
467     
468     
469     /**
470      * Copy the LdapResult element from a opaque response to a newly created 
471      * extendedResponse
472      *  
473      * @param resultResponse The original response
474      * @param extendedResponse The newly created ExtendedResponse
475      */
476     public static void copyLdapResult( ResultResponse resultResponse, ExtendedResponse extendedResponse )
477     {
478         extendedResponse.getLdapResult().setDiagnosticMessage( resultResponse.getLdapResult().getDiagnosticMessage() );
479         extendedResponse.getLdapResult().setMatchedDn( resultResponse.getLdapResult().getMatchedDn() );
480         extendedResponse.getLdapResult().setReferral( resultResponse.getLdapResult().getReferral() );
481         extendedResponse.getLdapResult().setResultCode( resultResponse.getLdapResult().getResultCode() );
482     }
483 
484 
485     /**
486      * @return the topFilter
487      */
488     public Filter getTopFilter()
489     {
490         return topFilter;
491     }
492 
493 
494     /**
495      * @param topFilter the topFilter to set
496      */
497     public void setTopFilter( Filter topFilter )
498     {
499         this.topFilter = topFilter;
500     }
501 
502 
503     /**
504      * @return the tlvId
505      */
506     public int getTlvId()
507     {
508         return tlvId;
509     }
510 
511 
512     /**
513      * @return the intermediateFactory
514      */
515     public IntermediateOperationFactory getIntermediateFactory()
516     {
517         return intermediateFactory;
518     }
519 
520 
521     /**
522      * @param intermediateFactory the intermediateFactory to set
523      */
524     public void setIntermediateFactory( IntermediateOperationFactory intermediateFactory )
525     {
526         this.intermediateFactory = intermediateFactory;
527     }
528 
529 
530     /**
531      * @return the extendedFactory
532      */
533     public ExtendedOperationFactory getExtendedFactory()
534     {
535         return extendedFactory;
536     }
537 
538 
539     /**
540      * @param extendedFactory the extendedFactory to set
541      */
542     public void setExtendedFactory( ExtendedOperationFactory extendedFactory )
543     {
544         this.extendedFactory = extendedFactory;
545     }
546 
547 
548     /**
549      * @return the dnFactory
550      */
551     public DnFactory getDnFactory()
552     {
553         return dnFactory;
554     }
555 
556 
557     /**
558      * @param dnFactory the dnFactory to set
559      */
560     public void setDnFactory( DnFactory dnFactory )
561     {
562         this.dnFactory = dnFactory;
563     }
564 }