package net.matrix_rad.skang; import java.lang.*; // Always needed, usually imported by default. import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import net.matrix_rad.security.ACL; import net.matrix_rad.security.Who; import net.matrix_rad.skang.*; import net.matrix_rad.squeal.Stuff; /** Every thing that is managed by Skang. */ public class Thing extends Object implements LeafLike, Struct { public final static String[] CLASS_SOURCE_FILES = { "ThingSpace.java", "SkangException.java", "MethodFailedException.java", "NotComponentException.java", "ThingNotFoundException.java", }; public Object thing = null; // The thing itself. public String name = null; // Name of the thing. public int number = 0; // Thing's number. public Skang skang = null; // The owning object. public String owner = null; // The owning object. public Class clas = null; // Class object of the thing. public String type = null; // Class of the thing. public String realType = null; // Real Class of the thing. protected ACL acl = null; // Access Control List. // Change this to null = late binder awaiting the real thing. // Change this to "" = not created by an add command. public String text = null; // The text of the thing. public String action = null; // An optional action. public String tell = null; // The original add command. public Method get = null; // A getting routine. public Method isValid = null; // An optional validation method. public Vector errors = null; // A list of errors returned from the validation method. public Method set = null; // A setting routine. public Method append = null; // An appending routine. public Method remove = null; // A removing routine. public boolean isReadOnly = false; // Is this thing read only? public boolean isServer = false; // Is this thing server side only? public boolean isStub = false; // Does this thing represent a real thing across the network? public boolean isStubbed = false; // Is this thing represented by a stub thing across the network? public short hasCrashed = 0; // How many times has this thing crashed? public ThingSpace myRoot = null; // Which ThingSpace are we in. public final static int DO_NOWHERE = 0; public final static int DO_HERE = 1; public final static int DO_APPLET = 2; public final static int DO_SERVLET = 3; public String[] toStrings() { String[] ret = new String[13]; int i = 0; ret[i++] = "Name : " + name; ret[i++] = "Class : " + type; ret[i++] = "Type : " + realType; ret[i++] = "ACL : " + acl; ret[i++] = "Number : " + number; ret[i++] = "Owner : " + owner; ret[i++] = "Tell : " + tell; ret[i++] = "Text : " + text; ret[i++] = "Action : " + action; ret[i++] = "Crash : " + hasCrashed; ret[i++] = (fromServer('w', null)) ? "Postable" : "Not postable"; ret[i++] = isReadOnly ? "Read only" : "Writable"; ret[i++] = isServer ? "Server only" : "Client or server"; return ret; } public void prune() { try {remove.invoke(this, null);} catch (Exception e) {;} } public String action() { return null; } public Object security() { // Should check the ACL. return this; } public Object toValue(Leaf aLeaf) { return aLeaf.value; } public BonsaiTree toTree() { BonsaiTree result = new BonsaiTree(name); String[] strings = toStrings(); for (int i = 0; i < strings.length; i++) result.add("" + i, strings[i]); return result; } public String toBigString() { String result = this.toString() + "\n"; String[] strings = toStrings(); for (int i = 0; i < strings.length; i++) result += " " + strings[i] + "\n"; return result; } protected Thing() { errors = new Vector(); } protected Thing(ThingSpace aRoot, String aName, String aType, Skang anOwner) { this(); myRoot = aRoot; name = aName; skang = anOwner; if (skang != null) owner = skang.getClass().getName(); if (aName == aType) type = aType; if (thing != null) { clas = thing.getClass(); realType = clas.getName(); } if (aType != null) type = aType; else type = realType; if (skang != null) owner = skang.getClass().getName(); newRoot(myRoot, true); //What.ERRLN("ADDED THING " + aThing.name + " " + aThing.type); } public void newRoot(ThingSpace aRoot, boolean doCollisions) { myRoot = aRoot; String baseName = name; // if (!type.toUpperCase().equals(Widget.type.toUpperCase())) if ((!type.toUpperCase().equals(Widget.type.toUpperCase())) && (!type.toUpperCase().equals(Stuff.type.toUpperCase()))) { int pos = baseName.lastIndexOf('.'); if (pos != -1) baseName = baseName.substring(pos + 1); } Leaf leaf = myRoot.get(type.toUpperCase() + "." + baseName); if (doCollisions) { if (leaf != null) { if (leaf.getValue() instanceof Thing) { Collision collision = null; Thing thing = (Thing) leaf.getValue(); if (thing.type.equals(Collision.type)) collision = (Collision) thing; else { // Should fix these - thing could be a sub tree; thing.name could already be taken. collision = new Collision(myRoot, baseName, skang); myRoot.add(thing.type.toUpperCase() + "." + thing.name, thing); collision.names.addElement(thing.name); } if (!type.equals(Collision.type)) { collision.names.addElement(name); baseName = name; What.ERRLN("DUPLICATE SYMBOLS IN ThingSpace." + myRoot.getKey() + " " + type + "." + name + " - " + thing.type + "." + thing.name); } } else What.ERRLN("DUPLICATE SYMBOL IN ThingSpace." + myRoot.getKey() + " " + type.toUpperCase() + "." + baseName + " BUT NOT A REAL Thing!"); hasCrashed++; } myRoot.add(type.toUpperCase() + "." + baseName, this); } else { if (leaf == null) { myRoot.add(type.toUpperCase() + "." + baseName, this); } } //What.OUTLN("SYMBOL " + type + "." + name + " IN ThingSpace." + myRoot.getKey() + " -> " + type.toUpperCase() + "." + baseName); } public static void appendText(String aName, String aText) throws SkangException, ThingNotFoundException { get(What.root, aName).appendText(aText); } public void appendText(String aText) throws SkangException { if (!this.canAppend(null)) { if (this.fromServer('w', null)) { // Should append the thing on the server. //What.OUTLN("SERVLET APPEND " + name + "(" + aText + ")"); What.me.servletPendingDoThing(myRoot, "append " + name + " '" + aText + "'"); } else if (What.servlet && this.GUIOnly('w', null)) { // Should append the thing on the applet. //What.OUTLN("APPLET APPEND " + name + "(" + aText + ")"); What.me.appletPendingDoThing(myRoot, "append " + name + " '" + aText + "'"); } else throw(new SkangException("Security violation appending to " + name)); } //What.ERRLN("THING.appendText() " + this.name + " = " + aText); if (this.append != null) { try { Object args[] = new Object[1]; args[0] = aText; this.append.invoke(this.thing, args); this.text += aText; } catch (Exception e) { this.hasCrashed++; SkangException ex = new SkangException("(Try builtin types.) " + this.name + ".appendText(" + aText + ") " + e.toString()); What.ERRLN(ex.toString()); // e.printStackTrace(); throw(ex); } //{What.ERRLN("(Try builtin types.) Problem with " + usage[1] + " " + e2.toString());} } } // public static Thing get(String aName) // throws ThingNotFoundException // { // return get(What.root, aName); // } public static Thing get(ThingSpace aRoot, String aName) throws ThingNotFoundException { //What.ERRLN("<>thing.get(" + aName + ")"); Leaf leaf = aRoot.get(aName); Thing returnThing = null; if (leaf != null) returnThing = (Thing) leaf.getValue(); if (returnThing == null) { // Fake a real search strategy. try {returnThing = Thing.get(aRoot, aName, Widget.type);} catch (ThingNotFoundException e) {;} try { if (returnThing == null) returnThing = Thing.get(aRoot, aName, Stuff.type); } catch (ThingNotFoundException e) {;} if (returnThing == null) returnThing = Thing.get(aRoot, aName, Parameter.type); } if (returnThing == null) throw(new ThingNotFoundException(aName)); return returnThing; } // public static Thing get(String aName, String aType) // throws ThingNotFoundException // { // return get(What.root, aName, aType); // } public static Thing get(ThingSpace aRoot, String aName, String aType) throws ThingNotFoundException { //What.ERRLN("thing.get(" + aName + ", " + aType + ")"); Thing returnThing = null; String baseName = aName; if ((!aType.toUpperCase().equals(Widget.type.toUpperCase())) && (!aType.toUpperCase().equals(Stuff.type.toUpperCase()))) { int pos = baseName.lastIndexOf('.'); if (pos != -1) baseName = baseName.substring(pos + 1); } if (aType != null) { try {returnThing = (Thing) aRoot.get(aType.toUpperCase() + "." + baseName).getValue();} catch (NullPointerException e) {;} catch (Exception e) {;} if (returnThing != null) { if (returnThing.type.equals(Collision.type)) { Thing firstThing = returnThing; try {returnThing = (Thing) aRoot.get(aType.toUpperCase() + "." + aName).getValue();} catch (NullPointerException e) {;} catch (Exception e) {;} if (returnThing == null) { What.ERRLN(aName + " is ambigous!"); // Should print out the Collision list. returnThing = firstThing; } } if (returnThing.type != aType) { What.ERRLN(returnThing.clas.getName() + " != " + aType + " != " + returnThing.type); returnThing = null; } } } //What.ERRLN("thing.get(" + aType.toUpperCase() + "." + aName + ") = " + returnThing); if (returnThing == null) throw(new ThingNotFoundException(aType, aName)); return returnThing; } public static Enumeration elements(ThingSpace aRoot, String aType) { Enumeration returnEnum = (new Hashtable()).elements(); // try { Leaf leaf = aRoot.get(aType.toUpperCase()); if (leaf != null) if (leaf.up() != null) returnEnum = leaf.up().elements(); } // catch (ThingNotFoundException e) // {;} return returnEnum; } public void setHelp(String aHelp) { // Only some things have help, so silently discard it. } public final int doWhere() { int where = DO_HERE; if (!canDo(null)) { if (fromServer('x', null)) where = DO_SERVLET; else if ((What.servlet) && GUIOnly('x', null)) where = DO_APPLET; else where = DO_NOWHERE; } else if (isStub) { if (What.areWe.standAlone) where = DO_APPLET; else where = DO_SERVLET; } return where; } public final boolean canDo(Who they) { if (they == null) they = (myRoot.user != null) ? myRoot.user : What.root.user; return What.me.security.canDo(they, acl); } public final boolean canRead(Who they) { if (they == null) they = (myRoot.user != null) ? myRoot.user : What.root.user; return What.me.security.canRead(they, acl); } public final boolean canAppend(Who they) { if (they == null) they = (myRoot.user != null) ? myRoot.user : What.root.user; return What.me.security.canAppend(they, acl); } public final boolean canWrite(Who they) { if (they == null) they = (myRoot.user != null) ? myRoot.user : What.root.user; return What.me.security.canWrite(they, acl); } public final boolean fromServer(char aType, Who they) { if (they == null) they = (myRoot.user != null) ? myRoot.user : What.root.user; return What.me.security.fromServer(aType, they, acl); } public final boolean GUIOnly(char aType, Who they) { if (they == null) they = (myRoot.user != null) ? myRoot.user : What.root.user; return What.me.security.GUIOnly(aType, they, acl); } public final static void setACL(String aName, String aBoss, String anACL) throws SkangException, ThingNotFoundException { Thing thing = get(What.root, aName); if (thing.canWrite(null)) thing.acl = new ACL(aBoss, anACL); } public final void setACL(String aBoss, String anACL) { if (this.canWrite(null)) this.acl = new ACL(aBoss, anACL); } public final String getACL() { return acl.getACL(); } public static void setText(String aName, String aText) throws SkangException, ThingNotFoundException { Thing thing = get(What.root, aName); try { if (thing != null) thing.setText(aText); else throw(new ThingNotFoundException(aName)); } // There is an intermittant NullPointerException somewhere that I can't track down. // Think I have found it, but I'll leave this in just in case. catch (NullPointerException e) {What.ERRLN("CAUGHT PHANTOM NULL!! " + aName + ", " + aText); e.printStackTrace();} } public void setText(String aText) throws SkangException { //What.ERR("THING.setText(" + this.name + " = " + aText + ")"); if (!this.canWrite(null)) { if (this.fromServer('w', null)) { //What.OUTLN("SERVLET Thing.setText(" + name + ", " + aText + ")"); What.me.servletPendingDoThing(myRoot, name + "='" + aText + "'"); } else if (What.servlet && this.GUIOnly('w', null)) { //What.OUTLN("APPLET Thing.setText(" + name + ", " + aText + ")"); What.me.appletPendingDoThing(myRoot, name + "='" + aText + "'"); } else throw(new SkangException("Security violation setting " + name)); } this.text = aText; if (this.set != null) { try { Object args[] = new Object[1]; args[0] = this.text; //What.ERR("1"); this.set.invoke(this.thing, args); //What.ERR("2"); } catch (Exception e) { //What.ERR(" CRASH "); this.hasCrashed++; SkangException ex = new SkangException("(Try builtin types.) " + this.name + ".setText(" + aText + ") " + e.toString()); What.ERRLN(ex.toString()); throw(ex); } } //What.ERRLN("END"); } public void showErrors() { if (this.errors.isEmpty()) What.ERRLN(""); else { for (Enumeration results = this.errors.elements(); results.hasMoreElements(); ) What.ERRLN((String) results.nextElement()); } } public static Struct initStruct(ThingSpace myRoot, String aName) { Thing result = null; What.ERRLN("Thing.initStruct(" + myRoot.toString() + ", " + aName + ")"); return result; } public void moreStruct(char aType, String aText) { What.ERRLN("Thing.moreStruct('" + aType + "', \"" + aText + "\")"); } public void finishStruct() { What.ERRLN("Thing.finishStruct()"); } }