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   *    http://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.dsmlv2.request;
21  
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.directory.api.asn1.DecoderException;
27  import org.apache.directory.api.dsmlv2.ParserUtils;
28  import org.apache.directory.api.ldap.codec.api.LdapApiService;
29  import org.apache.directory.api.ldap.codec.api.LdapConstants;
30  import org.apache.directory.api.ldap.model.entry.Value;
31  import org.apache.directory.api.ldap.model.exception.LdapException;
32  import org.apache.directory.api.ldap.model.filter.AndNode;
33  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
34  import org.apache.directory.api.ldap.model.filter.BranchNode;
35  import org.apache.directory.api.ldap.model.filter.EqualityNode;
36  import org.apache.directory.api.ldap.model.filter.ExprNode;
37  import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
38  import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
39  import org.apache.directory.api.ldap.model.filter.LeafNode;
40  import org.apache.directory.api.ldap.model.filter.LessEqNode;
41  import org.apache.directory.api.ldap.model.filter.NotNode;
42  import org.apache.directory.api.ldap.model.filter.OrNode;
43  import org.apache.directory.api.ldap.model.filter.PresenceNode;
44  import org.apache.directory.api.ldap.model.filter.SimpleNode;
45  import org.apache.directory.api.ldap.model.filter.SubstringNode;
46  import org.apache.directory.api.ldap.model.message.AliasDerefMode;
47  import org.apache.directory.api.ldap.model.message.Control;
48  import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
49  import org.apache.directory.api.ldap.model.message.SearchRequest;
50  import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
51  import org.apache.directory.api.ldap.model.message.SearchResultDone;
52  import org.apache.directory.api.ldap.model.message.SearchScope;
53  import org.apache.directory.api.ldap.model.name.Dn;
54  import org.dom4j.Element;
55  import org.dom4j.Namespace;
56  import org.dom4j.QName;
57  
58  
59  /**
60   * DSML Decorator for SearchRequest
61   *
62   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
63   */
64  public class SearchRequestDsml
65      extends AbstractResultResponseRequestDsml<SearchRequest, SearchResultDone>
66      implements SearchRequest
67  {
68      /** A temporary storage for a terminal Filter */
69      private Filter terminalFilter;
70  
71      /** The current filter. This is used while decoding a PDU */
72      private Filter currentFilter;
73  
74      /** The global filter. This is used while decoding a PDU */
75      private Filter topFilter;
76  
77  
78      /**
79       * Creates a new getDecoratedMessage() of SearchRequestDsml.
80       */
81      public SearchRequestDsml( LdapApiService codec )
82      {
83          super( codec, new SearchRequestImpl() );
84      }
85  
86  
87      /**
88       * Creates a new getDecoratedMessage() of SearchRequestDsml.
89       *
90       * @param ldapMessage
91       *      the message to decorate
92       */
93      public SearchRequestDsml( LdapApiService codec, SearchRequest ldapMessage )
94      {
95          super( codec, ldapMessage );
96      }
97  
98  
99      /**
100      * Gets the search filter associated with this search request.
101      *
102      * @return the expression node for the root of the filter expression tree.
103      */
104     public Filter getCodecFilter()
105     {
106         return topFilter;
107     }
108 
109 
110     /**
111      * Gets the search filter associated with this search request.
112      *
113      * @return the expression node for the root of the filter expression tree.
114      */
115     public ExprNode getFilterNode()
116     {
117         return transform( topFilter );
118     }
119 
120 
121     /**
122      * Get the terminal filter
123      *
124      * @return Returns the terminal filter.
125      */
126     public Filter getTerminalFilter()
127     {
128         return terminalFilter;
129     }
130 
131 
132     /**
133      * Set the terminal filter
134      *
135      * @param terminalFilter the teminalFilter.
136      */
137     public void setTerminalFilter( Filter terminalFilter )
138     {
139         this.terminalFilter = terminalFilter;
140     }
141 
142 
143     /**
144      * set the currentFilter to its parent
145      */
146     public void endCurrentConnectorFilter()
147     {
148         currentFilter = currentFilter.getParent();
149     }
150 
151 
152     /**
153      * Add a current filter. We have two cases :
154      * - there is no previous current filter : the filter
155      * is the top level filter
156      * - there is a previous current filter : the filter is added
157      * to the currentFilter set, and the current filter is changed
158      *
159      * In any case, the previous current filter will always be a
160      * ConnectorFilter when this method is called.
161      *
162      * @param localFilter The filter to set.
163      */
164     public void addCurrentFilter( Filter localFilter ) throws DecoderException
165     {
166         if ( currentFilter != null )
167         {
168             // Ok, we have a parent. The new Filter will be added to
169             // this parent, and will become the currentFilter if it's a connector.
170             ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
171             localFilter.setParent( currentFilter );
172 
173             if ( localFilter instanceof ConnectorFilter )
174             {
175                 currentFilter = localFilter;
176             }
177         }
178         else
179         {
180             // No parent. This Filter will become the root.
181             currentFilter = localFilter;
182             currentFilter.setParent( null );
183             topFilter = localFilter;
184         }
185     }
186 
187 
188     /**
189      * Transform the Filter part of a SearchRequest to an ExprNode
190      *
191      * @param filter The filter to be transformed
192      * @return An ExprNode
193      */
194     @SuppressWarnings(
195         { "unchecked", "rawtypes" })
196     private ExprNode transform( Filter filter )
197     {
198         if ( filter != null )
199         {
200             // Transform OR, AND or NOT leaves
201             if ( filter instanceof ConnectorFilter )
202             {
203                 BranchNode branch = null;
204 
205                 if ( filter instanceof AndFilter )
206                 {
207                     branch = new AndNode();
208                 }
209                 else if ( filter instanceof OrFilter )
210                 {
211                     branch = new OrNode();
212                 }
213                 else if ( filter instanceof NotFilter )
214                 {
215                     branch = new NotNode();
216                 }
217 
218                 List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet();
219 
220                 // Loop on all AND/OR children
221                 if ( filtersSet != null )
222                 {
223                     for ( Filter node : filtersSet )
224                     {
225                         branch.addNode( transform( node ) );
226                     }
227                 }
228 
229                 return branch;
230             }
231             else
232             {
233                 // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION
234                 LeafNode branch = null;
235 
236                 if ( filter instanceof PresentFilter )
237                 {
238                     branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() );
239                 }
240                 else if ( filter instanceof AttributeValueAssertionFilter )
241                 {
242                     AttributeValueAssertion ava = ( ( AttributeValueAssertionFilter ) filter ).getAssertion();
243 
244                     // Transform =, >=, <=, ~= filters
245                     switch ( ( ( AttributeValueAssertionFilter ) filter ).getFilterType() )
246                     {
247                         case LdapConstants.EQUALITY_MATCH_FILTER:
248                             branch = new EqualityNode( ava.getAttributeDesc(), ava.getAssertionValue() );
249 
250                             break;
251 
252                         case LdapConstants.GREATER_OR_EQUAL_FILTER:
253                             branch = new GreaterEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
254 
255                             break;
256 
257                         case LdapConstants.LESS_OR_EQUAL_FILTER:
258                             branch = new LessEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
259 
260                             break;
261 
262                         case LdapConstants.APPROX_MATCH_FILTER:
263                             branch = new ApproximateNode( ava.getAttributeDesc(), ava.getAssertionValue() );
264 
265                             break;
266                     }
267 
268                 }
269                 else if ( filter instanceof SubstringFilter )
270                 {
271                     // Transform Substring filters
272                     SubstringFilter substrFilter = ( SubstringFilter ) filter;
273                     String initialString = null;
274                     String finalString = null;
275                     List<String> anyString = null;
276 
277                     if ( substrFilter.getInitialSubstrings() != null )
278                     {
279                         initialString = substrFilter.getInitialSubstrings();
280                     }
281 
282                     if ( substrFilter.getFinalSubstrings() != null )
283                     {
284                         finalString = substrFilter.getFinalSubstrings();
285                     }
286 
287                     if ( substrFilter.getAnySubstrings() != null )
288                     {
289                         anyString = new ArrayList<String>();
290 
291                         for ( String any : substrFilter.getAnySubstrings() )
292                         {
293                             anyString.add( any );
294                         }
295                     }
296 
297                     branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString );
298                 }
299                 else if ( filter instanceof ExtensibleMatchFilter )
300                 {
301                     // Transform Extensible Match Filter
302                     ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter;
303                     String matchingRule = null;
304 
305                     Value<?> value = extFilter.getMatchValue();
306 
307                     if ( extFilter.getMatchingRule() != null )
308                     {
309                         matchingRule = extFilter.getMatchingRule();
310                     }
311 
312                     branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() );
313                 }
314 
315                 return branch;
316             }
317         }
318         else
319         {
320             // We have found nothing to transform. Return null then.
321             return null;
322         }
323     }
324 
325 
326     /**
327      * {@inheritDoc}
328      */
329     public MessageTypeEnum getType()
330     {
331         return getDecorated().getType();
332     }
333 
334 
335     /**
336      * {@inheritDoc}
337      */
338     public Element toDsml( Element root )
339     {
340         Element element = super.toDsml( root );
341 
342         SearchRequest request = getDecorated();
343 
344         // Dn
345         if ( request.getBase() != null )
346         {
347             element.addAttribute( "dn", request.getBase().getName() );
348         }
349 
350         // Scope
351         SearchScope scope = request.getScope();
352         if ( scope != null )
353         {
354             if ( scope == SearchScope.OBJECT )
355             {
356                 element.addAttribute( "scope", "baseObject" );
357             }
358             else if ( scope == SearchScope.ONELEVEL )
359             {
360                 element.addAttribute( "scope", "singleLevel" );
361             }
362             else if ( scope == SearchScope.SUBTREE )
363             {
364                 element.addAttribute( "scope", "wholeSubtree" );
365             }
366         }
367 
368         // DerefAliases
369         AliasDerefMode derefAliases = request.getDerefAliases();
370 
371         switch ( derefAliases )
372         {
373             case NEVER_DEREF_ALIASES:
374                 element.addAttribute( "derefAliases", "neverDerefAliases" );
375                 break;
376 
377             case DEREF_ALWAYS:
378                 element.addAttribute( "derefAliases", "derefAlways" );
379                 break;
380 
381             case DEREF_FINDING_BASE_OBJ:
382                 element.addAttribute( "derefAliases", "derefFindingBaseObj" );
383                 break;
384 
385             case DEREF_IN_SEARCHING:
386                 element.addAttribute( "derefAliases", "derefInSearching" );
387                 break;
388 
389             default:
390                 throw new IllegalStateException( "Unexpected deref alias mode " + derefAliases );
391         }
392 
393         // SizeLimit
394         if ( request.getSizeLimit() != 0L )
395         {
396             element.addAttribute( "sizeLimit", "" + request.getSizeLimit() );
397         }
398 
399         // TimeLimit
400         if ( request.getTimeLimit() != 0 )
401         {
402             element.addAttribute( "timeLimit", "" + request.getTimeLimit() );
403         }
404 
405         // TypesOnly
406         if ( request.getTypesOnly() )
407         {
408             element.addAttribute( "typesOnly", "true" );
409         }
410 
411         // Filter
412         Element filterElement = element.addElement( "filter" );
413         toDsml( filterElement, request.getFilter() );
414 
415         // Attributes
416         List<String> attributes = request.getAttributes();
417 
418         if ( attributes.size() > 0 )
419         {
420             Element attributesElement = element.addElement( "attributes" );
421 
422             for ( String entryAttribute : attributes )
423             {
424                 attributesElement.addElement( "attribute" ).addAttribute( "name", entryAttribute );
425             }
426         }
427 
428         return element;
429     }
430 
431 
432     /**
433      * Recursively converts the filter of the Search Request into a DSML representation and adds 
434      * it to the XML Element corresponding to the Search Request
435      *
436      * @param element
437      *      the parent Element
438      * @param filter
439      *      the filter to convert
440      */
441     private void toDsml( Element element, ExprNode filter )
442     {
443         // AND FILTER
444         if ( filter instanceof AndNode )
445         {
446             Element newElement = element.addElement( "and" );
447 
448             List<ExprNode> filterList = ( ( AndNode ) filter ).getChildren();
449 
450             for ( int i = 0; i < filterList.size(); i++ )
451             {
452                 toDsml( newElement, filterList.get( i ) );
453             }
454         }
455 
456         // OR FILTER
457         else if ( filter instanceof OrNode )
458         {
459             Element newElement = element.addElement( "or" );
460 
461             List<ExprNode> filterList = ( ( OrNode ) filter ).getChildren();
462 
463             for ( int i = 0; i < filterList.size(); i++ )
464             {
465                 toDsml( newElement, filterList.get( i ) );
466             }
467         }
468 
469         // NOT FILTER
470         else if ( filter instanceof NotNode )
471         {
472             Element newElement = element.addElement( "not" );
473 
474             toDsml( newElement, ( ( NotNode ) filter ).getFirstChild() );
475         }
476 
477         // SUBSTRING FILTER
478         else if ( filter instanceof SubstringNode )
479         {
480             Element newElement = element.addElement( "substrings" );
481 
482             SubstringNode substringFilter = ( SubstringNode ) filter;
483 
484             newElement.addAttribute( "name", substringFilter.getAttribute() );
485 
486             String initial = substringFilter.getInitial();
487 
488             if ( ( initial != null ) && ( !"".equals( initial ) ) )
489             {
490                 newElement.addElement( "initial" ).setText( initial );
491             }
492 
493             List<String> anyList = substringFilter.getAny();
494 
495             for ( int i = 0; i < anyList.size(); i++ )
496             {
497                 newElement.addElement( "any" ).setText( anyList.get( i ) );
498             }
499 
500             String finalString = substringFilter.getFinal();
501 
502             if ( ( finalString != null ) && ( !"".equals( finalString ) ) )
503             {
504                 newElement.addElement( "final" ).setText( finalString );
505             }
506         }
507 
508         // APPROXMATCH, EQUALITYMATCH, GREATEROREQUALS & LESSOREQUAL FILTERS
509         else if ( filter instanceof SimpleNode )
510         {
511             Element newElement = null;
512 
513             if ( filter instanceof ApproximateNode )
514             {
515                 newElement = element.addElement( "approxMatch" );
516             }
517             else if ( filter instanceof EqualityNode )
518             {
519                 newElement = element.addElement( "equalityMatch" );
520             }
521             else if ( filter instanceof GreaterEqNode )
522             {
523                 newElement = element.addElement( "greaterOrEqual" );
524             }
525             else if ( filter instanceof LessEqNode )
526             {
527                 newElement = element.addElement( "lessOrEqual" );
528             }
529 
530             String attributeName = ( ( SimpleNode<?> ) filter ).getAttribute();
531             newElement.addAttribute( "name", attributeName );
532 
533             Value<?> value = ( ( SimpleNode<?> ) filter ).getValue();
534             if ( value != null )
535             {
536                 if ( ParserUtils.needsBase64Encoding( value ) )
537                 {
538                     Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
539                     Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
540                     element.getDocument().getRootElement().add( xsdNamespace );
541                     element.getDocument().getRootElement().add( xsiNamespace );
542 
543                     Element valueElement = newElement.addElement( "value" ).addText(
544                         ParserUtils.base64Encode( value ) );
545                     valueElement
546                         .addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
547                 }
548                 else
549                 {
550                     newElement.addElement( "value" ).setText( value.getString() );
551                 }
552             }
553         }
554 
555         // PRESENT FILTER
556         else if ( filter instanceof PresenceNode )
557         {
558             Element newElement = element.addElement( "present" );
559 
560             newElement.addAttribute( "name", ( ( PresenceNode ) filter ).getAttribute() );
561         }
562 
563         // EXTENSIBLEMATCH
564         else if ( filter instanceof ExtensibleNode )
565         {
566             Element newElement = element.addElement( "extensibleMatch" );
567 
568             Value<?> value = ( ( ExtensibleNode ) filter ).getValue();
569             if ( value != null )
570             {
571                 if ( ParserUtils.needsBase64Encoding( value ) )
572                 {
573                     Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
574                     Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
575                     element.getDocument().getRootElement().add( xsdNamespace );
576                     element.getDocument().getRootElement().add( xsiNamespace );
577 
578                     Element valueElement = newElement.addElement( "value" ).addText(
579                         ParserUtils.base64Encode( value.getValue() ) );
580                     valueElement.addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
581                 }
582                 else
583                 {
584                     newElement.addElement( "value" ).setText( value.getString() );
585                 }
586             }
587 
588             if ( ( ( ExtensibleNode ) filter ).hasDnAttributes() )
589             {
590                 newElement.addAttribute( "dnAttributes", "true" );
591             }
592 
593             String matchingRule = ( ( ExtensibleNode ) filter ).getMatchingRuleId();
594             if ( ( matchingRule != null ) && ( "".equals( matchingRule ) ) )
595             {
596                 newElement.addAttribute( "matchingRule", matchingRule );
597             }
598         }
599     }
600 
601 
602     /**
603      * {@inheritDoc}
604      */
605     public MessageTypeEnum[] getResponseTypes()
606     {
607         return getDecorated().getResponseTypes();
608     }
609 
610 
611     /**
612      * {@inheritDoc}
613      */
614     public Dn getBase()
615     {
616         return getDecorated().getBase();
617     }
618 
619 
620     /**
621      * {@inheritDoc}
622      */
623     public SearchRequest setBase( Dn baseDn )
624     {
625         getDecorated().setBase( baseDn );
626 
627         return this;
628     }
629 
630 
631     /**
632      * {@inheritDoc}
633      */
634     public SearchScope getScope()
635     {
636         return getDecorated().getScope();
637     }
638 
639 
640     /**
641      * {@inheritDoc}
642      */
643     public SearchRequest setScope( SearchScope scope )
644     {
645         getDecorated().setScope( scope );
646 
647         return this;
648     }
649 
650 
651     /**
652      * {@inheritDoc}
653      */
654     public AliasDerefMode getDerefAliases()
655     {
656         return getDecorated().getDerefAliases();
657     }
658 
659 
660     /**
661      * {@inheritDoc}
662      */
663     public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
664     {
665         getDecorated().setDerefAliases( aliasDerefAliases );
666 
667         return this;
668     }
669 
670 
671     /**
672      * {@inheritDoc}
673      */
674     public long getSizeLimit()
675     {
676         return getDecorated().getSizeLimit();
677     }
678 
679 
680     /**
681      * {@inheritDoc}
682      */
683     public SearchRequest setSizeLimit( long entriesMax )
684     {
685         getDecorated().setSizeLimit( entriesMax );
686 
687         return this;
688     }
689 
690 
691     /**
692      * {@inheritDoc}
693      */
694     public int getTimeLimit()
695     {
696         return getDecorated().getTimeLimit();
697     }
698 
699 
700     /**
701      * {@inheritDoc}
702      */
703     public SearchRequest setTimeLimit( int secondsMax )
704     {
705         getDecorated().setTimeLimit( secondsMax );
706 
707         return this;
708     }
709 
710 
711     /**
712      * {@inheritDoc}
713      */
714     public boolean getTypesOnly()
715     {
716         return getDecorated().getTypesOnly();
717     }
718 
719 
720     /**
721      * {@inheritDoc}
722      */
723     public SearchRequest setTypesOnly( boolean typesOnly )
724     {
725         getDecorated().setTypesOnly( typesOnly );
726 
727         return this;
728     }
729 
730 
731     /**
732      * {@inheritDoc}
733      */
734     public ExprNode getFilter()
735     {
736         return getDecorated().getFilter();
737     }
738 
739 
740     /**
741      * {@inheritDoc}
742      */
743     public SearchRequest setFilter( ExprNode filter )
744     {
745         getDecorated().setFilter( filter );
746 
747         return this;
748     }
749 
750 
751     /**
752      * {@inheritDoc}
753      */
754     public SearchRequest setFilter( String filter ) throws LdapException
755     {
756         getDecorated().setFilter( filter );
757 
758         return this;
759     }
760 
761 
762     /**
763      * {@inheritDoc}
764      */
765     public List<String> getAttributes()
766     {
767         return getDecorated().getAttributes();
768     }
769 
770 
771     /**
772      * {@inheritDoc}
773      */
774     public SearchRequest addAttributes( String... attributes )
775     {
776         getDecorated().addAttributes( attributes );
777 
778         return this;
779     }
780 
781 
782     /**
783      * {@inheritDoc}
784      */
785     public SearchRequest removeAttribute( String attribute )
786     {
787         getDecorated().removeAttribute( attribute );
788 
789         return this;
790     }
791 
792 
793     /**
794      * {@inheritDoc}
795      */
796     public SearchRequest setMessageId( int messageId )
797     {
798         return ( SearchRequest ) super.setMessageId( messageId );
799     }
800 
801 
802     /**
803      * {@inheritDoc}
804      */
805     public SearchRequest addControl( Control control )
806     {
807         return ( SearchRequest ) super.addControl( control );
808     }
809 
810 
811     /**
812      * {@inheritDoc}
813      */
814     public SearchRequest addAllControls( Control[] controls )
815     {
816         return ( SearchRequest ) super.addAllControls( controls );
817     }
818 
819 
820     /**
821      * {@inheritDoc}
822      */
823     public SearchRequest removeControl( Control control )
824     {
825         return ( SearchRequest ) super.removeControl( control );
826     }
827     
828     
829     /**
830      * {@inheritDoc}
831      */
832     public boolean isFollowReferrals()
833     {
834         return getDecorated().isFollowReferrals();
835     }
836 
837 
838     /**
839      * {@inheritDoc}
840      */
841     public SearchRequest followReferrals()
842     {
843         return getDecorated().followReferrals();
844     }
845     
846     
847     /**
848      * {@inheritDoc}
849      */
850     public boolean isIgnoreReferrals()
851     {
852         return getDecorated().isIgnoreReferrals();
853     }
854 
855 
856     /**
857      * {@inheritDoc}
858      */
859     public SearchRequest ignoreReferrals()
860     {
861         return getDecorated().ignoreReferrals();
862     }
863 }