001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.util;
023:
024: import java.util.Hashtable;
025: import java.util.Iterator;
026: import java.util.Map;
027:
028: import javax.management.ObjectName;
029:
030: /**
031: * ObjectName pattern matching Helper.<p>
032: *
033: * Contains various routines for matching domains and properties.<p>
034: *
035: * Routines based on work done Trevor in the registry.
036: *
037: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
038: * @author <a href="mailto:trevor@protocool.com">Trevor Squires</a>.
039: * @version $Revision: 57200 $
040: */
041: public class ObjectNamePatternHelper {
042: // Static --------------------------------------------------------
043:
044: /**
045: * Compare an object name against a pattern.
046: *
047: * @param test the string to test
048: * @param pattern the pattern to match
049: */
050: public static boolean patternMatch(ObjectName test,
051: ObjectName pattern) {
052: if (pattern.equals("*:*"))
053: return true;
054:
055: if (patternMatch(test.getDomain(), pattern.getDomain())) {
056: PropertyPattern propertyPattern = new PropertyPattern(
057: pattern);
058: return propertyPattern.patternMatch(test);
059: }
060: return false;
061: }
062:
063: /**
064: * Compare strings where ? and * chars are significant.
065: *
066: * @param test the string to test
067: * @param pattern the pattern to match
068: */
069: public static boolean patternMatch(String test, String pattern) {
070: if (pattern.equals("*"))
071: return true;
072: return patternMatch(test.toCharArray(), 0, pattern
073: .toCharArray(), 0);
074: }
075:
076: /**
077: * Compare where ? and * chars are significant.<p>
078: *
079: * I arrived at this solution after quite a bit of trial and error - it's
080: * all a bit interwoven. Obviously I'm no good at parsers and there must
081: * be a clearer or more elegant way to do this. I'm suitably in awe of
082: * the perl regex hackers now.
083: *
084: * @param test the string to test
085: * @param tpos the start of the test string
086: * @param pattern the pattern to match
087: * @param ppos the start of the pattern string
088: */
089: public static boolean patternMatch(char[] test, int tpos,
090: char[] pattern, int ppos) {
091: int tlen = test.length;
092: int plen = pattern.length;
093:
094: while (ppos < plen) {
095: char c = pattern[ppos++];
096: if ('?' == c) {
097: // eat a test character and make sure we're not
098: // already at the end
099: if (tpos++ == tlen)
100: return false;
101: } else if ('*' == c) {
102: if (ppos == plen) // shortcut - * at the end of the pattern
103: return true;
104:
105: // Fell off the end
106: if (tpos == tlen)
107: return false;
108:
109: // hammer the test chars recursively until we
110: // get a match or we drop off the end of test
111: do {
112: if (patternMatch(test, tpos, pattern, ppos))
113: return true;
114: } while (++tpos < tlen);
115: } else if (tpos == tlen || c != test[tpos++])
116: return false;
117: }
118: // fell through with no falses so make sure all of test was examined
119: return (tpos == tlen);
120: }
121:
122: /**
123: * Encapsulation of property information
124: */
125: public static class PropertyPattern {
126: /**
127: * Are these properties a pattern?
128: */
129: boolean isPropertyPattern;
130:
131: /**
132: * The keys for the properties
133: */
134: Object[] propertyKeys;
135:
136: /**
137: * The keys for the properties
138: */
139: Object[] propertyValues;
140:
141: /**
142: * The canonical key property string
143: */
144: String canonicalKeyPropertyString;
145:
146: /**
147: * Construct a new property pattern
148: *
149: * @param pattern the object name that might be a pattern
150: */
151: public PropertyPattern(ObjectName pattern) {
152: isPropertyPattern = pattern.isPropertyPattern();
153: if (isPropertyPattern) {
154: Hashtable patternKPList = pattern.getKeyPropertyList();
155: int length = patternKPList.size();
156: propertyKeys = new Object[length];
157: propertyValues = new Object[length];
158:
159: int i = 0;
160: for (Iterator iterator = patternKPList.entrySet()
161: .iterator(); iterator.hasNext(); i++) {
162: Map.Entry entry = (Map.Entry) iterator.next();
163: propertyKeys[i] = entry.getKey();
164: propertyValues[i] = entry.getValue();
165: }
166: } else
167: canonicalKeyPropertyString = pattern
168: .getCanonicalKeyPropertyListString();
169: }
170:
171: /**
172: * Test whether the object name matches the pattern
173: *
174: * @param name the name to test
175: */
176: public boolean patternMatch(ObjectName name) {
177: if (isPropertyPattern) {
178: // "*" matches everything
179: if (propertyKeys.length == 0)
180: return true;
181:
182: Hashtable kplist = name.getKeyPropertyList();
183:
184: for (int i = 0; i < propertyKeys.length; i++) {
185: if (propertyValues[i].equals(kplist
186: .get(propertyKeys[i])) == false)
187: return false;
188: }
189: return true;
190: } else
191: return canonicalKeyPropertyString.equals(name
192: .getCanonicalKeyPropertyListString());
193: }
194: }
195: }
|