protected boolean matches(String pattern, String value) {

        char[] patArr = pattern.toCharArray();
        char[] valArr = value.toCharArray();
        int patIndex = 0;
        int patEndIndex = patArr.length - 1;
        int valIndex = 0;
        int valEndIndex = valArr.length - 1;
        char ch;

        boolean patternContainsStar = false;
        for (char patternChar : patArr) {
            if (patternChar == '*') {
                patternContainsStar = true;
                break;
            }
        }

        if (!patternContainsStar) {
            // No '*'s, so we make a shortcut
            if (patEndIndex != valEndIndex) {
                return false; // Pattern and string do not have the same size
            }
            for (int i = 0; i <= patEndIndex; i++) {
                ch = patArr[i];
                if (ch != '?') {
                    if (ch != valArr[i]) {
                        return false;// Character mismatch
                    }
                }
            }
            return true; // String matches against pattern
        }


        // Process characters before first star
        while ((ch = patArr[patIndex]) != '*' && valIndex <= valEndIndex) {
            if (ch != '?') {
                if (ch != valArr[valIndex]) {
                    return false;// Character mismatch
                }
            }
            patIndex++;
            valIndex++;
        }
        if (valIndex > valEndIndex) {
            // All characters in the value are used. Check if only '*'s remain
            // in the pattern. If so, we succeeded. Otherwise failure.
            for (int i = patIndex; i <= patEndIndex; i++) {
                if (patArr[i] != '*') {
                    return false;
                }
            }
            return true;
        }

        // Process characters after last star
        while ((ch = patArr[patEndIndex]) != '*' && valIndex <= valEndIndex) {
            if (ch != '?') {
                if (ch != valArr[valEndIndex]) {
                    return false;// Character mismatch
                }
            }
            patEndIndex--;
            valEndIndex--;
        }
        if (valIndex > valEndIndex) {
            // All characters in the value are used. Check if only '*'s remain
            // in the pattern. If so, we succeeded. Otherwise failure.
            for (int i = patIndex; i <= patEndIndex; i++) {
                if (patArr[i] != '*') {
                    return false;
                }
            }
            return true;
        }

        // process pattern between stars. patIndex and patEndIndex always point to a '*'.
        while (patIndex != patEndIndex && valIndex <= valEndIndex) {
            int innerPatternIndex = -1;
            for (int i = patIndex + 1; i <= patEndIndex; i++) {
                if (patArr[i] == '*') {
                    innerPatternIndex = i;
                    break;
                }
            }
            if (innerPatternIndex == patIndex + 1) {
                // Two stars next to each other, skip the first one.
                patIndex++;
                continue;
            }
            // Find the pattern between patIndex & innerPatternIndex in the value between
            // valIndex and valEndIndex
            int innerPatternLength = (innerPatternIndex - patIndex - 1);
            int innerValueLength = (valEndIndex - valIndex + 1);
            int foundIndex = -1;
            innerValueLoop:
            for (int i = 0; i <= innerValueLength - innerPatternLength; i++) {
                for (int j = 0; j < innerPatternLength; j++) {
                    ch = patArr[patIndex + j + 1];
                    if (ch != '?') {
                        if (ch != valArr[valIndex + i + j]) {
                            continue innerValueLoop;
                        }
                    }
                }

                foundIndex = valIndex + i;
                break;
            }

            if (foundIndex == -1) {
                return false;
            }

            patIndex = innerPatternIndex;
            valIndex = foundIndex + innerPatternLength;
        }

        // All characters in the string are used. Check if only '*'s are left
        // in the pattern. If so, we succeeded. Otherwise failure.
        for (int i = patIndex; i <= patEndIndex; i++) {
            if (patArr[i] != '*') {
                return false;
            }
        }

        return true;
    }
@Test
    public void testMatches() {
        assertMatch("x", "x");
        assertNoMatch("x", "y");

        assertMatch("xx", "xx");
        assertNoMatch("xy", "xz");

        assertMatch("?", "x");
        assertMatch("x?", "xy");
        assertMatch("?y", "xy");
        assertMatch("x?z", "xyz");

        assertMatch("*", "x");
        assertMatch("x*", "x");
        assertMatch("x*", "xy");
        assertMatch("xy*", "xy");
        assertMatch("xy*", "xyz");

        assertMatch("*x", "x");
        assertNoMatch("*x", "y");

        assertMatch("*x", "wx");
        assertNoMatch("*x", "wz");
        assertMatch("*x", "vwx");

        assertMatch("x*z", "xz");
        assertMatch("x*z", "xyz");
        assertMatch("x*z", "xyyz");

        assertNoMatch("ab*t?z", "abz");
        assertNoMatch("ab*d*yz", "abcdz");

        assertMatch("ab**cd**ef*yz", "abcdefyz");
        assertMatch("a*c?*z", "abcxyz");
        assertMatch("a*cd*z", "abcdxyz");

        assertMatch("*", "x:x");
        assertMatch("*", "x:x:x");
        assertMatch("x", "x:y");
        assertMatch("x", "x:y:z");

        assertMatch("foo?armat*", "foobarmatches");
        assertMatch("f*", "f");
        assertNoMatch("foo", "f");
        assertMatch("fo*b", "foob");
        assertNoMatch("fo*b*r", "fooba");
        assertNoMatch("foo*", "f");

        assertMatch("t*k?ou", "thankyou");
        assertMatch("he*l*world", "helloworld");
        assertNoMatch("foo", "foob");

        assertMatch("*:ActiveMQ.Advisory", "foo:ActiveMQ.Advisory");
        assertNoMatch("*:ActiveMQ.Advisory", "foo:ActiveMQ.Advisory.");
        assertMatch("*:ActiveMQ.Advisory*", "foo:ActiveMQ.Advisory");
        assertMatch("*:ActiveMQ.Advisory*", "foo:ActiveMQ.Advisory.");
        assertMatch("*:ActiveMQ.Advisory.*", "foo:ActiveMQ.Advisory.Connection");
        assertMatch("*:ActiveMQ.Advisory*:read", "foo:ActiveMQ.Advisory.Connection:read");
        assertNoMatch("*:ActiveMQ.Advisory*:read", "foo:ActiveMQ.Advisory.Connection:write");
        assertMatch("*:ActiveMQ.Advisory*:*", "foo:ActiveMQ.Advisory.Connection:read");
        assertMatch("*:ActiveMQ.Advisory*:*", "foo:ActiveMQ.Advisory.");
        assertMatch("topic", "topic:TEST:*");
        assertNoMatch("*:ActiveMQ*", "topic:TEST:*");
        assertMatch("topic:ActiveMQ.Advisory*", "topic:ActiveMQ.Advisory.Connection:create");
        assertMatch("foo?ar", "foobar");
        
        assertMatch("queue:*:read,write", "queue:testqueue:read");
        assertMatch("queue:*:read,write", "queue:test*:read,write");
        assertNoMatch("queue:*:read,write", "queue:*:read,write,delete");
    }