001/*
002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 */
019
020package org.nuxeo.ecm.directory.ldap.filter;
021
022import java.util.regex.Matcher;
023import java.util.regex.Pattern;
024
025/**
026 * This class is used to apply corrections to a filter expression. It is mainly used for filters that come from an
027 * Active Directory.
028 * <p>
029 * You can apply the corrections you want, in the desired order. The available jobs are listed in the enum FilterJobs.
030 * <p>
031 * Example: <code>FilterExpressionCorrector.correctFilter(filterValue,
032                            FilterJobs.JOB1, FilterJobs.JOB2);</code>
033 *
034 * @author Nicolas Ulrich <nulrich@nuxeo.com>
035 */
036public class FilterExpressionCorrector {
037
038    /**
039     * Enumeration of the available jobs
040     */
041    public enum FilterJobs {
042
043        CORRECT_NOT(notJob);
044
045        private final ICorrectorJob job;
046
047        FilterJobs(final ICorrectorJob job) {
048            this.job = job;
049        }
050
051        protected String run(final String filter) {
052            return job.run(filter);
053        }
054    }
055
056    /**
057     * A Job interface
058     */
059    interface ICorrectorJob {
060        String run(final String filter);
061    }
062
063    /**
064     * This job finds "!expression" and replaces it by "!(expression)"
065     */
066    private static final ICorrectorJob notJob = new ICorrectorJob() {
067
068        @Override
069        public String run(final String filter) {
070
071            final StringBuffer newString = new StringBuffer();
072
073            // Find 'not' without parenthesis
074            final Pattern pattern = Pattern.compile("![^(][^\\)]+[)]");
075            final Matcher matcher = pattern.matcher(filter);
076
077            // Find all the matches.
078            while (matcher.find()) {
079
080                // Add parenthesis
081                final StringBuffer res = new StringBuffer(matcher.group());
082                res.insert(1, '(').append(')');
083
084                // Replace
085                matcher.appendReplacement(newString, res.toString());
086            }
087
088            matcher.appendTail(newString);
089
090            return newString.toString();
091
092        }
093
094    };
095
096    /**
097     * Apply the chosen Correctors to the filter expression
098     *
099     * @param filterExpression The filter expression to correct
100     * @param jobs List of the jobs you want to apply.
101     */
102    public static String correctFilter(final String filterExpression, final FilterJobs... jobs) {
103
104        String result = filterExpression;
105
106        for (FilterJobs job : jobs) {
107            result = job.run(result);
108        }
109
110        return result;
111    }
112
113}