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 */
017package org.apache.activemq.console.filter;
018
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.Iterator;
022import java.util.List;
023import java.util.Map;
024import java.util.regex.Pattern;
025
026public 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}