001: // PlainRemoteResource.java
002: // $Id: PlainRemoteResource.java,v 1.31 2000/08/16 21:37:34 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: import java.io.OutputStream;
013: import java.io.PrintStream;
014:
015: import java.net.MalformedURLException;
016: import java.net.URL;
017: import java.net.URLEncoder;
018:
019: import java.util.zip.GZIPInputStream;
020: import java.util.zip.GZIPOutputStream;
021:
022: import org.w3c.tools.resources.Attribute;
023: import org.w3c.tools.resources.SimpleAttribute;
024: import org.w3c.tools.resources.ArrayAttribute;
025:
026: import org.w3c.tools.resources.serialization.AttributeDescription;
027: import org.w3c.tools.resources.serialization.EmptyDescription;
028: import org.w3c.tools.resources.serialization.ResourceDescription;
029:
030: import org.w3c.www.protocol.http.HttpManager;
031: import org.w3c.www.protocol.http.Reply;
032: import org.w3c.www.protocol.http.Request;
033:
034: public class PlainRemoteResource implements RemoteResource {
035: private static final boolean debug = false;
036: /**
037: * The client side admin context
038: */
039: protected AdminContext admin = null;
040: /**
041: * The remote resource set of attributes.
042: */
043: protected AttributeDescription attributes[];
044: /**
045: * The remote resource attribute values.
046: */
047: protected Object values[] = null;
048: /**
049: * Is that resource a container resource ?
050: */
051: protected boolean iscontainer = false;
052: /**
053: * Is that resource a indexers catalog ?
054: */
055: protected boolean isindexerscatalog = false;
056: /**
057: * Is that resource a directory resource ?
058: */
059: protected boolean isDirectoryResource = false;
060: /**
061: * Is that resource a framed resource ?
062: */
063: protected boolean isframed = false;
064: /**
065: * The name of that resource (ie it's identifier attribute).
066: */
067: protected String identifier = null;
068: /**
069: * The name of the parent of that resource, as an URL.
070: */
071: protected URL parent = null;
072: /**
073: * The admin URL for the wrapped resource.
074: */
075: protected URL url = null;
076: /**
077: * Set of attached frames.
078: */
079: protected RemoteResource frames[] = null;
080: /**
081: * Our description
082: */
083: protected ResourceDescription description = null;
084:
085: protected Request createRequest() {
086: Request request = admin.http.createRequest();
087: request.setURL(url);
088: if (!debug) {
089: request.setValue("TE", "gzip");
090: }
091: return request;
092: }
093:
094: protected InputStream getInputStream(Reply reply)
095: throws IOException {
096: if (reply.hasTransferEncoding("gzip"))
097: return new GZIPInputStream(reply.getInputStream());
098: else
099: return reply.getInputStream();
100: }
101:
102: protected void setFrames(RemoteResource frames[]) {
103: this .isframed = true;
104: this .frames = frames;
105: }
106:
107: /**
108: * Get the target resource class hierarchy.
109: * This method will return the class hierarchy as an array of String. The
110: * first string in the array is the name of the resource class itself, the
111: * last string will always be <em>java.lang.Object</em>.
112: * @return A String array givimg the target resource's class description.
113: * @exception RemoteAccessException If somenetwork failure occured.
114: */
115:
116: public String[] getClassHierarchy() throws RemoteAccessException {
117: return description.getClassHierarchy();
118: }
119:
120: /**
121: * Reindex the resource's children if this resource is a DirectoryResource.
122: * @exception RemoteAccessException If it's not a DirectoryResource
123: */
124: public void reindex(boolean rec) throws RemoteAccessException {
125: if (isDirectoryResource()) {
126: try {
127: Request req = createRequest();
128: // Prepare the request:
129: if (rec) {
130: req.setMethod("REINDEX-RESOURCE");
131: } else {
132: req.setMethod("REINDEX-LOCALLY");
133: }
134: // Run it:
135: Reply rep = admin.runRequest(req);
136: } catch (RemoteAccessException rae) {
137: throw rae;
138: } catch (Exception ex) {
139: ex.printStackTrace();
140: throw new RemoteAccessException(ex.getMessage());
141: }
142: } else {
143: throw new RemoteAccessException(
144: "Error, can't reindex! This is "
145: + "not a DirectoryResource.");
146: }
147: }
148:
149: /**
150: * Delete that resource, and detach it from its container.
151: * @exception RemoteAccessException If somenetwork failure occured.
152: */
153: public void delete() throws RemoteAccessException {
154: try {
155: Request req = createRequest();
156: // Prepare the request:
157: req.setMethod("DELETE-RESOURCE");
158: // Run it:
159: Reply rep = admin.runRequest(req);
160: } catch (RemoteAccessException rae) {
161: throw rae;
162: } catch (Exception ex) {
163: ex.printStackTrace();
164: throw new RemoteAccessException(ex.getMessage());
165: }
166: }
167:
168: /**
169: * Get the target resource list of attributes.
170: * This method returns the target resource attributes description. The
171: * resulting array contains instances of the Attribute class, one item
172: * per described attributes.
173: * <p>Even though this returns all the attribute resources, only the
174: * ones that are advertized as being editable can be set through this
175: * interface.
176: * @return An array of Attribute.
177: * @exception RemoteAccessException If somenetwork failure occured.
178: */
179: public synchronized AttributeDescription[] getAttributes()
180: throws RemoteAccessException {
181: return description.getAttributeDescriptions();
182: }
183:
184: /**
185: * @param name The attribute whose value is to be fetched, encoded as
186: * its name.
187: * @exception RemoteAccessException If somenetwork failure occured.
188: */
189:
190: public Object getValue(String attr) throws RemoteAccessException {
191: if (attr.equals("identifier")) {
192: return identifier;
193: }
194: String attrs[] = new String[1];
195: attrs[0] = attr;
196: return getValues(attrs)[0];
197: }
198:
199: protected AttributeDescription lookupAttribute(String name) {
200: AttributeDescription attds[] = description
201: .getAttributeDescriptions();
202: for (int i = 0; i < attds.length; i++) {
203: AttributeDescription ad = attds[i];
204: if (ad.getName().equals(name))
205: return ad;
206: }
207: return null;
208: }
209:
210: /**
211: * @param attrs The (ordered) set of attributes whose value is to be
212: * fetched.
213: * @return An (ordered) set of values, one per queried attribute.
214: * @exception RemoteAccessException If somenetwork failure occured.
215: */
216: public Object[] getValues(String attrs[])
217: throws RemoteAccessException {
218: Object values[] = new Object[attrs.length];
219: for (int i = 0; i < attrs.length; i++) {
220: AttributeDescription ad = lookupAttribute(attrs[i]);
221: if (ad != null) {
222: values[i] = ad.getValue();
223: } else {
224: values[i] = null;
225: }
226: }
227: return values;
228: }
229:
230: /**
231: * @param attr The attribute to set, encoded as it's name.
232: * @param value The new value for that attribute.
233: * @exception RemoteAccessException If somenetwork failure occured.
234: */
235:
236: public void setValue(String attr, Object value)
237: throws RemoteAccessException {
238: String attrs[] = new String[1];
239: Object vals[] = new Object[1];
240: attrs[0] = attr;
241: vals[0] = value;
242: setValues(attrs, vals);
243: }
244:
245: /**
246: * Set a set of attribute values in one shot.
247: * This method guarantees that either all setting is done, or none of
248: * them are.
249: * @param attrs The (ordered) list of attribute to set, encoded as their
250: * names.
251: * @param values The (ordered) list of values, for each of the above
252: * attributes.
253: * @exception RemoteAccessException If somenetwork failure occured.
254: */
255: public void setValues(String names[], Object values[])
256: throws RemoteAccessException {
257: String newId = null;
258: boolean change = false;
259:
260: AttributeDescription attrs[] = new AttributeDescription[names.length];
261:
262: for (int i = 0; i < names.length; i++) {
263: AttributeDescription ad = lookupAttribute(names[i]);
264: if (ad != null) {
265: ad.setValue(values[i]);
266: attrs[i] = ad;
267: }
268: if (names[i].equals("identifier")) {
269: change = true;
270: newId = (String) values[i];
271: }
272: }
273:
274: ResourceDescription descr = description.getClone(attrs);
275:
276: try {
277: ByteArrayOutputStream bout = new ByteArrayOutputStream();
278: OutputStream out;
279: if (debug) {
280: out = bout;
281: } else {
282: out = new GZIPOutputStream(bout);
283: }
284: admin.writer.writeResourceDescription(descr, out);
285: byte bits[] = bout.toByteArray();
286:
287: Request req = createRequest();
288: req.setMethod("SET-VALUES");
289: req.setContentType(admin.conftype);
290: req.setContentLength(bits.length);
291: if (!debug) {
292: req.addTransferEncoding("gzip");
293: }
294: req.setOutputStream(new ByteArrayInputStream(bits));
295:
296: // Run that request:
297: Reply rep = admin.runRequest(req);
298: } catch (RemoteAccessException rae) {
299: throw rae;
300: } catch (Exception ex) {
301: ex.printStackTrace();
302: throw new RemoteAccessException("exception "
303: + ex.getMessage());
304: }
305:
306: if (change) {
307: identifier = new String(newId);
308: try {
309: //if (parent != null) {
310: if (!isFrame()) {
311: if (iscontainer)
312: url = new URL(parent.toString() + identifier
313: + "/");
314: else
315: url = new URL(parent.toString() + identifier);
316: // update frames url
317: updateURL(new URL(parent.toString() + identifier));
318: } else {
319: String oldFile = url.getFile();
320: int index = oldFile.lastIndexOf('?');
321: String newFile = oldFile.substring(0, index);
322: updateURL(new URL(url, newFile));
323: }
324: } catch (MalformedURLException ex) {
325: ex.printStackTrace();
326: }
327: }
328: return;
329: }
330:
331: public void updateURL(URL parentURL) {
332: if (isFrame()) {
333: try {
334: url = new URL(parentURL, parentURL.getFile() + "?"
335: + identifier);
336: } catch (MalformedURLException ex) {
337: return;
338: }
339: }
340: //update frames URLs
341: if (frames != null) {
342: for (int i = 0; i < frames.length; i++) {
343: frames[i].updateURL(url);
344: }
345: }
346: }
347:
348: /**
349: * @exception RemoteAccessException If somenetwork failure occured.
350: */
351:
352: public boolean isContainer() throws RemoteAccessException {
353: // a Hack to avoid multiple sub-trees under the main root resource
354: if (identifier != null) {
355: if (identifier.equals("root"))
356: return false;
357: if (identifier.equals("control")) {
358: String classname = getClassHierarchy()[0];
359: if (classname
360: .equals("org.w3c.jigsaw.http.ControlResource"))
361: return false;
362: }
363: }
364: return iscontainer;
365: }
366:
367: /**
368: * @exception RemoteAccessException If somenetwork failure occured.
369: */
370:
371: public boolean isIndexersCatalog() throws RemoteAccessException {
372: return isindexerscatalog;
373: }
374:
375: /**
376: * Is is a DirectoryResource
377: * @exception RemoteAccessException If somenetwork failure occured.
378: */
379: public boolean isDirectoryResource() throws RemoteAccessException {
380: if (identifier != null) {
381: if (identifier.equals("root"))
382: return false;
383: }
384: return isDirectoryResource;
385: }
386:
387: /**
388: * @exception RemoteAccessException If somenetwork failure occured.
389: */
390: public String[] enumerateResourceIdentifiers()
391: throws RemoteAccessException {
392: if (!iscontainer)
393: throw new RuntimeException("not a container");
394: try {
395: update();
396: return description.getChildren();
397: } catch (Exception ex) {
398: ex.printStackTrace();
399: throw new RemoteAccessException("http " + ex.getMessage());
400: }
401: }
402:
403: /**
404: * @exception RemoteAccessException If somenetwork failure occured.
405: */
406:
407: public RemoteResource loadResource(String identifier)
408: throws RemoteAccessException {
409: try {
410: // Prepare the request:
411: Request req = createRequest();
412: req.setMethod("LOAD-RESOURCE");
413: req.setURL(new URL(url.toString()
414: + URLEncoder.encode(identifier)));
415: // Run it:
416: Reply rep = admin.runRequest(req);
417: // Decode the reply:
418: InputStream in = getInputStream(rep);
419: RemoteResource ret = admin.reader.readResource(url,
420: identifier, in);
421: in.close();
422: return ret;
423: } catch (RemoteAccessException rae) {
424: throw rae;
425: } catch (Exception ex) {
426: ex.printStackTrace();
427: throw new RemoteAccessException(ex.getMessage());
428: }
429: }
430:
431: /**
432: * Register a new resource within this container.
433: * @param id The identifier of the resource to be created.
434: * @param classname The name of the class of the resource to be added.
435: * @exception RemoteAccessException If somenetwork failure occured.
436: */
437: public RemoteResource registerResource(String id, String classname)
438: throws RemoteAccessException {
439: ResourceDescription rd = new EmptyDescription(classname, id);
440: try {
441: Request req = createRequest();
442: // Prepare the request:
443: req.setMethod("REGISTER-RESOURCE");
444: req.setContentType(admin.conftype);
445: req.setURL(url);
446: ByteArrayOutputStream bout = new ByteArrayOutputStream();
447: OutputStream out;
448: if (debug) {
449: out = bout;
450: } else {
451: out = new GZIPOutputStream(bout);
452: }
453: admin.writer.writeResourceDescription(rd, out);
454: byte bits[] = bout.toByteArray();
455: req.setContentLength(bits.length);
456: if (!debug) {
457: req.addTransferEncoding("gzip");
458: }
459: req.setOutputStream(new ByteArrayInputStream(bits));
460: // Run it:
461: Reply rep = admin.runRequest(req);
462:
463: // Decode the result:
464: rd = admin.reader
465: .readResourceDescription(getInputStream(rep));
466: RemoteResource ret = new PlainRemoteResource(admin, url, rd
467: .getIdentifier(), rd);
468:
469: return ret;
470: } catch (RemoteAccessException rae) {
471: throw rae;
472: } catch (Exception ex) {
473: ex.printStackTrace();
474: throw new RemoteAccessException(ex.getMessage());
475: }
476: }
477:
478: /**
479: * Is this resource a framed resource ?
480: * @return A boolean, <strong>true</strong> if the resource is framed
481: * and it currently has some frames attached, <strong>false</strong>
482: * otherwise.
483: * @exception RemoteAccessException If somenetwork failure occured.
484: */
485:
486: public boolean isFramed() throws RemoteAccessException {
487: return isframed;
488: }
489:
490: /**
491: * Get the frames attached to that resource.
492: * Each frame is itself a resource, so it is returned as an instance of
493: * a remote resource.
494: * @return A (posssibly <strong>null</strong>) array of frames attached
495: * to that resource.
496: * @exception RemoteAccessException If somenetwork failure occured.
497: */
498:
499: public RemoteResource[] getFrames() throws RemoteAccessException {
500: if (!isframed)
501: throw new RuntimeException("not a framed resource");
502: return frames;
503: }
504:
505: /**
506: * Unregister a given frame from that resource.
507: * @param frame The frame to unregister.
508: * @exception RemoteAccessException If somenetwork failure occured.
509: */
510: public void unregisterFrame(RemoteResource frame)
511: throws RemoteAccessException {
512: if (!isframed)
513: throw new RuntimeException("not a framed resource");
514: if (frames == null)
515: throw new RuntimeException("this resource has no frames");
516: // Remove it:
517: String id = null;
518: try {
519: id = ((PlainRemoteResource) frame).identifier;
520: Request req = createRequest();
521: // Prepare the request:
522: req.setMethod("UNREGISTER-FRAME");
523: req.setContentType(admin.conftype);
524: req.setURL(url);
525:
526: ResourceDescription dframe = new EmptyDescription("", id);
527: ByteArrayOutputStream bout = new ByteArrayOutputStream();
528: OutputStream out;
529: if (debug) {
530: out = bout;
531: } else {
532: out = new GZIPOutputStream(bout);
533: }
534: admin.writer.writeResourceDescription(dframe, out);
535: byte bits[] = bout.toByteArray();
536: req.setContentLength(bits.length);
537: if (!debug) {
538: req.addTransferEncoding("gzip");
539: }
540: req.setOutputStream(new ByteArrayInputStream(bits));
541:
542: // Run it:
543: Reply rep = admin.runRequest(req);
544: } catch (RemoteAccessException rae) {
545: throw rae;
546: } catch (Exception ex) {
547: ex.printStackTrace();
548: throw new RemoteAccessException(ex.getMessage());
549: }
550: RemoteResource f[] = new RemoteResource[frames.length - 1];
551: int j = 0;
552: for (int i = 0; i < frames.length; i++) {
553: if (((PlainRemoteResource) frames[i]).identifier.equals(id)) {
554: // got it, copy the end of the array
555: System.arraycopy(frames, i + 1, f, j, frames.length - i
556: - 1);
557: frames = f;
558: return;
559: } else {
560: try {
561: f[j++] = frames[i];
562: } catch (ArrayIndexOutOfBoundsException ex) {
563: return; // no modifications, return
564: }
565: }
566: }
567: }
568:
569: public boolean isFrame() {
570: return isFrameURL(url);
571: }
572:
573: protected boolean isFrameURL(URL furl) {
574: return (furl.toString().lastIndexOf('?') != -1);
575: }
576:
577: /**
578: * Attach a new frame to that resource.
579: * @param identifier The name for this frame (if any).
580: * @param clsname The name of the frame's class.
581: * @return A remote handle to the (remotely) created frame instance.
582: * @exception RemoteAccessException If somenetwork failure occured.
583: */
584:
585: public RemoteResource registerFrame(String id, String classname)
586: throws RemoteAccessException {
587: // Can we add new resources ?
588: if (!isframed)
589: throw new RuntimeException("not a framed resource");
590: try {
591: Request req = createRequest();
592: // Prepare the request:
593: req.setMethod("REGISTER-FRAME");
594: req.setContentType(admin.conftype);
595:
596: ResourceDescription dframe = new EmptyDescription(
597: classname, id);
598: ByteArrayOutputStream bout = new ByteArrayOutputStream();
599: OutputStream out;
600: if (debug) {
601: out = bout;
602: } else {
603: out = new GZIPOutputStream(bout);
604: }
605: admin.writer.writeResourceDescription(dframe, out);
606: byte bits[] = bout.toByteArray();
607: req.setContentLength(bits.length);
608: if (!debug) {
609: req.addTransferEncoding("gzip");
610: }
611: req.setOutputStream(new ByteArrayInputStream(bits));
612:
613: // Run it:
614: Reply rep = admin.runRequest(req);
615: dframe = admin.reader
616: .readResourceDescription(getInputStream(rep));
617: id = dframe.getIdentifier();
618: URL url = null;
619: if (isFrame()) {
620: url = new URL(this .url, this .url.getFile() + "?" + id);
621: } else {
622: url = new URL(parent.toString() + identifier + "?" + id);
623: }
624: PlainRemoteResource frame = new PlainRemoteResource(admin,
625: parent, url, id, dframe);
626: //insert it in the frame array
627: if (frames != null) {
628: RemoteResource nf[] = new RemoteResource[frames.length + 1];
629: System.arraycopy(frames, 0, nf, 0, frames.length);
630: nf[frames.length] = frame;
631: frames = nf;
632: } else {
633: frames = new RemoteResource[1];
634: frames[0] = frame;
635: }
636: return frame;
637: } catch (RemoteAccessException rae) {
638: throw rae;
639: } catch (Exception ex) {
640: ex.printStackTrace();
641: throw new RemoteAccessException(ex.getMessage());
642: }
643: }
644:
645: protected void createRemoteFrames() {
646: ResourceDescription dframes[] = description
647: .getFrameDescriptions();
648: int len = dframes.length;
649: this .frames = new RemoteResource[len];
650: for (int i = 0; i < len; i++) {
651: ResourceDescription dframe = dframes[i];
652: String frameid = dframe.getIdentifier();
653: URL url = null;
654: try {
655: if (isFrame()) {
656: url = new URL(this .url, this .url.getFile() + "?"
657: + frameid);
658: } else {
659: url = new URL(parent.toString() + identifier + "?"
660: + frameid);
661: }
662: } catch (MalformedURLException ex) {
663: ex.printStackTrace();
664: url = null;
665: }
666: PlainRemoteResource frame = new PlainRemoteResource(admin,
667: parent, url, frameid, dframe);
668: frames[i] = frame;
669: }
670: }
671:
672: /**
673: * Dump that resource to the given output stream.
674: * @param prt A print stream to dump to.
675: * @exception RemoteAccessException If somenetwork failure occured.
676: */
677:
678: public void dump(PrintStream prt) throws RemoteAccessException {
679: // Dump the class hierarchy:
680: System.out.println("+ classes: ");
681: String classes[] = getClassHierarchy();
682: for (int i = 0; i < classes.length; i++)
683: System.out.println("\t" + classes[i]);
684: // Any frames available ?
685: if (isframed && (frames != null)) {
686: System.out.println("+ " + frames.length + " frames.");
687: for (int i = 0; i < frames.length; i++) {
688: prt.println("\t"
689: + ((PlainRemoteResource) frames[i]).identifier);
690: ((PlainRemoteResource) frames[i]).dump(prt);
691: }
692: }
693: // Run the query, and display results:
694: System.out.println("+ attributes: ");
695: AttributeDescription attrs[] = getAttributes();
696: for (int i = 0; i < attrs.length; i++) {
697: Attribute att = attrs[i].getAttribute();
698: if (att.checkFlag(Attribute.EDITABLE)) {
699: Object value = attrs[i].getValue();
700: if (value != null) {
701: if (att instanceof SimpleAttribute) {
702: SimpleAttribute sa = (SimpleAttribute) att;
703: prt.println("\t" + att.getName() + "="
704: + sa.pickle(attrs[i].getValue()));
705: } else if (att instanceof ArrayAttribute) {
706: ArrayAttribute aa = (ArrayAttribute) att;
707: String values[] = aa
708: .pickle(attrs[i].getValue());
709: prt.print("\t" + att.getName() + "=");
710: for (int j = 0; j < values.length; j++) {
711: if (j != 0)
712: prt.print(" | ");
713: prt.print(values[j]);
714: }
715: }
716: } else
717: prt.println("\t" + att.getName() + " <undef>");
718: }
719: }
720: }
721:
722: /**
723: * reload the RemoteResource.
724: */
725: protected void update() throws RemoteAccessException {
726: try {
727: Request req = createRequest();
728: // Prepare the request:
729: req.setMethod("LOAD-RESOURCE");
730: // Run it:
731: Reply rep = admin.runRequest(req);
732: InputStream in = getInputStream(rep);
733: this .description = admin.reader.readResourceDescription(in);
734: createRemoteFrames();
735: } catch (RemoteAccessException rae) {
736: throw rae;
737: } catch (Exception ex) {
738: throw new RemoteAccessException(ex.getMessage());
739: }
740: }
741:
742: PlainRemoteResource(AdminContext admin, URL parent,
743: String identifier, ResourceDescription description) {
744: this (admin, parent, null, identifier, description);
745: }
746:
747: PlainRemoteResource(AdminContext admin, URL parent, URL url,
748: String identifier, ResourceDescription description) {
749: this .admin = admin;
750: this .parent = parent;
751: this .identifier = identifier;
752: this .description = description;
753:
754: String classes[] = description.getClassesAndInterfaces();
755: for (int i = 0; i < classes.length; i++) {
756: if (classes[i]
757: .equals("org.w3c.tools.resources.ContainerInterface"))
758: iscontainer = true;
759: if (classes[i]
760: .equals("org.w3c.tools.resources.FramedResource"))
761: isframed = true;
762: if (classes[i]
763: .equals("org.w3c.tools.resources.DirectoryResource"))
764: isDirectoryResource = true;
765: if (classes[i]
766: .equals("org.w3c.tools.resources.indexer.IndexersCatalog"))
767: isindexerscatalog = true;
768: }
769:
770: if (url == null) {
771: if (parent != null) {
772: String encoded = ((identifier == null) ? identifier
773: : URLEncoder.encode(identifier));
774: String urlpart = iscontainer ? encoded + "/" : encoded;
775: try {
776: this .url = ((identifier != null) ? new URL(parent
777: .toString()
778: + urlpart) : parent);
779: } catch (MalformedURLException ex) {
780: ex.printStackTrace();
781: this.url = null;
782: }
783: } else {
784: this.url = null;
785: }
786: } else {
787: this.url = url;
788: }
789: createRemoteFrames();
790: }
791:
792: }
|