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        public String run(final String filter) {
069
070            final StringBuffer newString = new StringBuffer();
071
072            // Find 'not' without parenthesis
073            final Pattern pattern = Pattern.compile("![^(][^\\)]+[)]");
074            final Matcher matcher = pattern.matcher(filter);
075
076            // Find all the matches.
077            while (matcher.find()) {
078
079                // Add parenthesis
080                final StringBuffer res = new StringBuffer(matcher.group());
081                res.insert(1, '(').append(')');
082
083                // Replace
084                matcher.appendReplacement(newString, res.toString());
085            }
086
087            matcher.appendTail(newString);
088
089            return newString.toString();
090
091        }
092
093    };
094
095    /**
096     * Apply the chosen Correctors to the filter expression
097     *
098     * @param filterExpression The filter expression to correct
099     * @param jobs List of the jobs you want to apply.
100     */
101    public static String correctFilter(final String filterExpression, final FilterJobs... jobs) {
102
103        String result = filterExpression;
104
105        for (FilterJobs job : jobs) {
106            result = job.run(result);
107        }
108
109        return result;
110    }
111
112}