001: // BrokerFrame.java
002: // $Id: BrokerFrame.java,v 1.11 2000/08/16 21:37:33 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1997.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.admin;
007:
008: import java.io.ByteArrayInputStream;
009: import java.io.ByteArrayOutputStream;
010: import java.io.IOException;
011: import java.io.InputStream;
012:
013: import java.util.Hashtable;
014: import java.util.StringTokenizer;
015:
016: import java.util.zip.GZIPInputStream;
017:
018: import org.w3c.jigsaw.daemon.ServerHandler;
019: import org.w3c.jigsaw.daemon.ServerHandlerManager;
020:
021: import org.w3c.tools.resources.AttributeHolder;
022: import org.w3c.tools.resources.ContainerInterface;
023: import org.w3c.tools.resources.DirectoryResource;
024: import org.w3c.tools.resources.FramedResource;
025: import org.w3c.tools.resources.InvalidResourceException;
026: import org.w3c.tools.resources.LookupResult;
027: import org.w3c.tools.resources.LookupState;
028: import org.w3c.tools.resources.MultipleLockException;
029: import org.w3c.tools.resources.ProtocolException;
030: import org.w3c.tools.resources.Resource;
031: import org.w3c.tools.resources.ResourceException;
032: import org.w3c.tools.resources.ResourceFrame;
033: import org.w3c.tools.resources.ResourceReference;
034:
035: import org.w3c.www.mime.MimeType;
036:
037: import org.w3c.www.http.HTTP;
038: import org.w3c.www.http.HttpEntityMessage;
039: import org.w3c.www.http.HttpMessage;
040: import org.w3c.www.http.HttpRequestMessage;
041:
042: import org.w3c.jigsaw.http.Client;
043: import org.w3c.jigsaw.http.HTTPException;
044: import org.w3c.jigsaw.http.Reply;
045: import org.w3c.jigsaw.http.Request;
046:
047: import org.w3c.jigsaw.frames.HTTPFrame;
048:
049: import org.w3c.tools.resources.ProtocolException;
050: import org.w3c.tools.resources.ResourceException;
051: import org.w3c.tools.resources.serialization.ResourceDescription;
052: import org.w3c.tools.resources.serialization.AttributeDescription;
053:
054: public class BrokerFrame extends HTTPFrame {
055:
056: class LookupFrameState {
057: private int index;
058: private String components[];
059:
060: void parseQuery(String query) {
061: StringTokenizer st = new StringTokenizer(query, "?");
062: int nbTokens = st.countTokens();
063: components = new String[nbTokens];
064: for (int i = 0; i < nbTokens; i++)
065: components[i] = st.nextToken();
066: index = 0;
067: }
068:
069: public boolean hasMoreComponents() {
070: return index < components.length;
071: }
072:
073: public final String getNextComponent() {
074: return components[index++];
075: }
076:
077: LookupFrameState(String query) {
078: parseQuery(query);
079: }
080: }
081:
082: protected ResourceBroker broker = null;
083:
084: public void registerResource(FramedResource resource) {
085: super .registerResource(resource);
086: if (resource instanceof ResourceBroker)
087: broker = (ResourceBroker) resource;
088: }
089:
090: /**
091: * The object that knows how to write the admin protocol.
092: */
093: protected AdminWriter writer = null;
094:
095: /**
096: * The ServerHandlerManager we export.
097: */
098: protected ServerHandlerManager shm = null;
099: /**
100: * The controlling ServerHandler.
101: */
102: protected AdminServer admin = null;
103:
104: /**
105: * Trigger an HTTP exception.
106: * @param request The request we couldn't fulfill.
107: * @param msg The error message.
108: * @exception ProtocolException Always thrown.
109: */
110:
111: protected void error(Request request, String msg)
112: throws ProtocolException {
113: Reply reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
114: reply.setContent(msg);
115: throw new HTTPException(reply);
116: }
117:
118: protected Reply okReply(Request request, byte bits[]) {
119: Reply reply = request.makeReply(HTTP.OK);
120: reply.setContentType(AdminContext.conftype);
121: if (bits != null) {
122: ByteArrayInputStream in = new ByteArrayInputStream(bits);
123: reply.setContentLength(bits.length);
124: reply.setStream(in);
125: }
126: return reply;
127: }
128:
129: protected Reply okReply(Request request) {
130: return okReply(request, null);
131: }
132:
133: /**
134: * Check that request incomming content type.
135: * @param request The request to check.
136: * @exception ProtocolException If the request type doesn't match admin.
137: */
138:
139: protected void checkContentType(Request request)
140: throws ProtocolException {
141: if (request.getContentType().match(AdminContext.conftype) < 0)
142: error(request, "invalid MIME type: "
143: + request.getContentType());
144: }
145:
146: /**
147: * Get a data input stream out of that request input stream
148: * @param request The request to get data from.
149: * @exception ProtocolException If we couldn't get the request's content.
150: * @return A DataInputStream instance to read the request's content.
151: */
152:
153: protected InputStream getInputStream(Request request)
154: throws ProtocolException {
155: // How fun HTTP/1.1 is, allowing us to double the network traffic :-(
156: // If this is a 1.1 request, send a 100 continue:
157: Client client = request.getClient();
158: if (client != null) {
159: try {
160: client.sendContinue();
161: } catch (IOException ex) {
162: throw new HTTPException(ex.getMessage());
163: }
164: }
165: // Now, only, get the data:
166: try {
167: if (request.hasTransferEncoding("gzip"))
168: return new GZIPInputStream(request.getInputStream());
169: else
170: return request.getInputStream();
171: } catch (IOException ex) {
172: error(request, "invalid request");
173: }
174: // not reached:
175: return null;
176: }
177:
178: /**
179: * Lookup the target of the given request.
180: * @param request The request whose target is to be fetched.
181: * @return A Resource instance.
182: * @exception ProtocolException If the resource couldn't be located.
183: */
184:
185: public ResourceReference lookup(Request request)
186: throws ProtocolException {
187: // Create lookup state and get rid of root resource requests:
188: LookupState ls = null;
189: try {
190: ls = new LookupState(request);
191: } catch (org.w3c.tools.resources.ProtocolException ex) {
192: ex.printStackTrace();
193: throw new HTTPException(ex);
194: }
195: LookupResult lr = new LookupResult(null);
196: ResourceReference rr = null; // cr
197: ls.markInternal();
198: if (!ls.hasMoreComponents())
199: return admin.getRootReference();
200: // Lookup the target resource:
201: String name = ls.getNextComponent();
202: ServerHandler sh = shm.lookupServerHandler(name);
203: if (sh == null) {
204: if (name.equals("realms")) {
205: rr = admin.getRealmCatalogResource();
206: } else if (name.equals("control")) {
207: rr = admin.getControlResource();
208: } else {
209: error(request, "unknown server handler");
210: }
211: } else {
212: // Lookup that resource, from the config resource of that server:
213: rr = sh.getConfigResource();
214: }
215: if (rr != null) {
216: ResourceReference rr_temp = null;
217: while (ls.hasMoreComponents()) {
218: try {
219: if (rr == null)
220: error(request, "url too long");
221: Resource r = rr.lock();
222: if (!(r instanceof ContainerInterface))
223: error(request, "url too long");
224: rr_temp = ((ContainerInterface) r).lookup(ls
225: .getNextComponent());
226: } catch (InvalidResourceException ex) {
227: error(request, "unable to restore resource");
228: } finally {
229: rr.unlock();
230: rr = rr_temp;
231: }
232: }
233: if (rr == null)
234: error(request, "unknown resource");
235: String query = request.getQueryString();
236: if (query != null) {
237: try {
238: Resource r = rr.lock();
239: // Querying a frame !
240: if (!(r instanceof FramedResource))
241: error(request, "not a framed resource");
242: } catch (InvalidResourceException ex) {
243: error(request, "unable to restore resource");
244: } finally {
245: rr.unlock();
246: }
247:
248: //search the right frame
249: LookupFrameState lfs = new LookupFrameState(query);
250:
251: String frameName = null;
252: ResourceReference the_rrf = rr;
253: ResourceReference[] rra = null;
254:
255: while (lfs.hasMoreComponents()) {
256:
257: try {
258: rra = ((FramedResource) the_rrf.lock())
259: .getFramesReference();
260: if (rra == null)
261: error(request, "unknown frame");
262: } catch (InvalidResourceException ex) {
263: error(request, ex.getMessage());
264: } finally {
265: the_rrf.unlock();
266: }
267: the_rrf = null;
268: frameName = lfs.getNextComponent();
269: ResourceReference rrf = null;
270: ResourceFrame frame = null;
271:
272: for (int i = 0; i < rra.length; i++) {
273: rrf = rra[i];
274: try {
275: frame = (ResourceFrame) rrf.lock();
276: if (frame.getIdentifier().equals(frameName)) {
277: the_rrf = rrf;
278: break;
279: }
280: } catch (InvalidResourceException ex) {
281: error(request, ex.getMessage());
282: } finally {
283: rrf.unlock();
284: }
285: }
286: if (the_rrf == null)
287: error(request, "unknown frame");
288: }
289:
290: return the_rrf;
291: } else {
292: // Emit back this resource (after a check):
293: return rr;
294: }
295: }
296: error(request, "unknown resource");
297: // not reached
298: return null;
299: }
300:
301: /**
302: * Set a set of attribute values for the target resource.
303: * @param request The request to handle.
304: * @return A Reply instance.
305: * @exception ProtocolException If some error occurs.
306: */
307:
308: public Reply remoteSetValues(Request request)
309: throws ProtocolException {
310: InputStream in = getInputStream(request);
311: //Get the target resource to act on:
312: ResourceReference rr = lookup(request);
313: try {
314: Resource r = rr.lock();
315: ResourceDescription descr = AdminReader
316: .readResourceDescription(in);
317: AttributeDescription attrs[] = descr
318: .getAttributeDescriptions();
319: for (int i = 0; i < attrs.length; i++) {
320: AttributeDescription ad = attrs[i];
321: r.setValue(ad.getName(), ad.getValue());
322: }
323: } catch (InvalidResourceException irex) {
324: irex.printStackTrace();
325: error(request, "Invalid resource");
326: } catch (IOException ioex) {
327: error(request, "bad request");
328: } catch (AdminProtocolException apex) {
329: error(request, apex.getMessage());
330: } finally {
331: rr.unlock();
332: }
333: // All the changes done, return OK:
334: return okReply(request);
335: }
336:
337: /**
338: * Return a resource back to the client.
339: * @param request The request to handle.
340: * @return A Reply instance.
341: * @exception ProtocolException If some error occurs.
342: */
343:
344: public Reply remoteLoadResource(Request request)
345: throws ProtocolException {
346: ResourceReference rr = lookup(request);
347:
348: // This request has no content
349: ByteArrayOutputStream bout = new ByteArrayOutputStream();
350:
351: try {
352: Resource r = rr.lock();
353: writer.writeResource(r, bout);
354: } catch (IOException ex) {
355: error(request, "bad request");
356: } catch (InvalidResourceException ex) {
357: error(request, "Invalid resource");
358: } catch (AdminProtocolException ex) {
359: error(request, ex.getMessage());
360: } finally {
361: rr.unlock();
362: }
363: // Setup the reply:
364: return okReply(request, bout.toByteArray());
365: }
366:
367: public Reply remoteRegisterFrame(Request request)
368: throws ProtocolException {
369: ResourceReference rr = lookup(request);
370: try {
371: Resource r = rr.lock();
372: if (!(r instanceof FramedResource))
373: error(request, "can't add frame to non-framed resource");
374: // Handle the request:
375: try {
376: InputStream in = getInputStream(request);
377: ResourceDescription rd = AdminReader
378: .readResourceDescription(in);
379: String cls = rd.getClassName();
380: String id = rd.getIdentifier();
381: // Create the frame:
382: ResourceFrame frame = null;
383: try {
384: frame = (ResourceFrame) Class.forName(cls)
385: .newInstance();
386: } catch (Exception ex) {
387: error(request, "invalid frame class " + cls);
388: }
389: // Register the frame:
390: Hashtable defs = new Hashtable(3);
391: if ((id != null) && !id.equals("")) {
392: defs.put("identifier", id);
393: }
394: ((FramedResource) r).registerFrame(frame, defs);
395: // Send back the whole resource (inclding new frame):
396: ByteArrayOutputStream bout = new ByteArrayOutputStream();
397: writer.writeResource(frame, bout);
398: return okReply(request, bout.toByteArray());
399: } catch (IOException ioex) {
400: error(request, "bad request");
401: } catch (AdminProtocolException apex) {
402: error(request, apex.getMessage());
403: }
404: } catch (InvalidResourceException irex) {
405: error(request, "invalid resource");
406: } finally {
407: rr.unlock();
408: }
409: // not reached:
410: return null;
411: }
412:
413: public Reply remoteUnregisterFrame(Request request)
414: throws ProtocolException {
415: ResourceReference rr = lookup(request);
416: try {
417: Resource r = rr.lock();
418: if (!(r instanceof FramedResource)) {
419: error(request,
420: "Can't unregister frames from a non-framed"
421: + " resource");
422: }
423: try {
424: InputStream in = getInputStream(request);
425: ResourceDescription rd = AdminReader
426: .readResourceDescription(in);
427: String identifier = rd.getIdentifier();
428: // find the indentifier
429: ResourceFrame f[] = ((FramedResource) r).getFrames();
430: for (int i = 0; i < f.length; i++)
431: if (f[i].getIdentifier().equals(identifier)) {
432: ((FramedResource) r).unregisterFrame(f[i]);
433: return okReply(request);
434: }
435: error(request, "Frame " + identifier
436: + " not registered");
437: } catch (IOException ex) {
438: error(request, "bad request");
439: } catch (AdminProtocolException apex) {
440: error(request, apex.getMessage());
441: }
442: } catch (InvalidResourceException ex2) {
443: error(request, "invalid resource");
444: } finally {
445: rr.unlock();
446: }
447: // Not reached
448: return null;
449: }
450:
451: public Reply remoteRegisterResource(Request request)
452: throws ProtocolException {
453: // Check target resource class:
454: ResourceReference rr = lookup(request);
455: try {
456: Resource r = rr.lock();
457: if (!(r instanceof ContainerInterface))
458: error(request, "can't add child in non-container");
459: // Handle request:
460: try {
461: InputStream in = getInputStream(request);
462: ResourceDescription rd = AdminReader
463: .readResourceDescription(in);
464: String cls = rd.getClassName();
465: String id = rd.getIdentifier();
466: // Create the resource:
467: Resource child = null;
468: try {
469: child = (Resource) Class.forName(cls).newInstance();
470: } catch (Exception ex) {
471: error(request, "invalid resource class " + cls);
472: }
473: // Add it to the container:
474: try {
475: ((ContainerInterface) r).registerResource(id,
476: child, null);
477: } catch (InvalidResourceException ex) {
478: error(request, ex.getMessage());
479: }
480: // Write back the new resource:
481: ByteArrayOutputStream bout = new ByteArrayOutputStream();
482: writer.writeResource(child, bout);
483: return okReply(request, bout.toByteArray());
484: } catch (IOException ex) {
485: error(request, "bad request");
486: } catch (AdminProtocolException apex) {
487: error(request, apex.getMessage());
488: }
489: } catch (InvalidResourceException ex) {
490: error(request, "Invalid resource");
491: } finally {
492: rr.unlock();
493: }
494: // not reached:
495: return null;
496: }
497:
498: public Reply remoteReindexResource(Request request, boolean rec)
499: throws ProtocolException {
500: // Check target resource class:
501: ResourceReference rr = lookup(request);
502: // Handle request:
503: try {
504: Resource r = rr.lock();
505: if (r != null) {
506: if (r instanceof org.w3c.tools.resources.DirectoryResource) {
507: org.w3c.tools.resources.DirectoryResource dir = (org.w3c.tools.resources.DirectoryResource) r;
508: dir.reindex(rec);
509: return okReply(request);
510: } else {
511: error(request, "Can't reindex this resource"
512: + "(not a DirectoryResource)");
513: }
514: } else {
515: error(request, "Bad request");
516: }
517: } catch (InvalidResourceException ex) {
518: error(request, "Invalid resource");
519: } finally {
520: rr.unlock();
521: }
522: // not reached
523: return null;
524: }
525:
526: public Reply remoteDeleteResource(Request request)
527: throws ProtocolException {
528: // Check target resource class:
529: ResourceReference rr = lookup(request);
530: // Handle request:
531: try {
532: Resource r = rr.lock();
533: if (r != null) {
534: try {
535: r.delete();
536: } catch (MultipleLockException ex) {
537: error(request, ex.getMessage());
538: }
539: return okReply(request);
540: } else {
541: error(request, "Bad request");
542: }
543: } catch (InvalidResourceException ex) {
544: error(request, "Invalid resource");
545: } finally {
546: rr.unlock();
547: }
548: // not reached
549: return null;
550: }
551:
552: /**
553: * Perform an extended request
554: * @param request the incomming request.
555: * @exception ProtocolException if a protocol error occurs
556: * @exception ResourceException if a server error occurs
557: */
558: public Reply extended(Request request) throws ProtocolException,
559: ResourceException {
560: String mth = request.getMethod();
561: if (mth.equals("SET-VALUES")) {
562: checkContentType(request);
563: return remoteSetValues(request);
564: } else if (mth.equals("LOAD-RESOURCE")) {
565: return remoteLoadResource(request);
566: } else if (mth.equals("REGISTER-RESOURCE")) {
567: checkContentType(request);
568: return remoteRegisterResource(request);
569: } else if (mth.equals("DELETE-RESOURCE")) {
570: return remoteDeleteResource(request);
571: } else if (mth.equals("REINDEX-RESOURCE")) {
572: return remoteReindexResource(request, true);
573: } else if (mth.equals("REINDEX-LOCALLY")) {
574: return remoteReindexResource(request, false);
575: } else if (mth.equals("UNREGISTER-FRAME")) {
576: checkContentType(request);
577: return remoteUnregisterFrame(request);
578: } else if (mth.equals("REGISTER-FRAME")) {
579: checkContentType(request);
580: return remoteRegisterFrame(request);
581: } else {
582: return super .extended(request);
583: }
584: }
585:
586: /**
587: * The default GET method for other king of associated resource
588: * @param request The request to handle.
589: * @exception ProtocolException If processsing the request failed.
590: * @exception ResourceException If the resource got a fatal error.
591: */
592: protected Reply getOtherResource(Request request)
593: throws ProtocolException, ResourceException {
594: // we don't manage this kind of resource
595: Reply error = request.makeReply(HTTP.NOT_IMPLEMENTED);
596: error.setContent("Method GET not implemented.<br><br>"
597: + "The administration server does not use plain "
598: + "HTTP but a variant of it. The only tool available "
599: + "for now is an application called <b>JigAdmin</b>. "
600: + "Please read the documentation.");
601: throw new HTTPException(error);
602: }
603:
604: public BrokerFrame(ServerHandlerManager shm, AdminServer admin,
605: AdminWriter writer) {
606: super();
607: this.shm = shm;
608: this.admin = admin;
609: this.writer = writer;
610: }
611:
612: }
|