--- /dev/null
+// FilterEngine.java\r
+// $Id: FilterEngine.java,v 1.1 2010/06/15 12:25:12 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.www.protocol.http;\r
+\r
+import java.util.StringTokenizer;\r
+import java.util.Vector;\r
+\r
+import java.net.URL;\r
+\r
+class ScopeNode {\r
+ private static final int FILTER_INIT_SIZE = 2;\r
+ private static final int CHILD_INIT_SIZE = 4;\r
+\r
+ String key = null;\r
+ RequestFilter filters[] = null;\r
+ boolean inex[] = null;\r
+ ScopeNode child[] = null;\r
+\r
+ /**\r
+ * Trigger the sync method of filters set on this node, and recurse.\r
+ */\r
+\r
+ synchronized void sync() {\r
+ // Sync our own filters\r
+ if ( filters != null ) {\r
+ for (int i = 0 ; i < filters.length ; i++) {\r
+ RequestFilter f = filters[i];\r
+ if ( f == null )\r
+ continue;\r
+ f.sync();\r
+ }\r
+ }\r
+ // Sync all our children filters:\r
+ if ( child != null ) {\r
+ for (int i = 0 ; i < child.length ; i++) {\r
+ ScopeNode c = child[i];\r
+ if ( c == null )\r
+ continue;\r
+ c.sync();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Resolve this scope node into the provided vector.\r
+ * @param into The vector containing the list of filter settings.\r
+ */\r
+\r
+ synchronized void resolve(Vector into) {\r
+ // Anything to be done here ?\r
+ if ( filters == null )\r
+ return;\r
+ // Apply the filters:\r
+ for (int i = 0 ; i < filters.length ; i++) {\r
+ if ( filters[i] == null ) \r
+ continue;\r
+ boolean is = into.contains(filters[i]); \r
+ if ((! inex[i]) && ( is )) {\r
+ // The filter is to be excluded, but is actually present:\r
+ into.removeElement(filters[i]);\r
+ } else if (inex[i] && ( !is)) {\r
+ // The filter is to be included, but is not present:\r
+ into.addElement(filters[i]);\r
+ }\r
+ }\r
+ }\r
+\r
+ synchronized void setFilter(boolean ie, RequestFilter filter) {\r
+ int slot = -1;\r
+ // Find a slot:\r
+ if ( filters == null ) {\r
+ // Initialize the filters list:\r
+ filters = new RequestFilter[FILTER_INIT_SIZE];\r
+ inex = new boolean[FILTER_INIT_SIZE];\r
+ slot = 0;\r
+ } else {\r
+ // Look for a free slot:\r
+ for (int i = 0 ; i < filters.length ; i++) {\r
+ if ( filters[i] == null ) {\r
+ slot = i;\r
+ break;\r
+ }\r
+ }\r
+ // Do we need to resize the filters arrays:\r
+ if ( slot == -1 ) {\r
+ slot = filters.length;\r
+ RequestFilter nf[] = new RequestFilter[slot<<1];\r
+ boolean ni[] = new boolean[slot<<1];\r
+ System.arraycopy(filters, 0, nf, 0, slot);\r
+ System.arraycopy(inex, 0, ni, 0, slot);\r
+ filters = nf;\r
+ inex = ni;\r
+ }\r
+ }\r
+ // Updae the appropriate slot:\r
+ filters[slot] = filter;\r
+ inex[slot] = ie;\r
+ }\r
+\r
+ synchronized ScopeNode lookup(String key) {\r
+ // No children ?\r
+ if ( child == null )\r
+ return null;\r
+ // Lookup children, may be made more efficient if prooves usefull:\r
+ for (int i = 0 ; i < child.length ; i++) {\r
+ if ( child[i] == null )\r
+ continue;\r
+ if ( key.equals(child[i].key) )\r
+ return child[i];\r
+ }\r
+ return null;\r
+ }\r
+\r
+ synchronized ScopeNode create(String key) {\r
+ int slot = -1;\r
+ // Get a slot:\r
+ if ( child == null ) {\r
+ child = new ScopeNode[CHILD_INIT_SIZE];\r
+ slot = 0;\r
+ } else {\r
+ // Look for a free slot:\r
+ for (int i = 0 ; i < child.length ; i++) {\r
+ if ( child[i] == null ) {\r
+ slot = i;\r
+ break;\r
+ }\r
+ }\r
+ // Do we need to resize ?\r
+ if ( slot == -1 ) {\r
+ slot = child.length;\r
+ ScopeNode nc[] = new ScopeNode[slot << 1];\r
+ System.arraycopy(child, 0, nc, 0, slot);\r
+ child = nc;\r
+ }\r
+ }\r
+ // Update the slot:\r
+ return child[slot] = new ScopeNode(key);\r
+ }\r
+\r
+ ScopeNode(String key) {\r
+ this.key = key;\r
+ }\r
+\r
+ ScopeNode() {\r
+ // Valid only for the root node\r
+ }\r
+\r
+}\r
+\r
+class FilterEngine {\r
+ ScopeNode root = null;\r
+\r
+ /**\r
+ * Split an URL into its various parts.\r
+ * @return An array of Strings containing the URL parts.\r
+ */\r
+\r
+ private String[] urlParts(URL url) {\r
+ Vector parts = new Vector(8);\r
+ // The protocol is always the first part:\r
+ parts.addElement(url.getProtocol());\r
+ // Then comes the host:port identifier (we deal *only* with http):\r
+ if ((url.getPort() == -1) || (url.getPort() == 80)) {\r
+ parts.addElement(url.getHost());\r
+ } else {\r
+ parts.addElement(url.getHost()+":"+url.getPort());\r
+ }\r
+ // get the "file" part of URI with a fix for jdk1.4\r
+ String sUrl = url.getFile();\r
+ if (sUrl.length() == 0) {\r
+ sUrl = "/";\r
+ }\r
+ // And last but not least, the parsed path (really not efficient !)\r
+ StringTokenizer st = new StringTokenizer(sUrl, "/");\r
+ while ( st.hasMoreTokens() )\r
+ parts.addElement(st.nextElement());\r
+ // Build the vector into an array:\r
+ String p[] = new String[parts.size()];\r
+ parts.copyInto(p);\r
+ return p;\r
+ }\r
+\r
+ /**\r
+ * Register this given filter in the given scope.\r
+ * @param scope The URL prefix defining the scope of the filter.\r
+ * @param inex Is the scope an include or an exclude scope.\r
+ * @param filter The filter to register in the given scope.\r
+ */\r
+\r
+ synchronized void setFilter(URL scope, boolean ie, RequestFilter filter) {\r
+ String parts[] = urlParts(scope);\r
+ ScopeNode node = root;\r
+ // Find or create the appropriate scope node for the filter:\r
+ for (int i = 0 ; i < parts.length ; i++) {\r
+ ScopeNode child = node.lookup(parts[i]);\r
+ if ( child == null ) \r
+ child = node.create(parts[i]);\r
+ node = child;\r
+ }\r
+ // Setup the filter in the scope node:\r
+ node.setFilter(ie, filter);\r
+ }\r
+\r
+ synchronized void setFilter(RequestFilter filter) {\r
+ root.setFilter(true, filter);\r
+ }\r
+\r
+ /**\r
+ * Get a global filter of the given class.\r
+ * @return A RequestFilter instance, or <strong>null</strong> if none\r
+ * was found.\r
+ */\r
+\r
+ synchronized RequestFilter getGlobalFilter(Class cls) {\r
+ RequestFilter filters[] = root.filters;\r
+ for (int i = 0 ; i < filters.length ; i++) {\r
+ if ( filters[i] == null )\r
+ continue;\r
+ Class fc = filters[i].getClass();\r
+ while (fc != null) {\r
+ if ( fc == cls )\r
+ return filters[i];\r
+ fc = fc.getSuperclass();\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Trigger the sync method of all installed filters.\r
+ * This method walk through the entire filter tree, and sync all filters\r
+ * found on the way.\r
+ */\r
+\r
+ synchronized void sync() {\r
+ root.sync();\r
+ }\r
+\r
+ /**\r
+ * Compute the set of filters that apply to this request.\r
+ * This method examine the current scopes of all filters, and determine\r
+ * the list of filters to run for the given request.\r
+ * @return An array of filters to run for the given request, or\r
+ * <strong>null</strong> if no filters apply.\r
+ */\r
+\r
+ RequestFilter[] run(Request request) {\r
+ String parts[] = urlParts(request.getURL());\r
+ int ipart = 0;\r
+ ScopeNode node = root;\r
+ // Compute the filters apply list:\r
+ Vector applies = new Vector();\r
+ while (node != null) {\r
+ node.resolve(applies);\r
+ if ( ipart < parts.length )\r
+ node = node.lookup(parts[ipart++]);\r
+ else\r
+ break;\r
+ }\r
+ // Optional (not done for now) order the filters:\r
+\r
+ // Now run them, and keep the state in the request:\r
+ if ( applies.size() == 0 )\r
+ return null;\r
+ RequestFilter f[] = new RequestFilter[applies.size()];\r
+ applies.copyInto(f);\r
+ return f;\r
+ }\r
+\r
+ FilterEngine() {\r
+ this.root = new ScopeNode("_root_");\r
+ }\r
+\r
+ \r
+}\r