001: // FilterEngine.java
002: // $Id: FilterEngine.java,v 1.10 2002/07/11 17:36:04 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.www.protocol.http;
007:
008: import java.util.StringTokenizer;
009: import java.util.Vector;
010:
011: import java.net.URL;
012:
013: class ScopeNode {
014: private static final int FILTER_INIT_SIZE = 2;
015: private static final int CHILD_INIT_SIZE = 4;
016:
017: String key = null;
018: RequestFilter filters[] = null;
019: boolean inex[] = null;
020: ScopeNode child[] = null;
021:
022: /**
023: * Trigger the sync method of filters set on this node, and recurse.
024: */
025:
026: synchronized void sync() {
027: // Sync our own filters
028: if (filters != null) {
029: for (int i = 0; i < filters.length; i++) {
030: RequestFilter f = filters[i];
031: if (f == null)
032: continue;
033: f.sync();
034: }
035: }
036: // Sync all our children filters:
037: if (child != null) {
038: for (int i = 0; i < child.length; i++) {
039: ScopeNode c = child[i];
040: if (c == null)
041: continue;
042: c.sync();
043: }
044: }
045: }
046:
047: /**
048: * Resolve this scope node into the provided vector.
049: * @param into The vector containing the list of filter settings.
050: */
051:
052: synchronized void resolve(Vector into) {
053: // Anything to be done here ?
054: if (filters == null)
055: return;
056: // Apply the filters:
057: for (int i = 0; i < filters.length; i++) {
058: if (filters[i] == null)
059: continue;
060: boolean is = into.contains(filters[i]);
061: if ((!inex[i]) && (is)) {
062: // The filter is to be excluded, but is actually present:
063: into.removeElement(filters[i]);
064: } else if (inex[i] && (!is)) {
065: // The filter is to be included, but is not present:
066: into.addElement(filters[i]);
067: }
068: }
069: }
070:
071: synchronized void setFilter(boolean ie, RequestFilter filter) {
072: int slot = -1;
073: // Find a slot:
074: if (filters == null) {
075: // Initialize the filters list:
076: filters = new RequestFilter[FILTER_INIT_SIZE];
077: inex = new boolean[FILTER_INIT_SIZE];
078: slot = 0;
079: } else {
080: // Look for a free slot:
081: for (int i = 0; i < filters.length; i++) {
082: if (filters[i] == null) {
083: slot = i;
084: break;
085: }
086: }
087: // Do we need to resize the filters arrays:
088: if (slot == -1) {
089: slot = filters.length;
090: RequestFilter nf[] = new RequestFilter[slot << 1];
091: boolean ni[] = new boolean[slot << 1];
092: System.arraycopy(filters, 0, nf, 0, slot);
093: System.arraycopy(inex, 0, ni, 0, slot);
094: filters = nf;
095: inex = ni;
096: }
097: }
098: // Updae the appropriate slot:
099: filters[slot] = filter;
100: inex[slot] = ie;
101: }
102:
103: synchronized ScopeNode lookup(String key) {
104: // No children ?
105: if (child == null)
106: return null;
107: // Lookup children, may be made more efficient if prooves usefull:
108: for (int i = 0; i < child.length; i++) {
109: if (child[i] == null)
110: continue;
111: if (key.equals(child[i].key))
112: return child[i];
113: }
114: return null;
115: }
116:
117: synchronized ScopeNode create(String key) {
118: int slot = -1;
119: // Get a slot:
120: if (child == null) {
121: child = new ScopeNode[CHILD_INIT_SIZE];
122: slot = 0;
123: } else {
124: // Look for a free slot:
125: for (int i = 0; i < child.length; i++) {
126: if (child[i] == null) {
127: slot = i;
128: break;
129: }
130: }
131: // Do we need to resize ?
132: if (slot == -1) {
133: slot = child.length;
134: ScopeNode nc[] = new ScopeNode[slot << 1];
135: System.arraycopy(child, 0, nc, 0, slot);
136: child = nc;
137: }
138: }
139: // Update the slot:
140: return child[slot] = new ScopeNode(key);
141: }
142:
143: ScopeNode(String key) {
144: this .key = key;
145: }
146:
147: ScopeNode() {
148: // Valid only for the root node
149: }
150:
151: }
152:
153: class FilterEngine {
154: ScopeNode root = null;
155:
156: /**
157: * Split an URL into its various parts.
158: * @return An array of Strings containing the URL parts.
159: */
160:
161: private String[] urlParts(URL url) {
162: Vector parts = new Vector(8);
163: // The protocol is always the first part:
164: parts.addElement(url.getProtocol());
165: // Then comes the host:port identifier (we deal *only* with http):
166: if ((url.getPort() == -1) || (url.getPort() == 80)) {
167: parts.addElement(url.getHost());
168: } else {
169: parts.addElement(url.getHost() + ":" + url.getPort());
170: }
171: // get the "file" part of URI with a fix for jdk1.4
172: String sUrl = url.getFile();
173: if (sUrl.length() == 0) {
174: sUrl = "/";
175: }
176: // And last but not least, the parsed path (really not efficient !)
177: StringTokenizer st = new StringTokenizer(sUrl, "/");
178: while (st.hasMoreTokens())
179: parts.addElement(st.nextElement());
180: // Build the vector into an array:
181: String p[] = new String[parts.size()];
182: parts.copyInto(p);
183: return p;
184: }
185:
186: /**
187: * Register this given filter in the given scope.
188: * @param scope The URL prefix defining the scope of the filter.
189: * @param inex Is the scope an include or an exclude scope.
190: * @param filter The filter to register in the given scope.
191: */
192:
193: synchronized void setFilter(URL scope, boolean ie,
194: RequestFilter filter) {
195: String parts[] = urlParts(scope);
196: ScopeNode node = root;
197: // Find or create the appropriate scope node for the filter:
198: for (int i = 0; i < parts.length; i++) {
199: ScopeNode child = node.lookup(parts[i]);
200: if (child == null)
201: child = node.create(parts[i]);
202: node = child;
203: }
204: // Setup the filter in the scope node:
205: node.setFilter(ie, filter);
206: }
207:
208: synchronized void setFilter(RequestFilter filter) {
209: root.setFilter(true, filter);
210: }
211:
212: /**
213: * Get a global filter of the given class.
214: * @return A RequestFilter instance, or <strong>null</strong> if none
215: * was found.
216: */
217:
218: synchronized RequestFilter getGlobalFilter(Class cls) {
219: RequestFilter filters[] = root.filters;
220: for (int i = 0; i < filters.length; i++) {
221: if (filters[i] == null)
222: continue;
223: Class fc = filters[i].getClass();
224: while (fc != null) {
225: if (fc == cls)
226: return filters[i];
227: fc = fc.getSuperclass();
228: }
229: }
230: return null;
231: }
232:
233: /**
234: * Trigger the sync method of all installed filters.
235: * This method walk through the entire filter tree, and sync all filters
236: * found on the way.
237: */
238:
239: synchronized void sync() {
240: root.sync();
241: }
242:
243: /**
244: * Compute the set of filters that apply to this request.
245: * This method examine the current scopes of all filters, and determine
246: * the list of filters to run for the given request.
247: * @return An array of filters to run for the given request, or
248: * <strong>null</strong> if no filters apply.
249: */
250:
251: RequestFilter[] run(Request request) {
252: String parts[] = urlParts(request.getURL());
253: int ipart = 0;
254: ScopeNode node = root;
255: // Compute the filters apply list:
256: Vector applies = new Vector();
257: while (node != null) {
258: node.resolve(applies);
259: if (ipart < parts.length)
260: node = node.lookup(parts[ipart++]);
261: else
262: break;
263: }
264: // Optional (not done for now) order the filters:
265:
266: // Now run them, and keep the state in the request:
267: if (applies.size() == 0)
268: return null;
269: RequestFilter f[] = new RequestFilter[applies.size()];
270: applies.copyInto(f);
271: return f;
272: }
273:
274: FilterEngine() {
275: this .root = new ScopeNode("_root_");
276: }
277:
278: }
|