All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mycila.event.internal.TopicsMatcher Maven / Gradle / Ivy

/**
 * Copyright (C) 2010 Mycila ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mycila.event.internal;

import com.mycila.event.Topic;
import com.mycila.event.Topics;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;

import static com.mycila.event.internal.Ensure.notNull;

public final class TopicsMatcher extends Topics implements Serializable {

    private static final long serialVersionUID = 0;
    private static final String DEFAULT_PATH_SEPARATOR = "/";
    private final String pattern;

    private TopicsMatcher(String pattern) {
        this.pattern = notNull(pattern, "Pattern");
    }

    public boolean matches(Topic target) {
        return doMatch(pattern, notNull(target, "Topic").getName(), true);
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof TopicsMatcher
                && ((TopicsMatcher) o).pattern.equals(pattern);
    }

    @Override
    public int hashCode() {
        return 31 * pattern.hashCode();
    }

    @Override
    public String toString() {
        return pattern;
    }

    public static Topics forPattern(String pattern) {
        return new TopicsMatcher(pattern);
    }

    private static boolean doMatch(String pattern, String path, boolean fullMatch) {
        if (path.startsWith(DEFAULT_PATH_SEPARATOR) != pattern.startsWith(DEFAULT_PATH_SEPARATOR))
            return false;
        String[] pattDirs = tokenizeToStringArray(pattern, DEFAULT_PATH_SEPARATOR);
        String[] pathDirs = tokenizeToStringArray(path, DEFAULT_PATH_SEPARATOR);
        int pattIdxStart = 0;
        int pattIdxEnd = pattDirs.length - 1;
        int pathIdxStart = 0;
        int pathIdxEnd = pathDirs.length - 1;
        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
            String patDir = pattDirs[pattIdxStart];
            if ("**".equals(patDir))
                break;
            if (!matchStrings(patDir, pathDirs[pathIdxStart]))
                return false;
            pattIdxStart++;
            pathIdxStart++;
        }
        if (pathIdxStart > pathIdxEnd) {
            if (pattIdxStart > pattIdxEnd)
                return pattern.endsWith(DEFAULT_PATH_SEPARATOR) ? path.endsWith(DEFAULT_PATH_SEPARATOR) : !path.endsWith(DEFAULT_PATH_SEPARATOR);
            if (!fullMatch)
                return true;
            if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && path.endsWith(DEFAULT_PATH_SEPARATOR))
                return true;
            for (int i = pattIdxStart; i <= pattIdxEnd; i++)
                if (!pattDirs[i].equals("**"))
                    return false;
            return true;
        } else if (pattIdxStart > pattIdxEnd)
            return false;
        else if (!fullMatch && "**".equals(pattDirs[pattIdxStart]))
            return true;
        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
            String patDir = pattDirs[pattIdxEnd];
            if (patDir.equals("**"))
                break;
            if (!matchStrings(patDir, pathDirs[pathIdxEnd]))
                return false;
            pattIdxEnd--;
            pathIdxEnd--;
        }
        if (pathIdxStart > pathIdxEnd) {
            for (int i = pattIdxStart; i <= pattIdxEnd; i++)
                if (!pattDirs[i].equals("**"))
                    return false;
            return true;
        }
        while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
            int patIdxTmp = -1;
            for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
                if (pattDirs[i].equals("**")) {
                    patIdxTmp = i;
                    break;
                }
            }
            if (patIdxTmp == pattIdxStart + 1) {
                pattIdxStart++;
                continue;
            }
            int patLength = (patIdxTmp - pattIdxStart - 1);
            int strLength = (pathIdxEnd - pathIdxStart + 1);
            int foundIdx = -1;
            strLoop:
            for (int i = 0; i <= strLength - patLength; i++) {
                for (int j = 0; j < patLength; j++) {
                    String subPat = pattDirs[pattIdxStart + j + 1];
                    String subStr = pathDirs[pathIdxStart + i + j];
                    if (!matchStrings(subPat, subStr))
                        continue strLoop;
                }
                foundIdx = pathIdxStart + i;
                break;
            }
            if (foundIdx == -1)
                return false;
            pattIdxStart = patIdxTmp;
            pathIdxStart = foundIdx + patLength;
        }
        for (int i = pattIdxStart; i <= pattIdxEnd; i++)
            if (!pattDirs[i].equals("**"))
                return false;
        return true;
    }

    private static String[] toStringArray(Collection collection) {
        if (collection == null)
            return null;
        return collection.toArray(new String[collection.size()]);
    }

    private static String[] tokenizeToStringArray(String str, String delimiters) {
        return tokenizeToStringArray(str, delimiters, true, true);
    }

    private static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
        if (str == null)
            return null;
        StringTokenizer st = new StringTokenizer(str, delimiters);
        List tokens = new ArrayList();
        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            if (trimTokens)
                token = token.trim();
            if (!ignoreEmptyTokens || token.length() > 0)
                tokens.add(token);
        }
        return toStringArray(tokens);
    }

    private static boolean matchStrings(String pattern, String str) {
        char[] patArr = pattern.toCharArray();
        char[] strArr = str.toCharArray();
        int patIdxStart = 0;
        int patIdxEnd = patArr.length - 1;
        int strIdxStart = 0;
        int strIdxEnd = strArr.length - 1;
        char ch;
        boolean containsStar = false;
        for (char aPatArr : patArr) {
            if (aPatArr == '*') {
                containsStar = true;
                break;
            }
        }
        if (!containsStar) {
            if (patIdxEnd != strIdxEnd)
                return false;
            for (int i = 0; i <= patIdxEnd; i++) {
                ch = patArr[i];
                if (ch != '?' && ch != strArr[i])
                    return false;
            }
            return true;
        }
        if (patIdxEnd == 0)
            return true;
        while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
            if (ch != '?' && ch != strArr[strIdxStart])
                return false;
            patIdxStart++;
            strIdxStart++;
        }
        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++)
                if (patArr[i] != '*')
                    return false;
            return true;
        }
        while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
            if (ch != '?' && ch != strArr[strIdxEnd])
                return false;
            patIdxEnd--;
            strIdxEnd--;
        }
        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++)
                if (patArr[i] != '*')
                    return false;
            return true;
        }
        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
            int patIdxTmp = -1;
            for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
                if (patArr[i] == '*') {
                    patIdxTmp = i;
                    break;
                }
            }
            if (patIdxTmp == patIdxStart + 1) {
                patIdxStart++;
                continue;
            }
            int patLength = (patIdxTmp - patIdxStart - 1);
            int strLength = (strIdxEnd - strIdxStart + 1);
            int foundIdx = -1;
            strLoop:
            for (int i = 0; i <= strLength - patLength; i++) {
                for (int j = 0; j < patLength; j++) {
                    ch = patArr[patIdxStart + j + 1];
                    if (ch != '?' && ch != strArr[strIdxStart + i + j])
                        continue strLoop;
                }
                foundIdx = strIdxStart + i;
                break;
            }
            if (foundIdx == -1)
                return false;
            patIdxStart = patIdxTmp;
            strIdxStart = foundIdx + patLength;
        }

        for (int i = patIdxStart; i <= patIdxEnd; i++)
            if (patArr[i] != '*')
                return false;
        return true;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy