001: // WildcardDictionary - a dictionary with wildcard lookups
002: //
003: // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
004: //
005: // Redistribution and use in source and binary forms, with or without
006: // modification, are permitted provided that the following conditions
007: // are met:
008: // 1. Redistributions of source code must retain the above copyright
009: // notice, this list of conditions and the following disclaimer.
010: // 2. Redistributions in binary form must reproduce the above copyright
011: // notice, this list of conditions and the following disclaimer in the
012: // documentation and/or other materials provided with the distribution.
013: //
014: // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
015: // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
016: // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
017: // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
018: // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
019: // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
020: // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
021: // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
022: // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
023: // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
024: // SUCH DAMAGE.
025: //
026: // Visit the ACME Labs Java page for up-to-date versions of this and other
027: // fine Java utilities: http://www.acme.com/java/
028:
029: package Acme;
030:
031: import java.util.*;
032:
033: /// A dictionary with wildcard lookups.
034: // <P>
035: // The keys in this dictionary are wildcard patterns. When you do a get(),
036: // the string you pass in is matched against all the patterns, and the
037: // first match is returned.
038: // <P>
039: // The wildcard matcher is fairly simple, it implements * meaning any
040: // string, ? meaning any single character, and | separating multiple
041: // patterns. All other characters must match literally.
042: // <P>
043: // <A HREF="/resources/classes/Acme/WildcardDictionary.java">Fetch the software.</A><BR>
044: // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
045: // <P>
046: // @see Acme.Utils#match
047:
048: public class WildcardDictionary extends Dictionary {
049:
050: private Vector keys;
051: private Vector elements;
052:
053: /// Constructor.
054: public WildcardDictionary() {
055: keys = new Vector();
056: elements = new Vector();
057: }
058:
059: /// Returns the number of elements contained within the dictionary.
060: public int size() {
061: return elements.size();
062: }
063:
064: /// Returns true if the dictionary contains no elements.
065: public boolean isEmpty() {
066: return size() == 0;
067: }
068:
069: /// Returns an enumeration of the dictionary's keys.
070: public Enumeration keys() {
071: return keys.elements();
072: }
073:
074: /// Returns an enumeration of the elements. Use the Enumeration methods
075: // on the returned object to fetch the elements sequentially.
076: public Enumeration elements() {
077: return elements.elements();
078: }
079:
080: /// Gets the object associated with the specified key in the dictionary.
081: // The key is assumed to be a String, which is matched against
082: // the wildcard-pattern keys in the dictionary.
083: // @param key the string to match
084: // @returns the element for the key, or null if there's no match
085: // @see Acme.Utils#match
086: public synchronized Object get(Object key) {
087: String sKey = (String) key;
088: int matching_len = 0, found = -1;
089: // to optimize speed, keys should be sorted by length
090: // TODO: above
091: for (int i = keys.size() - 1; i > -1; i--) {
092: String this Key = (String) keys.elementAt(i);
093: int current = Acme.Utils.matchSpan(this Key, sKey);
094: if (current > matching_len) {
095: found = i;
096: matching_len = current;
097: }
098: }
099: if (found > -1)
100: return elements.elementAt(found);
101: return null;
102: }
103:
104: public static String trimPathSeparators(String src) {
105: StringBuffer result = new StringBuffer(src.length());
106: boolean ms = false;
107: for (int i = 0; i < src.length(); i++) {
108: char c = src.charAt(i);
109: if (c == '/' || c == '\\') {
110: if (!ms) {
111: result.append(c);
112: ms = true;
113: }
114: } else {
115: result.append(c);
116: ms = false;
117: }
118: }
119: return result.toString();
120: }
121:
122: /// Puts the specified element into the Dictionary, using the specified
123: // key. The element may be retrieved by doing a get() with the same
124: // key. The key and the element cannot be null.
125: // @param key the specified wildcard-pattern key
126: // @param value the specified element
127: // @return the old value of the key, or null if it did not have one.
128: // @exception NullPointerException If the value of the specified
129: // element is null.
130: public synchronized Object put(Object key, Object element) {
131: int i = keys.indexOf(key);
132: if (i != -1) {
133: Object oldElement = elements.elementAt(i);
134: elements.setElementAt(element, i);
135: return oldElement;
136: } else {
137: keys.addElement(key);
138: elements.addElement(element);
139: return null;
140: }
141: }
142:
143: /// Removes the element corresponding to the key. Does nothing if the
144: // key is not present.
145: // @param key the key that needs to be removed
146: // @return the value of key, or null if the key was not found.
147: public synchronized Object remove(Object key) {
148: int i = keys.indexOf(key);
149: if (i != -1) {
150: Object oldElement = elements.elementAt(i);
151: keys.removeElementAt(i);
152: elements.removeElementAt(i);
153: return oldElement;
154: } else
155: return null;
156: }
157: }
|