--- /dev/null
+// BrokerFrame.java\r
+// $Id: BrokerFrame.java,v 1.2 2010/06/15 17:53:08 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1997.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.admin;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import java.util.Hashtable;\r
+import java.util.StringTokenizer;\r
+\r
+import java.util.zip.GZIPInputStream;\r
+\r
+import org.w3c.jigsaw.daemon.ServerHandler;\r
+import org.w3c.jigsaw.daemon.ServerHandlerManager;\r
+\r
+import org.w3c.tools.resources.AttributeHolder;\r
+import org.w3c.tools.resources.ContainerInterface;\r
+import org.w3c.tools.resources.DirectoryResource;\r
+import org.w3c.tools.resources.FramedResource;\r
+import org.w3c.tools.resources.InvalidResourceException;\r
+import org.w3c.tools.resources.LookupResult;\r
+import org.w3c.tools.resources.LookupState;\r
+import org.w3c.tools.resources.MultipleLockException;\r
+import org.w3c.tools.resources.ProtocolException;\r
+import org.w3c.tools.resources.Resource;\r
+import org.w3c.tools.resources.ResourceException;\r
+import org.w3c.tools.resources.ResourceFrame;\r
+import org.w3c.tools.resources.ResourceReference;\r
+\r
+import org.w3c.www.mime.MimeType;\r
+\r
+import org.w3c.www.http.HTTP;\r
+import org.w3c.www.http.HttpEntityMessage;\r
+import org.w3c.www.http.HttpMessage;\r
+import org.w3c.www.http.HttpRequestMessage;\r
+\r
+import org.w3c.jigsaw.http.Client;\r
+import org.w3c.jigsaw.http.HTTPException;\r
+import org.w3c.jigsaw.http.Reply;\r
+import org.w3c.jigsaw.http.Request;\r
+\r
+import org.w3c.jigsaw.frames.HTTPFrame;\r
+\r
+import org.w3c.tools.resources.ProtocolException;\r
+import org.w3c.tools.resources.ResourceException;\r
+import org.w3c.tools.resources.serialization.ResourceDescription;\r
+import org.w3c.tools.resources.serialization.AttributeDescription;\r
+\r
+public class BrokerFrame extends HTTPFrame {\r
+\r
+ class LookupFrameState {\r
+ private int index ;\r
+ private String components[] ;\r
+\r
+ void parseQuery(String query) {\r
+ StringTokenizer st = new StringTokenizer(query, "?");\r
+ int nbTokens = st.countTokens();\r
+ components = new String[nbTokens];\r
+ for (int i = 0 ; i < nbTokens ; i++)\r
+ components[i] = st.nextToken();\r
+ index = 0;\r
+ }\r
+\r
+ public boolean hasMoreComponents() {\r
+ return index < components.length ;\r
+ }\r
+\r
+ public final String getNextComponent() {\r
+ return components[index++] ;\r
+ }\r
+\r
+ LookupFrameState (String query) {\r
+ parseQuery(query);\r
+ }\r
+ }\r
+\r
+ protected ResourceBroker broker = null;\r
+\r
+ public void registerResource(FramedResource resource) {\r
+ super.registerResource(resource);\r
+ if (resource instanceof ResourceBroker)\r
+ broker = (ResourceBroker) resource;\r
+ }\r
+\r
+ \r
+ /**\r
+ * The object that knows how to write the admin protocol.\r
+ */\r
+ protected AdminWriter writer = null;\r
+\r
+ /**\r
+ * The ServerHandlerManager we export.\r
+ */\r
+ protected ServerHandlerManager shm = null;\r
+ /**\r
+ * The controlling ServerHandler.\r
+ */\r
+ protected AdminServer admin = null;\r
+\r
+ /**\r
+ * Trigger an HTTP exception.\r
+ * @param request The request we couldn't fulfill.\r
+ * @param msg The error message.\r
+ * @exception ProtocolException Always thrown.\r
+ */\r
+\r
+ protected void error(Request request, String msg) \r
+ throws ProtocolException\r
+ {\r
+ Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+ reply.setContent(msg);\r
+ throw new HTTPException(reply);\r
+ }\r
+\r
+ protected Reply okReply(Request request, byte bits[]) {\r
+ Reply reply = request.makeReply(HTTP.OK);\r
+ reply.setContentType(AdminContext.conftype);\r
+ if ( bits != null ) {\r
+ ByteArrayInputStream in = new ByteArrayInputStream(bits);\r
+ reply.setContentLength(bits.length);\r
+ reply.setStream(in);\r
+ }\r
+ return reply;\r
+ }\r
+\r
+ protected Reply okReply(Request request) {\r
+ return okReply(request, null);\r
+ }\r
+\r
+ /**\r
+ * Check that request incomming content type.\r
+ * @param request The request to check.\r
+ * @exception ProtocolException If the request type doesn't match admin.\r
+ */\r
+\r
+ protected void checkContentType(Request request) \r
+ throws ProtocolException\r
+ {\r
+ if ( request.getContentType().match(AdminContext.conftype) < 0 ) \r
+ error(request, "invalid MIME type: "+request.getContentType());\r
+ }\r
+\r
+ /**\r
+ * Get a data input stream out of that request input stream\r
+ * @param request The request to get data from.\r
+ * @exception ProtocolException If we couldn't get the request's content.\r
+ * @return A DataInputStream instance to read the request's content.\r
+ */\r
+\r
+ protected InputStream getInputStream(Request request) \r
+ throws ProtocolException\r
+ {\r
+ // How fun HTTP/1.1 is, allowing us to double the network traffic :-(\r
+ // If this is a 1.1 request, send a 100 continue:\r
+ Client client = request.getClient();\r
+ if ( client != null ) {\r
+ try {\r
+ client.sendContinue();\r
+ } catch (IOException ex) {\r
+ throw new HTTPException(ex.getMessage());\r
+ }\r
+ }\r
+ // Now, only, get the data:\r
+ try {\r
+ if (request.hasTransferEncoding("gzip"))\r
+ return new GZIPInputStream(request.getInputStream());\r
+ else\r
+ return request.getInputStream();\r
+ } catch (IOException ex) {\r
+ error(request, "invalid request");\r
+ }\r
+ // not reached:\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Lookup the target of the given request.\r
+ * @param request The request whose target is to be fetched.\r
+ * @return A Resource instance.\r
+ * @exception ProtocolException If the resource couldn't be located.\r
+ */\r
+\r
+ public ResourceReference lookup(Request request) \r
+ throws ProtocolException\r
+ {\r
+ // Create lookup state and get rid of root resource requests:\r
+ LookupState ls = null;\r
+ try {\r
+ ls = new LookupState(request);\r
+ } catch (org.w3c.tools.resources.ProtocolException ex) {\r
+ ex.printStackTrace();\r
+ throw new HTTPException(ex);\r
+ }\r
+ LookupResult lr = new LookupResult(null);\r
+ ResourceReference rr = null; // cr\r
+ ls.markInternal();\r
+ if ( ! ls.hasMoreComponents() ) \r
+ return admin.getRootReference();\r
+ // Lookup the target resource:\r
+ String name = ls.getNextComponent();\r
+ ServerHandler sh = shm.lookupServerHandler(name);\r
+ if ( sh == null ) {\r
+ if(name.equals("realms")) {\r
+ rr = admin.getRealmCatalogResource();\r
+ } else if (name.equals("control")) {\r
+ rr = admin.getControlResource();\r
+ } else {\r
+ error(request, "unknown server handler");\r
+ }\r
+ } else {\r
+ // Lookup that resource, from the config resource of that server:\r
+ rr = sh.getConfigResource();\r
+ }\r
+ if ( rr != null ) {\r
+ ResourceReference rr_temp = null;\r
+ while ( ls.hasMoreComponents() ) {\r
+ try {\r
+ if (rr == null)\r
+ error(request, "url too long");\r
+ Resource r = rr.lock();\r
+ if ( ! ( r instanceof ContainerInterface) )\r
+ error(request, "url too long");\r
+ rr_temp = ((ContainerInterface) r).lookup(\r
+ ls.getNextComponent());\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, "unable to restore resource");\r
+ } finally {\r
+ rr.unlock();\r
+ rr = rr_temp;\r
+ }\r
+ }\r
+ if ( rr == null )\r
+ error(request, "unknown resource");\r
+ String query = request.getQueryString();\r
+ if ( query != null ) {\r
+ try {\r
+ Resource r = rr.lock();\r
+ // Querying a frame !\r
+ if ( ! (r instanceof FramedResource) )\r
+ error(request, "not a framed resource");\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, "unable to restore resource");\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+\r
+ //search the right frame\r
+ LookupFrameState lfs = new LookupFrameState(query);\r
+ \r
+ String frameName = null;\r
+ ResourceReference the_rrf = rr; \r
+ ResourceReference[] rra = null; \r
+\r
+ while (lfs.hasMoreComponents()) {\r
+\r
+ try {\r
+ rra = ((FramedResource) \r
+ the_rrf.lock()).getFramesReference();\r
+ if (rra == null)\r
+ error(request, "unknown frame");\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, ex.getMessage());\r
+ } finally {\r
+ the_rrf.unlock();\r
+ }\r
+ the_rrf = null;\r
+ frameName = lfs.getNextComponent();\r
+ ResourceReference rrf = null; \r
+ ResourceFrame frame = null;\r
+\r
+ for (int i = 0 ; i < rra.length ; i++) {\r
+ rrf = rra[i];\r
+ try {\r
+ frame = (ResourceFrame) rrf.lock();\r
+ if (frame.getIdentifier().equals(frameName)) {\r
+ the_rrf = rrf;\r
+ break;\r
+ }\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, ex.getMessage());\r
+ } finally {\r
+ rrf.unlock();\r
+ }\r
+ }\r
+ if (the_rrf == null)\r
+ error(request,"unknown frame");\r
+ }\r
+ \r
+ return the_rrf;\r
+ } else {\r
+ // Emit back this resource (after a check):\r
+ return rr;\r
+ }\r
+ }\r
+ error(request, "unknown resource");\r
+ // not reached\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Set a set of attribute values for the target resource.\r
+ * @param request The request to handle.\r
+ * @return A Reply instance.\r
+ * @exception ProtocolException If some error occurs.\r
+ */\r
+\r
+ public Reply remoteSetValues(Request request) \r
+ throws ProtocolException\r
+ {\r
+ InputStream in = getInputStream(request);\r
+ //Get the target resource to act on:\r
+ ResourceReference rr = lookup(request);\r
+ try {\r
+ Resource r = rr.lock();\r
+ ResourceDescription descr = \r
+ AdminReader.readResourceDescription(in);\r
+ AttributeDescription attrs[] = descr.getAttributeDescriptions();\r
+ for (int i = 0 ; i < attrs.length ; i++) {\r
+ AttributeDescription ad = attrs[i];\r
+ r.setValue(ad.getName(), ad.getValue());\r
+ }\r
+ } catch (InvalidResourceException irex) {\r
+ irex.printStackTrace();\r
+ error(request, "Invalid resource");\r
+ } catch (IOException ioex) {\r
+ error(request, "bad request");\r
+ } catch (AdminProtocolException apex) {\r
+ error(request, apex.getMessage());\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // All the changes done, return OK:\r
+ return okReply(request);\r
+ }\r
+\r
+ /**\r
+ * Return a resource back to the client.\r
+ * @param request The request to handle.\r
+ * @return A Reply instance.\r
+ * @exception ProtocolException If some error occurs.\r
+ */\r
+\r
+ public Reply remoteLoadResource(Request request) \r
+ throws ProtocolException\r
+ {\r
+ ResourceReference rr = lookup(request);\r
+\r
+ // This request has no content\r
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();\r
+\r
+ try {\r
+ Resource r = rr.lock();\r
+ writer.writeResource(r, bout);\r
+ } catch (IOException ex) {\r
+ error(request, "bad request");\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, "Invalid resource");\r
+ } catch (AdminProtocolException ex) {\r
+ error(request, ex.getMessage());\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // Setup the reply:\r
+ return okReply(request, bout.toByteArray());\r
+ }\r
+\r
+ public Reply remoteRegisterFrame(Request request) \r
+ throws ProtocolException\r
+ {\r
+ ResourceReference rr = lookup(request);\r
+ try {\r
+ Resource r = rr.lock();\r
+ if ( ! ( r instanceof FramedResource) )\r
+ error(request, "can't add frame to non-framed resource");\r
+ // Handle the request:\r
+ try {\r
+ InputStream in = getInputStream(request);\r
+ ResourceDescription rd = \r
+ AdminReader.readResourceDescription(in);\r
+ String cls = rd.getClassName();\r
+ String id = rd.getIdentifier();\r
+ // Create the frame:\r
+ ResourceFrame frame = null;\r
+ try {\r
+ frame = (ResourceFrame) Class.forName(cls).newInstance();\r
+ //Added by Jeff Huang\r
+ //TODO: FIXIT\r
+ } catch (Exception ex) {\r
+ error(request, "invalid frame class "+cls);\r
+ }\r
+ // Register the frame:\r
+ Hashtable defs = new Hashtable(3);\r
+ if ((id != null) && ! id.equals("") ) {\r
+ defs.put("identifier", id);\r
+ }\r
+ ((FramedResource) r).registerFrame(frame, defs);\r
+ // Send back the whole resource (inclding new frame):\r
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();\r
+ writer.writeResource(frame, bout);\r
+ return okReply(request, bout.toByteArray());\r
+ } catch (IOException ioex) {\r
+ error(request, "bad request");\r
+ } catch (AdminProtocolException apex) {\r
+ error(request, apex.getMessage());\r
+ }\r
+ } catch (InvalidResourceException irex) {\r
+ error(request, "invalid resource");\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // not reached:\r
+ return null;\r
+ }\r
+\r
+ public Reply remoteUnregisterFrame(Request request) \r
+ throws ProtocolException\r
+ {\r
+ ResourceReference rr = lookup(request);\r
+ try{\r
+ Resource r = rr.lock();\r
+ if(!(r instanceof FramedResource)) {\r
+ error(request, "Can't unregister frames from a non-framed" +\r
+ " resource");\r
+ }\r
+ try {\r
+ InputStream in = getInputStream(request);\r
+ ResourceDescription rd = \r
+ AdminReader.readResourceDescription(in);\r
+ String identifier = rd.getIdentifier(); \r
+ // find the indentifier\r
+ ResourceFrame f[] = ((FramedResource) r).getFrames();\r
+ for (int i = 0 ; i < f.length ; i++)\r
+ if (f[i].getIdentifier().equals(identifier)) {\r
+ ((FramedResource) r).unregisterFrame(f[i]);\r
+ return okReply(request);\r
+ }\r
+ error(request, "Frame " + identifier + " not registered");\r
+ } catch (IOException ex) {\r
+ error(request, "bad request");\r
+ } catch (AdminProtocolException apex) {\r
+ error(request, apex.getMessage());\r
+ }\r
+ } catch (InvalidResourceException ex2) {\r
+ error(request, "invalid resource");\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // Not reached\r
+ return null;\r
+ }\r
+\r
+ public Reply remoteRegisterResource(Request request) \r
+ throws ProtocolException\r
+ {\r
+ // Check target resource class:\r
+ ResourceReference rr = lookup(request);\r
+ try {\r
+ Resource r = rr.lock();\r
+ if ( ! ( r instanceof ContainerInterface) )\r
+ error(request, "can't add child in non-container");\r
+ // Handle request:\r
+ try {\r
+ InputStream in = getInputStream(request);\r
+ ResourceDescription rd = \r
+ AdminReader.readResourceDescription(in);\r
+ String cls = rd.getClassName();\r
+ String id = rd.getIdentifier();\r
+ // Create the resource:\r
+ Resource child = null;\r
+ try {\r
+ child = (Resource) Class.forName(cls).newInstance();\r
+ //Added by Jeff Huang\r
+ //TODO: FIXIT\r
+ } catch (Exception ex) {\r
+ error(request, "invalid resource class "+cls);\r
+ }\r
+ // Add it to the container:\r
+ try {\r
+ ((ContainerInterface) r).registerResource(id, child, null);\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, ex.getMessage());\r
+ }\r
+ // Write back the new resource:\r
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();\r
+ writer.writeResource(child, bout);\r
+ return okReply(request, bout.toByteArray());\r
+ } catch (IOException ex) {\r
+ error(request, "bad request");\r
+ } catch (AdminProtocolException apex) {\r
+ error(request, apex.getMessage());\r
+ }\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, "Invalid resource");\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // not reached:\r
+ return null;\r
+ }\r
+\r
+ public Reply remoteReindexResource(Request request, boolean rec) \r
+ throws ProtocolException\r
+ {\r
+ // Check target resource class:\r
+ ResourceReference rr = lookup(request);\r
+ // Handle request:\r
+ try {\r
+ Resource r = rr.lock();\r
+ if(r != null) {\r
+ if (r instanceof org.w3c.tools.resources.DirectoryResource) {\r
+ org.w3c.tools.resources.DirectoryResource dir = \r
+ (org.w3c.tools.resources.DirectoryResource) r;\r
+ dir.reindex(rec);\r
+ return okReply(request);\r
+ } else {\r
+ error(request, "Can't reindex this resource"+\r
+ "(not a DirectoryResource)");\r
+ }\r
+ } else {\r
+ error(request, "Bad request");\r
+ }\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, "Invalid resource");\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // not reached\r
+ return null;\r
+ }\r
+\r
+ public Reply remoteDeleteResource(Request request) \r
+ throws ProtocolException\r
+ {\r
+ // Check target resource class:\r
+ ResourceReference rr = lookup(request);\r
+ // Handle request:\r
+ try {\r
+ Resource r = rr.lock();\r
+ if(r != null) {\r
+ try {\r
+ r.delete();\r
+ } catch (MultipleLockException ex) {\r
+ error(request, ex.getMessage());\r
+ }\r
+ return okReply(request);\r
+ } else {\r
+ error(request, "Bad request");\r
+ }\r
+ } catch (InvalidResourceException ex) {\r
+ error(request, "Invalid resource");\r
+ } finally {\r
+ rr.unlock();\r
+ }\r
+ // not reached\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Perform an extended request\r
+ * @param request the incomming request.\r
+ * @exception ProtocolException if a protocol error occurs \r
+ * @exception ResourceException if a server error occurs\r
+ */\r
+ public Reply extended(Request request) \r
+ throws ProtocolException, ResourceException\r
+ {\r
+ String mth = request.getMethod();\r
+ if ( mth.equals("SET-VALUES") ) {\r
+ checkContentType(request);\r
+ return remoteSetValues(request);\r
+ } else if (mth.equals("LOAD-RESOURCE")) {\r
+ return remoteLoadResource(request);\r
+ } else if (mth.equals("REGISTER-RESOURCE") ) {\r
+ checkContentType(request);\r
+ return remoteRegisterResource(request);\r
+ } else if (mth.equals("DELETE-RESOURCE") ) {\r
+ return remoteDeleteResource(request);\r
+ } else if (mth.equals("REINDEX-RESOURCE") ) {\r
+ return remoteReindexResource(request, true);\r
+ } else if (mth.equals("REINDEX-LOCALLY") ) {\r
+ return remoteReindexResource(request, false);\r
+ } else if (mth.equals("UNREGISTER-FRAME")) {\r
+ checkContentType(request);\r
+ return remoteUnregisterFrame(request);\r
+ } else if (mth.equals("REGISTER-FRAME")) {\r
+ checkContentType(request);\r
+ return remoteRegisterFrame(request);\r
+ } else {\r
+ return super.extended(request);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The default GET method for other king of associated resource\r
+ * @param request The request to handle.\r
+ * @exception ProtocolException If processsing the request failed.\r
+ * @exception ResourceException If the resource got a fatal error.\r
+ */\r
+ protected Reply getOtherResource(Request request) \r
+ throws ProtocolException, ResourceException\r
+ {\r
+ // we don't manage this kind of resource\r
+ Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED) ;\r
+ error.setContent("Method GET not implemented.<br><br>"+\r
+ "The administration server does not use plain "+\r
+ "HTTP but a variant of it. The only tool available "+\r
+ "for now is an application called <b>JigAdmin</b>. "+\r
+ "Please read the documentation.");\r
+ throw new HTTPException (error) ;\r
+ }\r
+\r
+ public BrokerFrame(ServerHandlerManager shm,\r
+ AdminServer admin,\r
+ AdminWriter writer)\r
+ {\r
+ super();\r
+ this.shm = shm;\r
+ this.admin = admin;\r
+ this.writer = writer;\r
+ }\r
+\r
+}\r