001/*
002 * (C) Copyright 2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 */
017
018package org.nuxeo.ecm.directory.ldap.filter;
019
020import java.util.regex.Matcher;
021import java.util.regex.Pattern;
022
023/**
024 * This class is used to apply corrections to a filter expression. It is mainly used for filters that come from an
025 * Active Directory.
026 * <p>
027 * You can apply the corrections you want, in the desired order. The available jobs are listed in the enum FilterJobs.
028 * <p>
029 * Example: <code>FilterExpressionCorrector.correctFilter(filterValue,
030                            FilterJobs.JOB1, FilterJobs.JOB2);</code>
031 *
032 * @author Nicolas Ulrich <nulrich@nuxeo.com>
033 */
034public class FilterExpressionCorrector {
035
036    /**
037     * Enumeration of the available jobs
038     */
039    public enum FilterJobs {
040
041        CORRECT_NOT(notJob);
042
043        private final ICorrectorJob job;
044
045        FilterJobs(final ICorrectorJob job) {
046            this.job = job;
047        }
048
049        protected String run(final String filter) {
050            return job.run(filter);
051        }
052    }
053
054    /**
055     * A Job interface
056     */
057    interface ICorrectorJob {
058        String run(final String filter);
059    }
060
061    /**
062     * This job finds "!expression" and replaces it by "!(expression)"
063     */
064    private static final ICorrectorJob notJob = new ICorrectorJob() {
065
066        public String run(final String filter) {
067
068            final StringBuffer newString = new StringBuffer();
069
070            // Find 'not' without parenthesis
071            final Pattern pattern = Pattern.compile("![^(][^\\)]+[)]");
072            final Matcher matcher = pattern.matcher(filter);
073
074            // Find all the matches.
075            while (matcher.find()) {
076
077                // Add parenthesis
078                final StringBuffer res = new StringBuffer(matcher.group());
079                res.insert(1, '(').append(')');
080
081                // Replace
082                matcher.appendReplacement(newString, res.toString());
083            }
084
085            matcher.appendTail(newString);
086
087            return newString.toString();
088
089        }
090
091    };
092
093    /**
094     * Apply the chosen Correctors to the filter expression
095     *
096     * @param filterExpression The filter expression to correct
097     * @param jobs List of the jobs you want to apply.
098     */
099    public static String correctFilter(final String filterExpression, final FilterJobs... jobs) {
100
101        String result = filterExpression;
102
103        for (FilterJobs job : jobs) {
104            result = job.run(result);
105        }
106
107        return result;
108    }
109
110}