00001 // WildcardDictionary - a dictionary with wildcard lookups 00002 // 00003 // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved. 00004 // 00005 // Redistribution and use in source and binary forms, with or without 00006 // modification, are permitted provided that the following conditions 00007 // are met: 00008 // 1. Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // 2. Redistributions in binary form must reproduce the above copyright 00011 // notice, this list of conditions and the following disclaimer in the 00012 // documentation and/or other materials provided with the distribution. 00013 // 00014 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 00015 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00016 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00017 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 00018 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00019 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00020 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00021 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00022 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00023 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00024 // SUCH DAMAGE. 00025 // 00026 // Visit the ACME Labs Java page for up-to-date versions of this and other 00027 // fine Java utilities: http://www.acme.com/java/ 00028 00029 package Acme; 00030 00031 import java.util.*; 00032 00034 // <P> 00035 // The keys in this dictionary are wildcard patterns. When you do a get(), 00036 // the string you pass in is matched against all the patterns, and the 00037 // first match is returned. 00038 // <P> 00039 // The wildcard matcher is fairly simple, it implements * meaning any 00040 // string, ? meaning any single character, and | separating multiple 00041 // patterns. All other characters must match literally. 00042 // <P> 00043 // <A HREF="/resources/classes/Acme/WildcardDictionary.java">Fetch the software.</A><BR> 00044 // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A> 00045 // <P> 00046 // @see Acme.Utils#match 00047 00048 public class WildcardDictionary extends Dictionary 00049 { 00050 00051 private Vector keys; 00052 private Vector elements; 00053 00055 public WildcardDictionary() 00056 { 00057 keys = new Vector(); 00058 elements = new Vector(); 00059 } 00060 00062 public int size() 00063 { 00064 return elements.size(); 00065 } 00066 00068 public boolean isEmpty() 00069 { 00070 return size() == 0; 00071 } 00072 00074 public Enumeration keys() 00075 { 00076 return keys.elements(); 00077 } 00078 00080 // on the returned object to fetch the elements sequentially. 00081 public Enumeration elements() 00082 { 00083 return elements.elements(); 00084 } 00085 00087 // The key is assumed to be a String, which is matched against 00088 // the wildcard-pattern keys in the dictionary. 00089 // @param key the string to match 00090 // @returns the element for the key, or null if there's no match 00091 // @see Acme.Utils#match 00092 public synchronized Object get( Object key ) 00093 { 00094 String sKey = (String) key; 00095 int matching_len = 0, found = -1; 00096 // to optimize speed, keys should be sorted by length 00097 // TODO: above 00098 for ( int i = keys.size()-1; i > -1 ; i-- ) 00099 { 00100 String thisKey = (String) keys.elementAt( i ); 00101 int current = Acme.Utils.matchSpan( thisKey, sKey ); 00102 if (current > matching_len) 00103 { 00104 found = i; 00105 matching_len = current; 00106 } 00107 } 00108 if (found > -1) 00109 return elements.elementAt( found ); 00110 return null; 00111 } 00112 00113 public static String trimPathSeparators(String src) { 00114 StringBuffer result = new StringBuffer(src.length()); 00115 boolean ms = false; 00116 for (int i=0; i<src.length(); i++) { 00117 char c = src.charAt(i); 00118 if (c == '/' || c == '\\') { 00119 if (!ms) { 00120 result.append(c); 00121 ms = true; 00122 } 00123 } else { 00124 result.append(c); 00125 ms = false; 00126 } 00127 } 00128 return result.toString(); 00129 } 00130 00132 // key. The element may be retrieved by doing a get() with the same 00133 // key. The key and the element cannot be null. 00134 // @param key the specified wildcard-pattern key 00135 // @param value the specified element 00136 // @return the old value of the key, or null if it did not have one. 00137 // @exception NullPointerException If the value of the specified 00138 // element is null. 00139 public synchronized Object put( Object key, Object element ) 00140 { 00141 int i = keys.indexOf( key ); 00142 if ( i != -1 ) 00143 { 00144 Object oldElement = elements.elementAt( i ); 00145 elements.setElementAt( element, i ); 00146 return oldElement; 00147 } 00148 else 00149 { 00150 keys.addElement( key ); 00151 elements.addElement( element ); 00152 return null; 00153 } 00154 } 00155 00157 // key is not present. 00158 // @param key the key that needs to be removed 00159 // @return the value of key, or null if the key was not found. 00160 public synchronized Object remove( Object key ) 00161 { 00162 int i = keys.indexOf( key ); 00163 if ( i != -1 ) 00164 { 00165 Object oldElement = elements.elementAt( i ); 00166 keys.removeElementAt( i ); 00167 elements.removeElementAt( i ); 00168 return oldElement; 00169 } 00170 else 00171 return null; 00172 } 00173 }