001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.activemq.console.filter;
018    
019    import java.util.ArrayList;
020    import java.util.HashMap;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.regex.Pattern;
025    
026    public abstract class RegExQueryFilter extends AbstractQueryFilter {
027        public static final String REGEX_PREFIX = "REGEX:QUERY:";
028    
029        /**
030         * Creates a regular expression query that is able to match an object using
031         * key-value pattern regex filtering
032         * 
033         * @param next
034         */
035        protected RegExQueryFilter(QueryFilter next) {
036            super(next);
037        }
038    
039        /**
040         * Separates the regular expressions queries from the usual queries. A query
041         * is a regex query, if it is key-value pair with the format <key>=<value>,
042         * and value is a pattern that satisfies the isRegularExpression method.
043         * 
044         * @param queries - list of queries
045         * @return filtered objects that matches the regex query
046         * @throws Exception
047         */
048        public List query(List queries) throws Exception {
049            Map regex = new HashMap();
050            List newQueries = new ArrayList();
051    
052            // Lets parse for regular expression queries
053            for (Iterator i = queries.iterator(); i.hasNext();) {
054                // Get key-value pair
055                String token = (String)i.next();
056                String key = "";
057                String val = "";
058                int pos = token.indexOf("=");
059                if (pos >= 0) {
060                    val = token.substring(pos + 1);
061                    key = token.substring(0, pos);
062                }
063    
064                // Add the regex query to list and make it a non-factor in the
065                // succeeding queries
066                if (isRegularExpression(val)) {
067                    regex.put(key, compileQuery(val));
068    
069                    // Add the normal query to the query list
070                } else {
071                    newQueries.add(token);
072                }
073            }
074    
075            // Filter the result using the regular expressions specified
076            return filterCollectionUsingRegEx(regex, next.query(newQueries));
077        }
078    
079        /**
080         * Checks if a given string is a regular expression query. Currently, a
081         * pattern is a regex query, if it starts with the
082         * RegExQueryFilter.REGEX_PREFIX.
083         * 
084         * @param query
085         * @return
086         */
087        protected boolean isRegularExpression(String query) {
088            return query.startsWith(REGEX_PREFIX);
089        }
090    
091        /**
092         * Compiles the regex query to a pattern.
093         * 
094         * @param query - query string to compile
095         * @return regex pattern
096         */
097        protected Pattern compileQuery(String query) {
098            return Pattern.compile(query.substring(REGEX_PREFIX.length()));
099        }
100    
101        /**
102         * Filter the specified colleciton using the regex patterns extracted.
103         * 
104         * @param regex - regex map
105         * @param data - list of objects to filter
106         * @return filtered list of objects that matches the regex map
107         * @throws Exception
108         */
109        protected List filterCollectionUsingRegEx(Map regex, List data) throws Exception {
110            // No regular expressions filtering needed
111            if (regex == null || regex.isEmpty()) {
112                return data;
113            }
114    
115            List filteredElems = new ArrayList();
116    
117            // Get each data object to filter
118            for (Iterator i = data.iterator(); i.hasNext();) {
119                Object dataElem = i.next();
120                // If properties of data matches all the regex pattern, add it
121                if (matches(dataElem, regex)) {
122                    filteredElems.add(dataElem);
123                }
124            }
125    
126            return filteredElems;
127        }
128    
129        /**
130         * Determines how the object is to be matched to the regex map.
131         * 
132         * @param data - object to match
133         * @param regex - regex map
134         * @return true, if the object matches the regex map, false otherwise
135         * @throws Exception
136         */
137        protected abstract boolean matches(Object data, Map regex) throws Exception;
138    }