package net.matrix_rad.squeal; import java.lang.Class; import java.lang.Exception; import java.lang.String; import java.lang.Throwable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.NoSuchMethodException; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import net.matrix_rad.skang.Skang; import net.matrix_rad.skang.Struct; import net.matrix_rad.skang.Thing; import net.matrix_rad.skang.ThingSpace; import net.matrix_rad.skang.ThingNotFoundException; import net.matrix_rad.skang.What; import net.matrix_rad.skang.Whinge; /** * Stuff is the wrapper around DB rows and other such data. * * @.requires Java 1.1 at least. * @author David Seikel * @.copyright 2003 David Seikel * @version 0.101 prototype 2004-11-22 10:40:00 * @.secure SSS */ abstract public class Stuff extends Thing implements Struct { protected static class Row extends Object { public Row() { } public void showRow() { for (Enumeration stufflets = row.keys(); stufflets.hasMoreElements(); ) { String key = (String) stufflets.nextElement(); What.OUTLN("** Stuff$Row.row " + key + "=" + row.get(key)); } What.OUTLN("**"); } public static void addRow(Vector someRows, Hashtable aRow) { Row newRow = new Row(); newRow.row = aRow; someRows.addElement(newRow); } public void putRow(Hashtable aRow) { row = aRow; } public Hashtable getRow() { return (Hashtable) row.clone(); } public Enumeration keys() { return row.keys(); } public Stuff getSubStuff(String aName) { //What.ERRLN("** Stuff->Row->getSubStuff(" + aName + ")"); return (Stuff) subStuffs.get(aName); } public void putSubStuff(String aName, Stuff aStuff) { What.ERRLN("** Stuff->Row->putSubStuff(" + aName + ", " + aStuff.name + ")"); subStuffs.put(aName, aStuff); } public Object getStufflet(String aStufflet) { Object result = null; int pos = aStufflet.indexOf("."); if (pos != -1) { String first = aStufflet.substring(0, pos); String last = aStufflet.substring(pos + 1); Stuff subStuff = (Stuff) subStuffs.get(first); if (subStuff != null) result = subStuff.getStufflet(last); } else result = this.row.get(aStufflet); return result; } public void putStufflet(String aStufflet, Object aValue) { int pos = aStufflet.indexOf("."); if (pos != -1) { String first = aStufflet.substring(0, pos); String last = aStufflet.substring(pos + 1); Stuff subStuff = (Stuff) subStuffs.get(first); if (subStuff != null) subStuff.putStufflet(last, aValue); } else this.row.put(aStufflet, aValue); } private Hashtable row = new Hashtable(); private Hashtable subStuffs = new Hashtable(); } public Stuff(ThingSpace myRoot, String aName, String aKey, Skang anOwner) { super(myRoot, aName + ((aKey == null) ? "" : "[" + aKey + "]"), type, anOwner); What.OUTLN("** STUFF->Stuff(" + myRoot + ", " + aName + ", " + aKey + ")"); try {this.myMobField = (String) this.getClass().getField("mobField").get(this);} catch (Exception e) {;} if (this.myMobField != null) { this.isMobs = true; this.mobIDs = new Hashtable(); } Row.addRow(rows, new Hashtable()); this.initStufflets(); } public static Stuff getStuff(ThingSpace myRoot, String aName) throws ThingNotFoundException { return (Stuff) Thing.get(myRoot, aName, type); } public static Stuff getStuffed(ThingSpace myRoot, String aStuff, String aKey) { //What.OUTLN("** STUFF->getStuffed(" + myRoot + ", " + aStuff + ", " + aKey + ")"); Stuff result = null; if (myRoot != null) { try {result = getStuff(myRoot, aStuff + ((aKey == null) ? "" : "[" + aKey + "]"));} catch (ThingNotFoundException e) {;} } if (result == null) { //What.OUTLN("** STUFF->getStuffed(" + myRoot + ", " + aStuff + ", " + aKey + ") - CREATING " + aStuff + "." + aKey); try { Object args[] = new Object[4]; Class classes[] = new Class[4]; args[0] = myRoot; classes[0] = myRoot.getClass(); args[1] = aStuff; classes[1] = args[1].getClass(); args[2] = aKey; classes[2] = Class.forName("java.lang.String"); args[3] = What.me; classes[3] = Class.forName("net.matrix_rad.skang.Skang"); Class stuffClass = Class.forName(aStuff); result = (Stuff) stuffClass.getConstructor(classes).newInstance(args); if ((result != null) && (myRoot != null)) { } } catch (Exception e) {What.ERRLN("Stuff.getStuffed(" + myRoot + ", " + aStuff + ", " + aKey + ") " + e.toString() + " :-: " + e.getMessage()); e.printStackTrace();} } else { //What.OUTLN("** STUFF->getStuffed(" + myRoot + ", " + aStuff + ", " + aKey + ") - FOUND " + aStuff + "." + result.key); //What.OUTLN("** STUFF->getStuffed(" + myRoot + ", " + aStuff + ", " + aKey + ") - FOUND = " + result.toBigString()); } //What.OUTLN("** STUFF->getStuffed(" + myRoot + ", " + aStuff + ", " + aKey + ") - RESULT = " + result.toBigString()); return result; } protected void initStufflets() { //What.OUTLN("** STUFF->initStufflets() - " + this.name); try { String name = this.getClass().getName(); this.metaData = (Hashtable) metaCache.get(name); if (this.metaData == null) { this.metaData = new Hashtable(); metaCache.put(name, this.metaData); } if (this.metaData.isEmpty()) { //What.OUTLN("** STUFF->initStufflets().getClass() - " + this.getClass().getName()); // String myStufflets[] = (String[]) this.getClass().getDeclaredField("stufflets").get(this); String myStufflets[] = (String[]) this.getClass().getField("stufflets").get(this); for (int i = 0; i < myStufflets.length; i++) { MetaData meta = decodeMetaData(myStufflets[i]); //What.ERRLN("** STUFF->initStufflets() GET SUB STUFF " + meta.subStuff); if (meta != null) { //What.ERRLN("** STUFF->initStufflets() GET SUB STUFFE " + meta.subStuff); Stuff subStuff = this.getSubStuff(meta.name); if ((subStuff == null) && ((meta.subStuff != null) && (!meta.subStuff.equals("")))) { //What.ERRLN("** STUFF->initStufflets() GET SUB STUFFED " + meta.subStuff); subStuff = this.getStuffed(this.myRoot, meta.subStuff, this.key); ((Row) rows.elementAt(0)).putSubStuff(meta.name, subStuff); } } } metaCache.put(name, this.metaData); } } catch (Exception e) { What.ERRLN("** STUFF->initStufflets() " + e.getMessage() + " : " + e.toString()); e.printStackTrace(); } What.me.addModule(myRoot, "net.matrix_rad.squeal.StuffSkang", "SSS"); } protected MetaData decodeMetaData(String aText) { String name = aText; int pos = name.indexOf("|"); if (pos != -1) name = name.substring(0, pos); //What.OUTLN("** STUFF->decodeMeta(" + aText + ") - " + name); MetaData original = (MetaData) this.metaData.get(name); MetaData meta = original; if ((pos != -1) || (original == null)) // If there was real meta data in the arguments, or it didn't exist. { meta = new MetaData(aText); try {meta.validate = this.getClass().getDeclaredMethod("validate" + name, null); //What.OUTLN("** STUFF->decodeMeta() - validate" + name + "() found!"); } catch (NoSuchMethodException e) {;} this.metaData.put(name, meta.merge(original)); } return meta; } // Should maybe unabstract and call the others. abstract public boolean delete(); abstract public boolean read(String aKey); abstract public boolean write(); public void clear(boolean clearAll) { What.OUTLN("#### STUFF->clear()." + name); dirty = false; old = false; //What.OUTLN(" OLD=" + old + " DIRTY=" + dirty); key = null; rows = new Vector(); Row.addRow(rows, new Hashtable()); empty = true; if (clearAll) { if (isMobs) mobIDs = new Hashtable(); else mobIDs = null; } } protected void addRow(Hashtable row) { if (this.empty) this.rows = new Vector(); Row.addRow(this.rows, row); this.empty = false; } protected boolean delete(boolean aResult) { // for (Enumeration stufflets = this.metaData.elements(); stufflets.hasMoreElements(); ) // { // MetaData meta = (MetaData) stufflets.nextElement(); // if ((meta.subStuff != null) && (!meta.subStuff.equals(""))) // { // try // { // Stuff theStuff = ((Row) rows.elementAt(0)).getSubStuff(meta.name); // theStuff.delete(); // } // catch (Exception e1) // {What.ERRLN("** SquealStuff.delete() " + e1.toString() + " :-: " + e1.getMessage());} // } // } if (aResult) { dirty = false; old = false; //What.OUTLN(" OLD=" + old + " DIRTY=" + dirty); } return aResult; } protected boolean read(boolean aResult, Vector someRows) { What.OUTLN("**Stuff.read()." + this.getClass().getName()); rowDiff = null; if (someRows != null) { String temp = this.key; this.clear(true); this.key = temp; if (!someRows.isEmpty()) { rows = new Vector(); for (Enumeration newRows = someRows.elements(); newRows.hasMoreElements(); ) { try { this.addRow((Hashtable) newRows.nextElement()); //((Row) rows.elementAt(rows.size() - 1)).showRow(); } catch (Exception e) {;} } aResult = true; } } if (isMobs) mobIDs = new Hashtable(); for (int i = 0; i < rows.size(); i++) { if (isMobs) { String mobKey = (String) this.getStufflet(this.myMobField, i); if (mobKey != null) { mobIDs.put(mobKey, this.key); What.OUTLN("**Stuff.read()." + this.getClass().getName() + " ADDED mobKey=" + mobKey + " key=" + this.key); } } for (Enumeration stufflets = this.metaData.elements(); stufflets.hasMoreElements(); ) { MetaData meta = (MetaData) stufflets.nextElement(); if ((meta.subStuff != null) && (!meta.subStuff.equals(""))) { String subKey = (String) this.getStufflet(meta.name, i); if (subKey == null) { subKey = key; if (subKey != null) this.putStufflet(meta.name, subKey, i); } try { //What.OUTLN("** Stuff.read() SUBSTUFF FOR " + meta.name + " (" + subKey + ") -> " + meta.subStuff); Stuff theStuff = getStuffed(myRoot, meta.subStuff, subKey); ((Row) rows.elementAt(i)).putSubStuff(meta.name, theStuff); } catch (Exception e1) {What.ERRLN("** Stuff.read() " + e1.toString() + " :-: " + e1.getMessage()); e1.printStackTrace();} } } } if (aResult) { dirty = false; old = true; //What.OUTLN(" OLD=" + old + " DIRTY=" + dirty); } //What.OUTLN("**Stuff.read()." + this.getClass().getName() + " - RESULT = " + this.toBigString()); return aResult; } protected boolean write(boolean aResult) { What.OUTLN("** Stuff.write() rowDiff = " + rowDiff); if (rowDiff == null) rowDiff = new Vector(); for (int i = 0; i < rows.size(); i++) { for (Enumeration stufflets = this.metaData.elements(); stufflets.hasMoreElements(); ) { MetaData meta = (MetaData) stufflets.nextElement(); if ((meta.subStuff != null) && (!meta.subStuff.equals(""))) { try { What.OUTLN("** Stuff.write() SUBSTUFF FOR " + meta.name + " -> " + meta.subStuff); Stuff theStuff = ((Row) rows.elementAt(i)).getSubStuff(meta.name); if (theStuff != null) { What.OUTLN("** Stuff.write() SUBSTUFF FOR " + meta.name + " -> " + meta.subStuff + " FOUND! KEY=" + this.key); if ((this.key != null) && (!this.key.equals(""))) { theStuff.key = this.key; for (int j = 0; j < theStuff.rows.size(); j++) { What.OUTLN("** Stuff.write() SUBSTUFF FOR " + meta.name + " -> " + meta.subStuff + " FOUND! KEY(" + theStuff.myKeyField + ")=" + this.key + " for row " + j); theStuff.putStufflet(theStuff.myKeyField, this.key, j); } } if (!theStuff.write()) aResult = false; } else { // Should do an insert, but where is the substuff? } } catch (Exception e) {What.ERRLN("** Stuff.write() " + e.toString() + " :-: " + e.getMessage()); e.printStackTrace();} } } } if (this.dirty) { if (aResult) { dirty = false; old = true; //What.OUTLN(" OLD=" + old + " DIRTY=" + dirty); } } else { addError(null, "Nothing was written because nothing was changed."); } return aResult; } /** * Returns an enumeration of the rows of this Stuff. * * @return an enumeration of the rows of this Stuff. * @see java.util.Enumeration */ // public final synchronized Enumeration elements() // { // return new StuffEnumerator(rows); // } public Object getStufflet(String aStufflet) { return this.getStufflet(aStufflet, 0); } public Object getStufflet(String aStufflet, int aRow) { Object result = null; if ((this.isStufflet(aStufflet)) && (aRow < rows.size())) result = ((Row) rows.elementAt(aRow)).getStufflet(aStufflet); return result; } public Stuff getSubStuff(String aStufflet) { return getSubStuff(aStufflet, 0); } public Stuff getSubStuff(String aStufflet, int aRow) { Stuff result = null; if ((this.isStufflet(aStufflet)) && (aRow < rows.size())) result = ((Row) rows.elementAt(aRow)).getSubStuff(aStufflet); return result; } public Hashtable getMetaData() { return (Hashtable) this.metaData.clone(); } public Hashtable getRow(int aRow) { Hashtable result = null; if (aRow < rows.size()) result = ((Row) this.rows.elementAt(aRow)).getRow(); return result; } public MetaData getMetaData(String aStufflet) { MetaData result = null; if (this.isStufflet(aStufflet)) result = (MetaData) this.metaData.get(aStufflet); return result; } public int getCount() { return this.rows.size(); } public String getKey() { return this.key; } public boolean isStufflet(String aStufflet) { boolean result = false; //What.OUTLN("**Stuff.isStufflet(" + aStufflet + ")." + this.name); int pos = aStufflet.indexOf("."); if (pos != -1) { //What.OUTLN("**Stuff.isStufflet(" + aStufflet + ") - SUBSTUFF"); String first = aStufflet.substring(0, pos); String last = aStufflet.substring(pos + 1); Stuff subStuff = getSubStuff(first); if (subStuff != null) result = subStuff.isStufflet(last); } else if (this.metaData.get(aStufflet) != null) result = true; // Should throw an exception if aStufflet is not in stufflets[]. // if (!result) // throw new stuffletNotFoundException(); return result; } public Vector list() { //What.OUTLN("**Stuff.list()"); Vector result = list(null, new Vector(), "", ""); return result; } public Vector list(Vector aResult, String aKey, String aName) { if (aResult == null) aResult = new Vector(); for (int i = 0; i < this.rows.size(); i++) { Hashtable row = this.getRow(i); String index = (String) row.get(aKey); String value = (String) row.get(aName); // Should handle multiple fields in name. if ((value != null) && (!value.equals(""))) aResult.addElement(index + "|" + value); } return aResult; } public static Vector list(Vector aResult, Vector someRows, String aKey, String aName) { if (aResult == null) aResult = new Vector(); if ((someRows != null) && (!someRows.isEmpty())) { for (Enumeration contents = someRows.elements(); contents.hasMoreElements(); ) { Hashtable row = (Hashtable) contents.nextElement(); String index = (String) row.get(aKey); String value = (String) row.get(aName); // Should handle multiple fields in name. if ((value != null) && (!value.equals(""))) aResult.addElement(index + "|" + value); } } return aResult; } public static String list2String(Vector aResult, Vector someRows, String aKey, String aName) { String result = ""; int pos = 0; Vector list = list(aResult, someRows, aKey, aName); if (!list.isEmpty()) { for (Enumeration contents = list.elements(); contents.hasMoreElements(); ) { String row = (String) contents.nextElement(); if ((pos = row.indexOf('|')) != -1) result += row.substring(0, pos) + "|"; } } pos = result.length(); if (pos > 0) result = result.substring(0, pos - 1); return result; } public void putStufflet(String aStufflet, Object aValue) { this.putStufflet(aStufflet, aValue, 0); } public void putStufflet(String aStufflet, Object aValue, int aRow) { What.OUTLN("**Stuff.putStufflet(" + this.name + "->" + aStufflet + ", " + aValue + ", " + aRow + ") " + rows.size()); if ((this.isStufflet(aStufflet)) && (aRow < rows.size())) { What.OUTLN("**Stuff.putStufflet(" + this.name + "->" + aStufflet + ", " + aValue + ") putting..."); ((Row) rows.elementAt(aRow)).putStufflet(aStufflet, aValue); this.dirty = true; this.empty = false; if (rowDiff != null) { What.OUTLN("**Stuff.putStufflet(" + this.name + "->" + aStufflet + ", " + aValue + ") rowDiff!"); if (aRow >= rowDiff.size()) rowDiff.setSize(aRow + 1); Hashtable diff = (Hashtable) rowDiff.elementAt(aRow); if (diff == null) diff = new Hashtable(); if (aValue != null) diff.put(aStufflet, aValue); rowDiff.setElementAt(diff, aRow); } What.OUTLN("**Stuff.putStufflet(" + this.name + "->" + aStufflet + ", " + aValue + ") PUT!"); //What.OUTLN(" OLD=" + this.old + " DIRTY=" + this.dirty); } else What.OUTLN("**Stuff.putStufflet(" + this.name + "->" + aStufflet + ", " + aValue + ") NOT putting " + this.isStufflet(aStufflet)); } public boolean thisIsMandatory(String aStufflet) { boolean result = true; String value = (String) this.getStufflet(aStufflet); MetaData meta = getMetaData(aStufflet); if ((value == null) || value.equals("")) { addError(aStufflet, meta.heading + " is mandatory."); result = false; } return result; } protected void addError(String aStufflet, String error) { if (aStufflet != null) error = aStufflet + "|" + error; if (myRoot.whinge == null) new Whinge(myRoot); myRoot.whinge.addThingError(this, error); } public void showErrors() { // super.showErrors(); } // public Vector mergeResults(Vector result, Vector subResult) // { // if (!subResult.isEmpty()) // { // for (Enumeration results = subResult.elements(); results.hasMoreElements(); ) // result.addElement(results.nextElement()); // } // // return result; // } public boolean validate() { boolean result = true; for (Enumeration stufflets = this.metaData.keys(); stufflets.hasMoreElements(); ) { String name =(String) stufflets.nextElement(); if (!this.validate(name)) result = false; } return result; } public boolean validate(String aStufflet) { boolean result = true; if (isStufflet(aStufflet)) { try { MetaData meta = this.getMetaData(aStufflet); if ((meta != null) && (meta.validate != null)) result = ((Boolean) meta.validate.invoke(this, null)).booleanValue(); } catch (InvocationTargetException e) { What.ERRLN(e.getMessage() + " : " + e.toString()); e.printStackTrace(); Throwable e1 = e.getTargetException(); addError(aStufflet, e1.getMessage() + " : " + e1.toString()); result = false; } catch (Exception e) { What.ERRLN(e.getMessage() + " : " + e.toString()); e.printStackTrace(); addError(aStufflet, e.getMessage() + " : " + e.toString()); result = false; } } return result; } public static Stuff getStuff(String aName) throws ThingNotFoundException { return (Stuff) get(What.root, aName, type); } public String toStruct(boolean metaDataOnly, boolean doDiff) { What.ERRLN(this.name + "->toStruct(" + metaDataOnly + ", " + doDiff + ") " + rows.size() + " rowDiff = " + rowDiff); String result = "{ Stuff " + this.name + "\n"; Vector fields = new Vector(); int cols = 0; //What.OUTLN("*************************************************************************************"); Hashtable metaData = this.getMetaData(); int count = this.getCount(); if (metaDataOnly) { for (Enumeration contents = metaData.keys(); contents.hasMoreElements(); ) { String key = (String) contents.nextElement(); MetaData meta = (MetaData) metaData.get(key); fields.addElement(meta.name); result += "&" + meta.name + "||" + meta.heading + "," + MetaData.SQLToStringType(meta.SQLType) + "," + meta.width + "," + meta.precision + "," + meta.scale + "," + meta.isNullable + "," + meta.isSigned + "," + meta.isCurrency + "," + meta.isAutoInc + "," + meta.isSQL + "\n"; cols++; } } else if (!(doDiff && (rowDiff != null))) { Hashtable row = this.getRow(0); result += "#"; for (Enumeration contents = row.keys(); contents.hasMoreElements(); ) { String key = (String) contents.nextElement(); String value = (String) row.get(key); MetaData meta = (MetaData) metaData.get(key); fields.addElement(meta.name); if (cols > 0) result += "|"; result += key; cols++; } result += "\n"; } if (!metaDataOnly) { if (doDiff && (rowDiff != null)) { for (int i = 0; i < rowDiff.size(); i++) { Hashtable diff = (Hashtable) rowDiff.elementAt(i); if (diff != null) { boolean bar = false; for (Enumeration contents = diff.keys(); contents.hasMoreElements(); ) { String key = (String) contents.nextElement(); String value = (String) diff.get(key); if (bar) result += "|"; else { result += "= " + i + " "; bar = true; } result += What.genericEncode(key + "=" + value, "%|", "%P"); } if (bar) result += "\n"; } } } else { for (int i = 0; i < rows.size(); i++) { result += "+"; Hashtable row = this.getRow(i); for (int column = 0; column < cols; column++) { //What.OUTLN("" + i + "," + column + " " + fields.elementAt(column) + "=" + row.get(fields.elementAt(column))); if (column > 0) result += "|"; result += What.genericEncode((String) row.get(fields.elementAt(column)), "%|", "%P"); } result += "\n"; } } if (this.old) result += "?old\n"; else result += "?new\n"; if (this.dirty) result += "?dirty\n"; else result += "?clean\n"; } result += "}\n"; //What.OUTLN(result); //What.OUTLN("*************************************************************************************"); return result; } public static Struct initStruct(ThingSpace myRoot, String aName) { What.ERRLN("Stuff.initStruct(" + aName + ")"); Stuff result = null; try {result = getStuff(myRoot, aName);} catch (ThingNotFoundException e) {;} if (result != null) { What.ERRLN("Stuff.initStruct(" + aName + ") FOUND"); result.structFields = new Vector(); if (!result.empty) { // result.clear(false); } // result.rows = new Vector(); int pos = aName.indexOf('[') + 1; int lastPos = aName.indexOf(']'); if ((pos != 0) && (lastPos != -1) && (pos < lastPos)) result.key = aName.substring(pos, lastPos); } return result; } public void moreStruct(char aType, String aText) { What.ERRLN("Stuff.moreStruct('" + aType + "', \"" + aText + "\")"); if ((aText == null) || (aText.equals(""))) return; /* ? set boolean & meta data # field names + new row = X change row X =X foo=bar|name=fred = Y something=whatever|age=44 */ switch (aType) { case '?' : { if (aText.equals("new")) this.old = false; else if (aText.equals("old")) this.old = true; else if (aText.equals("clean")) this.dirty = false; else if (aText.equals("dirty")) this.dirty = true; break; } case '&' : { this.structFields.addElement(this.decodeMetaData(aText)); break; } case '#' : { String temp = null; int pos = 0; int lastPos = 0; while ((pos = aText.indexOf('|', pos)) != -1) { temp = What.genericDecode(aText.substring(lastPos, pos), "%|", "%P"); if (temp != null) this.structFields.addElement(this.decodeMetaData(temp)); lastPos = ++pos; } temp = What.genericDecode(aText.substring(lastPos), "%|", "%P"); if (temp != null) this.structFields.addElement(this.decodeMetaData(temp)); break; } case '+' : { String temp = null; Hashtable row = new Hashtable(); int count = 0; int pos = 0; int lastPos = 0; while ((pos = aText.indexOf('|', pos)) != -1) { temp = What.genericDecode(aText.substring(lastPos, pos), "%|", "%P"); //What.OUTLN(" " + count + " " + ((MetaData) this.structFields.elementAt(count)).name + "=" + temp); if (temp != null) { row.put(((MetaData) this.structFields.elementAt(count)).name, temp); if (((MetaData) this.structFields.elementAt(count)).name.equals(this.myKeyField)) this.key = temp; } lastPos = ++pos; count++; } temp = What.genericDecode(aText.substring(lastPos), "%|", "%P"); //What.OUTLN(" " + count + " " + ((MetaData) this.structFields.elementAt(count)).name + "=" + temp); if (temp != null) row.put(((MetaData) this.structFields.elementAt(count)).name, temp); this.addRow(row); this.old = true; //What.OUTLN(" OLD=" + this.old + " DIRTY=" + this.dirty); break; } case '=' : { What.ERRLN("=== " + this.name); String temp = null; int pos = 0; int lastPos = 0; if ((pos = aText.indexOf(' ', pos)) != -1) { int row = What.tLine(aText.substring(0, pos)); What.ERRLN("=== " + this.name + "[" + row + "]"); lastPos = ++pos; if ((pos = aText.indexOf('|', pos)) == -1) pos = aText.length(); { do { temp = What.genericDecode(aText.substring(lastPos, pos), "%|", "%P"); if (temp != null) { What.ERRLN("=== " + this.name + "[" + row + "]. " + temp); int otherPos = temp.indexOf('='); if (otherPos != -1) { String stufflet = temp.substring(0, otherPos); String value = temp.substring(otherPos + 1); if ((stufflet != null) && (!stufflet.equals(""))) { What.ERRLN("=== " + this.name + "[" + row + "]." + stufflet + " = " + value); this.putStufflet(stufflet, value, row); if (stufflet.equals(this.myKeyField)) this.key = value; } } } lastPos = ++pos; } while ((pos = aText.indexOf('|', pos)) != -1); } } break; } } } public void finishStruct() { What.ERRLN("Stuff.finishStruct() " + this.toBigString()); if (rows.size() == 0) { Row.addRow(this.rows, new Hashtable()); this.empty = true; } waitForStruct = false; } public void skangMe(String aCommand, boolean shouldWait) { What.ERRLN("** Stuff.skangMe(" + aCommand + ") " + myRoot); String temp = null; if (shouldWait) waitForStruct = true; try { if (!What.areWe.standAlone) { Skang.servletPendingDoThing(myRoot, aCommand); temp = Skang.postThings(myRoot, "/" + Skang.servletPath + "/stuffskang.svlt:SSL"); } else temp = What.me.doThing(myRoot, aCommand); } catch (Exception e) {What.ERRLN("** Stuff.skangMe(" + aCommand + ") " + e.getMessage() + " : " + e.toString());}; if (temp != null) What.me.doThing(myRoot, temp); if (shouldWait) while (waitForStruct) What.me.pause(1); } public String[] toStrings() { int rowSize = (rows != null) ? rows.size() : 0; int metaSize = (metaData != null) ? metaData.size() : 0; int size = 2 + (empty ? metaSize : (3 + rowSize)); int i = 0; String[] ret = new String[13 + 9 + size + 1]; String struct = toStruct(empty, false); 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"; ret[i++] = "Key field : " + myKeyField; ret[i++] = "Key : " + key; ret[i++] = empty ? "Empty" : "Full"; ret[i++] = old ? "Old" : "New"; ret[i++] = dirty ? "Dirty" : "Clean"; ret[i++] = gotMetaData ? "Got MetaData" : "No MetaData"; ret[i++] = "MetaDatas : " + metaSize; ret[i++] = "Stufflets : " + stufflets.length; ret[i++] = "Rows : " + rowSize; for(int pos = struct.indexOf('\n'), lastpos = 0; pos != -1; pos = struct.indexOf('\n', lastpos)) { ret[i++] = struct.substring(lastpos, pos); lastpos = pos + 1; } ret[i++] = "Mob field : " + myMobField; return ret; } // Should add ACL's to stuff, and reduce the ACL for Squeal. Should do per stufflet ACL as well. // Should write a toString() that uses top level method like validate(aStufflet) does, but with a default based on type and length. // Should provide some sort of extensible filter mechanism. // SQL filter is just an extension to the WHERE clause. // Method filter is called for each row and returns true or false to include it into the list. // Should be able to do some sort of subStuff object. // Should check TODO.html#SQUEAL, we might be able to make this a Skang module or Thing :- /* *stufflist thing,stuff // This thing is used to list/select records from this stuff, with some sort of autoupdate. *Typical usage is that a window has a stuff asigned to it, it's widgets have stufflets *assigned to them, but they default to the windows stuff. stuffindex stuff // Returns key1|name,key2|name,key3|name. *stuffsave thing stuff,key // Save everything for matching stuff in self and children with this key. *stuffclear thing stuff // All things and child things with this matching stuff get cleared. *stuffdelete thing stuff,key // Same as stuffclear stuff, but record is deleted as well. Widget isValid() calls Widget.stuff.validate(Widget.stufflet). stufflist will register a listener with Stuff, the listener will get updated Vectors when needed, the listener gets Widget,stuff,Vector. *stufflist will set the default action to "stuffload parent stuff,%". *Add defaultStuff to Module, Widget.setStuff() with no stuff uses Module.defaultStuff, *An actual module that wants to use a default stuff provides - public static final String defaultStuff = "WhateverStuff"; How to handle foriegn keys? Some stufflet is a foreign key for some other stuff. Just a lookup (select name from other where id='foriegn'). Lookup with Choice (select id,name from other; choice.select("foriegn")). Table fill (select * from other where part_id='foreign'). ItemStuff->"loaned_to|au.org.humbug.PasswdStuff" stufflist Loaned_to,ItemStuff.loaned_to ReservationStuff should be a subset of ItemStuff. ReservationStuff->"id|au.org.humbug.ReservationSubStuff" ReservationSubStuff->"member_id|au.org.humbug.PasswdStuff|name" stuffgrid Grid,ReservationStuff.id */ public final static String type = "Stuff"; public String myKeyField = null; private Vector structFields = null; // Each element is a MetaData. protected boolean isMobs = false; // Dedicated to the NT counting system "One, two, mobs, biggest mobs". protected Hashtable mobIDs = null; public static final String mobField = null; // Name of mob key field. protected String myMobField = null; protected boolean dirty = false; protected boolean old = false; protected boolean gotMetaData = false; private boolean waitForStruct = false; protected boolean empty = true; protected String key = null; protected Hashtable metaData = null; protected Vector rows = new Vector(); protected Vector rowDiff = null; public static final String keyField = "ID"; // Name of key field. protected static Hashtable metaCache = new Hashtable(); // A cache of metaData's, coz meta data shouldn't change. public static final String stufflets[] = { }; } /* final class StuffEnumerator implements Enumeration { Vector vector; int count; StuffEnumerator(Vector v) { vector = v; count = 0; } public boolean hasMoreElements() { return count < vector.elementCount; } public Object nextElement() { synchronized (vector) { if (count < vector.elementCount) return vector.elementData[count++]; } throw new NoSuchElementException("StuffEnumerator"); } } */