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 *    https://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.actions.request.search;
021
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.apache.directory.api.asn1.DecoderException;
027import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
028import org.apache.directory.api.i18n.I18n;
029import org.apache.directory.api.ldap.codec.AttributeValueAssertion;
030import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
031import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
032import org.apache.directory.api.ldap.codec.search.AndFilter;
033import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
034import org.apache.directory.api.ldap.codec.search.ConnectorFilter;
035import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
036import org.apache.directory.api.ldap.codec.search.Filter;
037import org.apache.directory.api.ldap.codec.search.OrFilter;
038import org.apache.directory.api.ldap.codec.search.PresentFilter;
039import org.apache.directory.api.ldap.codec.search.SubstringFilter;
040import org.apache.directory.api.ldap.model.entry.Value;
041import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
042import org.apache.directory.api.ldap.model.filter.AndNode;
043import org.apache.directory.api.ldap.model.filter.ApproximateNode;
044import org.apache.directory.api.ldap.model.filter.BranchNode;
045import org.apache.directory.api.ldap.model.filter.EqualityNode;
046import org.apache.directory.api.ldap.model.filter.ExprNode;
047import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
048import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
049import org.apache.directory.api.ldap.model.filter.LeafNode;
050import org.apache.directory.api.ldap.model.filter.LessEqNode;
051import org.apache.directory.api.ldap.model.filter.NotNode;
052import org.apache.directory.api.ldap.model.filter.OrNode;
053import org.apache.directory.api.ldap.model.filter.PresenceNode;
054import org.apache.directory.api.ldap.model.filter.SubstringNode;
055import org.apache.directory.api.ldap.model.message.SearchRequest;
056import org.slf4j.Logger;
057import org.slf4j.LoggerFactory;
058
059
060/**
061 * The action used to initialize the AttributeDesc list
062 * <pre>
063 * SearchRequest ::= [APPLICATION 3] SEQUENCE {
064 *     ...
065 *     filter      Filter,
066 *     attributes  AttributeDescriptionList }
067 *
068 * AttributeDescriptionList ::= SEQUENCE OF
069 *     AttributeDescription
070 * </pre>
071 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
072 */
073public class InitSearchRequestAttributeDescList extends GrammarAction<LdapMessageContainer<SearchRequest>>
074{
075    /** The logger */
076    private static final Logger LOG = LoggerFactory.getLogger( InitSearchRequestAttributeDescList.class );
077
078    /**
079     * Instantiates a new init attribute desc list action.
080     */
081    public InitSearchRequestAttributeDescList()
082    {
083        super( "Initialize AttributeDesc list" );
084    }
085
086
087    /**
088     * Transform the Filter part of a SearchRequest to an ExprNode
089     *
090     * @param filter The filter to be transformed
091     * @return An ExprNode
092     * @throws LdapSchemaException If teh filter is invalid
093     */
094    private ExprNode transform( Filter filter ) throws LdapSchemaException
095    {
096        if ( filter != null )
097        {
098            // Transform OR, AND or NOT leaves
099            if ( filter instanceof ConnectorFilter )
100            {
101                BranchNode branch;
102
103                if ( filter instanceof AndFilter )
104                {
105                    branch = new AndNode();
106                }
107                else if ( filter instanceof OrFilter )
108                {
109                    branch = new OrNode();
110                }
111                else
112                {
113                    branch = new NotNode();
114                }
115
116                List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet();
117
118                // Loop on all AND/OR children
119                if ( filtersSet != null )
120                {
121                    for ( Filter node : filtersSet )
122                    {
123                        branch.addNode( transform( node ) );
124                    }
125                }
126
127                return branch;
128            }
129            else
130            {
131                // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION
132                LeafNode branch = null;
133
134                if ( filter instanceof PresentFilter )
135                {
136                    branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() );
137                }
138                else if ( filter instanceof AttributeValueAssertionFilter )
139                {
140                    AttributeValueAssertion ava = ( ( AttributeValueAssertionFilter ) filter ).getAssertion();
141
142                    // Transform =, >=, <=, ~= filters
143                    int filterType = ( ( AttributeValueAssertionFilter ) filter ).getFilterType();
144                    
145                    switch ( filterType )
146                    {
147                        case LdapCodecConstants.EQUALITY_MATCH_FILTER:
148                            branch = new EqualityNode( ava.getAttributeDesc(), ava.getAssertion() );
149                            break;
150
151                        case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
152                            branch = new GreaterEqNode( ava.getAttributeDesc(), ava.getAssertion() );
153                            break;
154
155                        case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
156                            branch = new LessEqNode( ava.getAttributeDesc(), ava.getAssertion() );
157                            break;
158
159                        case LdapCodecConstants.APPROX_MATCH_FILTER:
160                            branch = new ApproximateNode( ava.getAttributeDesc(), ava.getAssertion() );
161                            break;
162
163                        default:
164                            throw new IllegalArgumentException( I18n.err( I18n.ERR_05503_UNEXPECTED_FILTER_TYPE, filterType ) );
165                    }
166
167                }
168                else if ( filter instanceof SubstringFilter )
169                {
170                    // Transform Substring filters
171                    SubstringFilter substrFilter = ( SubstringFilter ) filter;
172                    String initialString = null;
173                    String finalString = null;
174                    List<String> anyString = null;
175
176                    if ( substrFilter.getInitialSubstrings() != null )
177                    {
178                        initialString = substrFilter.getInitialSubstrings();
179                    }
180
181                    if ( substrFilter.getFinalSubstrings() != null )
182                    {
183                        finalString = substrFilter.getFinalSubstrings();
184                    }
185
186                    if ( substrFilter.getAnySubstrings() != null )
187                    {
188                        anyString = new ArrayList<>();
189
190                        for ( String any : substrFilter.getAnySubstrings() )
191                        {
192                            anyString.add( any );
193                        }
194                    }
195
196                    branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString );
197                }
198                else if ( filter instanceof ExtensibleMatchFilter )
199                {
200                    // Transform Extensible Match Filter
201                    ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter;
202                    String matchingRule = null;
203
204                    Value value = extFilter.getMatchValue();
205
206                    if ( extFilter.getMatchingRule() != null )
207                    {
208                        matchingRule = extFilter.getMatchingRule();
209                    }
210
211                    branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() );
212                }
213
214                return branch;
215            }
216        }
217        else
218        {
219            // We have found nothing to transform. Return null then.
220            return null;
221        }
222    }
223
224
225    /**
226     * {@inheritDoc}
227     */
228    public void action( LdapMessageContainer<SearchRequest> container ) throws DecoderException
229    {
230        // Here, we have to inject the decoded filter into the SearchRequest
231        SearchRequest searchRequest = container.getMessage();
232
233        try
234        {
235            searchRequest.setFilter( transform( container.getTopFilter() ) );
236        }
237        catch ( LdapSchemaException lse )
238        {
239            throw new DecoderException( lse.getMessage(), lse ); 
240        }
241
242        // We can have an END transition
243        container.setGrammarEndAllowed( true );
244
245        if ( LOG.isDebugEnabled() )
246        {
247            LOG.debug( I18n.msg( I18n.MSG_05158_INITIALIZE_ATT_DESC_LIST ) );
248        }
249    }
250}