001/* 
002 * (C) Copyright 2006-2011 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 *     bstefanescu
018 */
019package org.nuxeo.ecm.webengine.jaxrs.servlet.mapping;
020
021/**
022 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
023 */
024public class WildcardSegmentMatcher extends SegmentMatcher {
025
026    protected final char[] pattern;
027
028    public WildcardSegmentMatcher(String pattern) {
029        this.pattern = pattern.replace("**", "*").toCharArray();
030    }
031
032    public WildcardSegmentMatcher(char[] pattern) {
033        this.pattern = pattern;
034    }
035
036    @Override
037    public boolean matches(String segment) {
038        if (pattern.length == 0) {
039            return true;
040        }
041        return matches(segment.toCharArray(), 0, 0);
042    }
043
044    public boolean matches(char[] segment, int soff, int poff) {
045        if (poff == pattern.length) {
046            // pattern consumed
047            if (soff == segment.length) {
048                // segment consumed too
049                return true;
050            }
051            // segment is not yet consumed
052            if (pattern[pattern.length - 1] == '*') {
053                // last char is a wildcard => matched
054                return true;
055            }
056            return false;
057        }
058        if (soff == segment.length) {
059            // segment consumed but pattern is not yet consumed
060            if (poff + 1 == pattern.length && pattern[poff] == '*') {
061                // there is only one char remaining and it is a wildcard => matched
062                return true;
063            }
064            return false;
065        }
066
067        if (pattern[poff] == '*') {
068            // current pattern char is a wildcard - try all substrings
069            for (int i = soff; i < segment.length; i++) {
070                if (matches(segment, i, poff + 1)) {
071                    return true;
072                }
073            }
074            return false;
075        }
076
077        // test is the current char is matching
078        if (pattern[poff] != '?' && pattern[poff] != segment[soff]) {
079            return false; // not matching
080        }
081
082        // continue iteration on segments and matchers
083        return matches(segment, soff + 1, poff + 1);
084
085    }
086
087    @Override
088    public String toString() {
089        return new String(pattern);
090    }
091}