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