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     */
020    package org.apache.directory.shared.ldap.filter;
021    
022    
023    import java.util.ArrayList;
024    import java.util.List;
025    import java.util.regex.Pattern;
026    
027    import org.apache.directory.shared.ldap.entry.StringValue;
028    import org.apache.directory.shared.ldap.exception.LdapException;
029    import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
030    import org.apache.directory.shared.ldap.schema.Normalizer;
031    import org.apache.directory.shared.ldap.util.StringTools;
032    
033    
034    /**
035     * Filter expression tree node used to represent a substring assertion.
036     * 
037     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038     * @version $Revision: 928945 $
039     */
040    public class SubstringNode extends LeafNode
041    {
042        /** The initial fragment before any wildcard */
043        private String initialPattern;
044    
045        /** The end fragment after wildcard */
046        private String finalPattern;
047    
048        /** List of fragments between wildcard */
049        private List<String> anyPattern;
050    
051        /**
052         * Creates a new SubstringNode object with only one wildcard and no internal
053         * any fragments between wildcards.
054         * 
055         * @param attribute the name of the attribute to substring assert
056         * @param initialPattern the initial fragment
057         * @param finalPattern the final fragment
058         */
059        public SubstringNode( String attribute, String initialPattern, String finalPattern )
060        {
061            super( attribute, AssertionType.SUBSTRING );
062    
063            anyPattern = new ArrayList<String>( 2 );
064            this.finalPattern = finalPattern;
065            this.initialPattern = initialPattern;
066        }
067    
068        
069        /**
070         * Clone the Node
071         */
072        @Override public ExprNode clone()
073        {
074            ExprNode clone = (ExprNode)super.clone();
075            
076            if ( anyPattern != null )
077            {
078                ((SubstringNode)clone).anyPattern = new ArrayList<String>();
079                
080                for ( String any:anyPattern )
081                {
082                    ((SubstringNode)clone).anyPattern.add( any );
083                }
084            }
085            
086            return clone;
087        }
088    
089        /**
090         * Creates a new SubstringNode object without any value
091         * 
092         * @param attribute the name of the attribute to substring assert
093         */
094        public SubstringNode( String attribute )
095        {
096            super( attribute, AssertionType.SUBSTRING );
097    
098            anyPattern = new ArrayList<String>( 2 );
099            this.finalPattern = null;
100            this.initialPattern = null;
101        }
102    
103    
104        /**
105         * Creates a new SubstringNode object more than one wildcard and an any
106         * list.
107         * 
108         * @param anyPattern list of internal fragments between wildcards
109         * @param attribute the name of the attribute to substring assert
110         * @param initialPattern the initial fragment
111         * @param finalPattern the final fragment
112         */
113        public SubstringNode( List<String> anyPattern, String attribute, String initialPattern, String finalPattern )
114        {
115            super( attribute, AssertionType.SUBSTRING );
116    
117            this.anyPattern = anyPattern;
118            this.finalPattern = finalPattern;
119            this.initialPattern = initialPattern;
120        }
121    
122    
123        /**
124         * Gets the initial fragment.
125         * 
126         * @return the initial prefix
127         */
128        public final String getInitial()
129        {
130            return initialPattern;
131        }
132        
133        /**
134         * Set the initial pattern
135         * @param initialPattern The initial pattern
136         */
137        public void setInitial( String initialPattern ) 
138        {
139            this.initialPattern = initialPattern;
140        }
141    
142        /**
143         * Gets the final fragment or suffix.
144         * 
145         * @return the suffix
146         */
147        public final String getFinal()
148        {
149            return finalPattern;
150        }
151    
152    
153        /**
154         * Set the final pattern
155         * @param finalPattern The final pattern
156         */
157        public void setFinal( String finalPattern ) 
158        {
159            this.finalPattern = finalPattern;
160        }
161    
162    
163        /**
164         * Gets the list of wildcard surrounded any fragments.
165         * 
166         * @return the any fragments
167         */
168        public final List<String> getAny()
169        {
170            return anyPattern;
171        }
172    
173    
174        /**
175         * Set the any patterns
176         * @param anyPattern The any patterns
177         */
178        public void setAny( List<String> anyPattern ) 
179        {
180            this.anyPattern = anyPattern;
181        }
182    
183    
184        /**
185         * Add an any pattern
186         * @param anyPattern The any pattern
187         */
188        public void addAny( String anyPattern ) 
189        {
190            this.anyPattern.add( anyPattern );
191        }
192    
193    
194        /**
195         * Gets the compiled regular expression for the substring expression.
196         * 
197         * @param normalizer the normalizer to use for pattern component normalization
198         * @return the equivalent compiled regular expression
199         * @throws LdapInvalidDnException if there are problems while normalizing
200         */
201        public final Pattern getRegex( Normalizer normalizer ) throws LdapException
202        {
203            boolean isBinary = false;
204            
205            if ( ( anyPattern != null ) && ( anyPattern.size() > 0 ) )
206            {
207                String[] any = new String[anyPattern.size()];
208    
209                for ( int i = 0; i < any.length; i++ )
210                {
211                    any[i] = ( String ) normalizer.normalize( anyPattern.get( i ) );
212                    
213                    if ( any[i].length() == 0 )
214                    {
215                        any[i] = " ";
216                    }
217                }
218    
219                String initialStr = null;
220    
221                if ( initialPattern != null )
222                {
223                    initialStr = ( String ) normalizer.normalize( initialPattern );
224                }
225    
226                String finalStr = null;
227    
228                if ( finalPattern != null )
229                {
230                    finalStr = ( String ) normalizer.normalize( finalPattern );
231                }
232    
233                return StringTools.getRegex( initialStr, any, finalStr );
234            }
235    
236            String initialStr = null;
237    
238            if ( initialPattern != null )
239            {
240                initialStr = ( String ) normalizer.normalize( initialPattern );
241            }
242    
243            String finalStr = null;
244    
245            if ( finalPattern != null )
246            {
247                finalStr = ( String ) normalizer.normalize( finalPattern );
248            }
249    
250            return StringTools.getRegex( initialStr, null, finalStr );
251        }
252    
253    
254        /**
255         * @see Object#hashCode()
256         * @return the instance's hash code 
257         */
258        public int hashCode()
259        {
260            int h = 37;
261            
262            h = h*17 + super.hashCode();
263            h = h*17 + ( initialPattern != null ? initialPattern.hashCode() : 0 );
264            
265            if ( anyPattern != null )
266            {
267                for ( String pattern:anyPattern )
268                {
269                    h = h*17 + pattern.hashCode();
270                }
271            }
272            
273            h = h*17 + ( finalPattern != null ? finalPattern.hashCode() : 0 );
274            
275            return h;
276        }
277    
278    
279        /**
280         * @see java.lang.Object#toString()
281         * @return A string representing the AndNode
282         */
283        public String toString()
284        {
285            StringBuilder buf = new StringBuilder();
286            
287            buf.append( '(' ).append( getAttribute() ).append( '=' );
288    
289            if ( null != initialPattern )
290            {
291                buf.append( AbstractExprNode.escapeFilterValue( new StringValue( initialPattern ) ) ).append( '*' );
292            }
293            else
294            {
295                buf.append( '*' );
296            }
297    
298            if ( null != anyPattern )
299            {
300                for ( String any:anyPattern )
301                {
302                    buf.append( AbstractExprNode.escapeFilterValue( new StringValue( any ) ) );
303                    buf.append( '*' );
304                }
305            }
306    
307            if ( null != finalPattern )
308            {
309                buf.append( AbstractExprNode.escapeFilterValue( new StringValue( finalPattern ) ) );
310            }
311    
312            buf.append( super.toString() );
313            
314            buf.append( ')' );
315            
316            return buf.toString();
317        }
318    }