[e-cvs] cvs commit: e/src/jsrc/org/erights/e/elib/prim SafeJ.java
markm@eros.cs.jhu.edu
markm@eros.cs.jhu.edu
Mon, 24 Dec 2001 21:33:25 -0500
markm 01/12/24 21:33:25
Added: src/jsrc/org/erights/e/elib/prim SafeJ.java
Log:
Oops, forgot this one
Revision Changes Path
1.1 e/src/jsrc/org/erights/e/elib/prim/SafeJ.java
Index: SafeJ.java
===================================================================
package org.erights.e.elib.prim;
import org.erights.e.elib.tables.FlexSet;
import org.erights.e.elib.tables.IdentityCacheTable;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.ConstSet;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.develop.exception.ExceptionMgr;
import org.erights.e.develop.assertion.T;
import org.erights.e.meta.java.net.URLSugar;
import org.quasiliteral.term.Term;
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.QuasiBuilder;
import org.quasiliteral.term.QuasiBuilderAdaptor;
import org.quasiliteral.term.TermParser;
import org.quasiliteral.astro.AstroSchema;
import org.quasiliteral.astro.BaseSchema;
import org.quasiliteral.astro.AstroBuilder;
import java.net.URL;
import java.io.IOException;
import java.lang.reflect.Field;
//This file is hereby placed in the public domain
/**
*
* @author <a href="mailto:markm@caplet.com">Mark Miller</a>
*/
public final class SafeJ {
/**
*
*/
static private final String[] ApprovedClassList = {
"java.awt.event.WindowEvent",
//"java.lang.Boolean", only after we remove getBoolean(String)
"java.lang.Byte",
"java.lang.Character",
"java.lang.Comparable",
"java.lang.Double",
"java.lang.Float",
"java.lang.Integer",
"java.lang.Long",
"java.lang.Number",
"java.lang.Object",
"java.lang.Runnable",
"java.lang.RuntimeException", //must enforce DeepPassByCopy
"java.lang.Short",
//"java.lang.StrictMath", only after we remove random()
"java.lang.String",
"java.lang.StringBuffer",
"java.lang.Throwable", //XXX must enforce DeepPassByCopy
"java.lang.Void",
"java.math.BigInteger",
"org.apache.oro.text.regex.Perl5Compiler",
"org.apache.oro.text.regex.Perl5Matcher",
"org.apache.oro.text.regex.PatternMatcherInput",
"org.erights.e.elang.interp.Loop",
"org.erights.e.elang.interp.ProtocolDesc",
"org.erights.e.elang.syntax.EParser",
"org.erights.e.elib.base.MessageDesc",
"org.erights.e.elib.base.ParamDesc",
"org.erights.e.elib.eio.TextWriter",
"org.erights.e.elib.quasi.FirstCharSplitter",
"org.erights.e.elib.quasi.Identifiers",
"org.erights.e.elib.quasi.Substituter",
"org.erights.e.elib.ref.Ref",
"org.erights.e.elib.prim.E",
"org.erights.e.elib.prim.Queue",
"org.erights.e.elib.prim.Thrower",
"org.erights.e.elib.sealing.Brand",
"org.erights.e.elib.slot.NullOkMaker",
"org.erights.e.elib.slot.SimpleSlotMaker",
"org.erights.e.elib.tables.ConstList",
"org.erights.e.elib.tables.ConstMap",
"org.erights.e.elib.tables.EList",
"org.erights.e.elib.tables.EMap",
"org.erights.e.elib.tables.FlexList",
"org.erights.e.elib.tables.FlexMap",
//must enforce DeepPassByCopy
"org.erights.e.elib.util.TwineException",
"net.captp.api.SturdyRef",
"org.capml.quasi.XMLQuasiParser",
};
static private final FlexSet ApprovedClasses;
static {
int len = ApprovedClassList.length;
ApprovedClasses = FlexSet.fromType(String.class, len);
for (int i = 0; i < len; i++) {
ApprovedClasses.addElement(ApprovedClassList[i], true);
}
}
static private final IdentityCacheTable SAFEJ_CACHE =
new IdentityCacheTable(Term.class, 100);
static private final String[] SafejTagNames = {
"LiteralChar",
"LiteralInteger",
"LiteralFloat64",
"LiteralString",
"class",
"name",
"method",
"static",
"signature",
"suppress",
"comment",
"byproxy",
"selfless",
"byconstruction",
"persistent",
"safe",
"honorary"
};
/**
*
*/
static public final AstroSchema SAFEJ_SCHEMA =
new BaseSchema("safej", ConstList.fromArray(SafejTagNames));
/**
*
*/
static public final AstroBuilder SAFEJ_BUILDER =
new TermBuilder(SAFEJ_SCHEMA);
/**
*
*/
static public final QuasiBuilder SAFEJ_QBUILDER =
new QuasiBuilderAdaptor(SAFEJ_BUILDER);
/**
* Prevent instantiation
*/
private SafeJ() {}
/**
*
*/
static public Term getOptSafejTerm(String fqn) {
Twine tfqn = Twine.fromString(fqn);
Term optResult = (Term)SAFEJ_CACHE.get(tfqn, null);
if (null != optResult) {
return optResult;
}
String path = StringHelper.replaceAll(fqn, ".", "/") + ".safej";
URL optTermURL = ClassLoader.getSystemResource(path);
if (null == optTermURL) {
return null;
}
String termSrc;
try {
termSrc = URLSugar.getText(optTermURL);
} catch (IOException ioe) {
throw ExceptionMgr.asSafe(ioe);
}
// XXX Bug: Investigate why the commented out version doesn't work.
// Term result = (Term)TermParser.run(Twine.fromString(termSrc),
// SAFEJ_QBUILDER);
Term result = (Term)TermParser.run(Twine.fromString(termSrc));
SAFEJ_CACHE.put(tfqn, result);
return result;
}
/**
*
*/
static public Term optAttribute(Term root,
String rootName,
String attrName) {
//Hard code Term-tree walking in order to avoid having elib depend
//on quasi-Terms
T.require(root.getTag().getTagName() == rootName,
"Mismatch: ", root, " vs ", rootName);
attrName = attrName.intern();
ConstList args = root.getArgs();
for (int i = 0, len = args.size(); i < len; i++) {
Term arg = (Term)args.get(i);
if (arg.getTag().getTagName() == attrName) {
return arg;
}
}
return null;
}
/**
* Like getAttribute/3, but only checks args[0].
* <p>
* If you know the arg you're looking for may only be first or absent,
* this is a nice little optimization. But it does make your format
* more position dependent, and therefore more brittle.
*/
static public Term optFirstAttribute(Term root,
String rootName,
String attrName) {
//Hard code Term-tree walking in order to avoid having elib depend
//on quasi-Terms
T.require(root.getTag().getTagName() == rootName,
"Mismatch: ", root, " vs ", rootName);
attrName = attrName.intern();
ConstList args = root.getArgs();
Term arg = (Term)args.get(0);
if (arg.getTag().getTagName() == attrName) {
return arg;
} else {
return null;
}
}
/**
* Is clazz approved as safe? <p>
*
* If so, this means a {@link StaticMaker} on clazz follows capability
* discipline and provides no authority.
*/
static public boolean approve(Class clazz) {
String fqn = clazz.getName();
if (ApprovedClasses.contains(fqn)) {
return true;
}
if (clazz.isArray()) {
//Array types are safe
ApprovedClasses.addElement(fqn, true);
return true;
}
Term optTerm = getOptSafejTerm(fqn);
if (null == optTerm) {
return false;
}
return null != optFirstAttribute(optTerm, "class", "safe");
}
/**
* If the sugar class has a static SAFEJ field consisting of an array
* of strings, return a set (a ConstMap from set elements to null) of
* these strings; otherwise return null. <p>
*
* These strings should be typedVerbs of methods to be included to
* sugarring.
*/
static /*package*/ ConstSet optSafeJ(Class clazz,
Class optSugar,
boolean staticFlag) {
ConstSet optResult = null;
Term optSafejTerm = getOptSafejTerm(clazz.getName());
if (null != optSafejTerm) {
//Hard code Term-tree walking in order to avoid having elib depend
//on quasi-Terms
String attrName = staticFlag ? "statics" : "methods";
Term optMeths = optAttribute(optSafejTerm, "class", attrName);
if (null != optMeths) {
ConstList methList = optMeths.getArgs();
FlexSet accum = FlexSet.fromType(String.class,
methList.size());
for (int i = 0, len = methList.size(); i < len; i++) {
Term meth = (Term)methList.get(i);
Term methArg0 = (Term)meth.getArgs().get(0);
String optSig = methArg0.getOptString();
//Just for testing:
if (null != optSig &&
(optSig.equals("getAlpha()") ||
optSig.equals("getRule()"))) {
optSig = optSig;
}
if (null == optSig) {
T.require(methArg0.getTag().getTagName() == "suppress",
"Unrecognized meth attribute: ", methArg0,
" in ", meth);
} else {
T.require(optSig.indexOf('(') >= 1,
"Must be a method signature: ", optSig);
accum.addElement(optSig);
}
}
optResult = accum.snapshot();
}
}
if (null == optSugar) {
return optResult;
}
String[] optTypedVerbs =
(String[])getStaticValue(optSugar, "SAFEJ", null);
if (null == optTypedVerbs) {
return optResult;
}
T.require(null == optResult,
"SAFEJ Specification conflict for ", clazz);
return ConstList.fromArray(optTypedVerbs).asSet();
}
/**
* Gets the value of clazz's static public field named 'fieldName'. <p>
*
* If there is no such field, return 'instead' instead.
*/
static /*package*/ Object getStaticValue(Class clazz,
String fieldName,
Object instead) {
Field staticField;
try {
staticField = clazz.getField(fieldName);
} catch (NoSuchFieldException nsfe) {
return instead;
}
String[] typedVerbs;
try {
return staticField.get(null);
} catch (IllegalAccessException iae) {
throw ExceptionMgr.asSafe(iae);
}
}
}