/* // $Id: //guest/julian_hyde/saffron/src/main/saffron/util/Util.java#4 $ // Saffron preprocessor and data engine // Copyright (C) 2002 Julian Hyde <julian.hyde@mail.com> // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // See the COPYING file located in the top-level-directory of // the archive of this library for complete text of license. */ package saffron.util; import openjava.mop.OJClass; import openjava.mop.OJField; import openjava.mop.Toolbox; import openjava.ptree.*; import openjava.ptree.util.GenericVisitor; import openjava.tools.DebugOut; import saffron.opt.RelSubset; import saffron.opt.VisitorRelVisitor; import saffron.rel.Rel; import java.io.*; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.*; /** * Miscellaneous utility functions. **/ public class Util extends Toolbox { /** System-dependent newline character. */ public static String lineSeparator = System.getProperty( "line.separator"); /** System-dependent file separator, e.g. / or \. **/ public static String fileSeparator = System.getProperty( "file.separator"); public static PrintWriter debugWriter; /** * Print an object using reflection. We can handle <code>null</code>; * arrays of objects and primitive values; for regular objects, we print * all public fields. **/ public static void print(PrintWriter pw, Object o) { print(pw, o, 0); } public static void println(PrintWriter pw, Object o) { print(pw, o, 0); pw.println(); } public static void print(PrintWriter pw, Object o, int indent) { if (o == null) { pw.print("null"); return; } Class clazz = o.getClass(); if (clazz == String.class || clazz == Integer.class || clazz == Boolean.class || clazz == Character.class || clazz == Byte.class || clazz == Short.class || clazz == Long.class || clazz == Float.class || clazz == Double.class || clazz == Void.class) { pw.print(o.toString()); } else if (clazz.isArray()) { // o is an array, but we can't cast to Object[] because it may be // an array of primitives. Object[] a; // for debug if (o instanceof Object[]) { a = (Object[]) o; discard(a); } int n = Array.getLength(o); pw.print("{"); for (int i = 0; i < n; i++) { if (i > 0) { pw.println(","); } else { pw.println(); } for (int j = 0; j < indent; j++) { pw.print("\t"); } print(pw, Array.get(o, i), indent + 1); } pw.print("}"); } else if (o instanceof Iterator) { pw.print(clazz.getName()); Iterator iter = (Iterator) o; pw.print(" {"); int i = 0; while (iter.hasNext()) { if (i++ > 0) { pw.println(","); } print(pw, iter.next(), indent + 1); } pw.print("}"); } else if (o instanceof Enumeration) { pw.print(clazz.getName()); Enumeration enum = (Enumeration) o; pw.print(" {"); int i = 0; while (enum.hasMoreElements()) { if (i++ > 0) { pw.println(","); } print(pw, enum.nextElement(), indent + 1); } pw.print("}"); } else { pw.print(clazz.getName()); pw.print(" {"); Field[] fields = clazz.getFields(); int printed = 0; for (int i = 0; i < fields.length; i++) { if (isStatic(fields[i])) { continue; } if (printed++ > 0) { pw.println(","); } else { pw.println(); } for (int j = 0; j < indent; j++) { pw.print("\t"); } pw.print(fields[i].getName()); pw.print("="); Object val = null; try { val = fields[i].get(o); } catch (IllegalAccessException e) { throw newInternal(e); } print(pw, val, indent + 1); } pw.print("}"); } } public static final void discard(Object o) {} public static final void discard(int i) {} /** * Returns whether two strings are equal or are both null. **/ public static final boolean equal(String s0, String s1) { if (s0 == null) { return s1 == null; } else if (s1 == null) { return false; } else { return s0.equals(s1); } } // static final boolean isBlank(String s) // { // return s == null || s.equals(""); // } public static Rel clone(Rel rel) { return (Rel) rel.clone(); } public static Rel[] clone(Rel[] rels) { rels = (Rel[]) rels.clone(); for (int i = 0; i < rels.length; i++) { rels[i] = (Rel) rels[i].clone(); } return rels; } // static Parameter clone(Parameter parameter) // throws CloneNotSupportedException // { // return (Parameter) parameter.clone(); // } public static Expression clone(Expression exp) { return (Expression) exp.makeRecursiveCopy(); } public static Expression[] clone(Expression[] a) { Expression[] a2 = new Expression[a.length]; for (int i = 0; i < a.length; i++) a2[i] = clone(a[i]); return a2; } public static String[] clone(String[] a) { String[] a2 = new String[a.length]; for (int i = 0; i < a.length; i++) { a2[i] = a[i]; } return a2; } public static StatementList clone(StatementList e) { throw new UnsupportedOperationException(); } // static SortItem clone(SortItem sortItem) // { // try { // return (SortItem) sortItem.clone(); // } catch (CloneNotSupportedException e) { // Util.processInternal(e); // return null; // } // } // static SortItem[] clone(SortItem[] a) // { // SortItem[] a2 = new SortItem[a.length]; // for (int i = 0; i < a.length; i++) // a2[i] = clone(a[i]); // return a2; // } public static String toString(Rel[] a) { StringBuffer sb = new StringBuffer(); sb.append("{"); for (int i = 0; i < a.length; i++) { if (i > 0) { sb.append(", "); } sb.append(a[i]); } sb.append("}"); return sb.toString(); } static boolean isStatic(java.lang.reflect.Member member) { int modifiers = member.getModifiers(); return java.lang.reflect.Modifier.isStatic(modifiers); } // /** Same as {@link OJClass#getMethod}, except that <ul> // * // * <li>this method finds <code>boolean Object.equals(Object)</code> when // * called with <code>subjectType = java.lang.String.class</code> and // * <code>parameterTypes = {java.lang.String.class}</code>; and // * // * <li>this method returns <code>null</code> if it can't find a method. // * // * @deprecated // * @see getMethod(OJClass,name,OJClass[],OJClass) // * // * </ul> // */ // static OJMethod getMethod( // OJClass subjectType, String name, OJClass[] parameterTypes) // { // if (false) { // // naive implementation... this should work, but doesn't // try { // OJMethod method = subjectType.getMethod( // name, parameterTypes); // return method; // } catch (openjava.mop.NoSuchMemberException e) { // throw newInternal(e); // } catch (SecurityException e) { // throw newInternal(e); // } // } else if (false) { // try { // OJMethod[] methods = subjectType.getMethods(); // for (int i = 0; i < methods.length; i++) { // if (!methods[i].getName().equals(name)) { // continue; // } // OJClass[] parameterTypes2 = methods[i].getParameterTypes(); // if (parameterTypes2.length != parameterTypes.length) { // continue; // } // int nParamsNotMatched = 0; // for (int j = 0; j < parameterTypes.length; j++) { // if (!parameterTypes2[j].isAssignableFrom( // parameterTypes[j])) { // nParamsNotMatched++; // } // } // if (nParamsNotMatched > 0) { // continue; // } // // Found one! todo: Look for another, and choose between // // them. // return methods[i]; // } // } catch (SecurityException e) { // throw newInternal(e); // } // return null; // } else { // return getMethod(subjectType, name, parameterTypes, subjectType); // } // } // static OJMethod getMethod( // OJClass subjectType, String name, OJClass[] parameterTypes, // OJClass situation) // { // try { // OJMethod method = subjectType.getAcceptableMethod( // name, parameterTypes, situation); // return method; // } catch (openjava.mop.NoSuchMemberException e) { // throw newInternal(e); // } catch (SecurityException e) { // throw newInternal(e); // } // } // /** @deprecated // * @see getConstructor(OJClass,OJClass[],OJClass) // */ // static OJConstructor getConstructor( // OJClass subjectType, OJClass[] parameterTypes) // { // OJClass situation = subjectType; // return getConstructor(subjectType, parameterTypes, situation); // } // static OJConstructor getConstructor( // OJClass subjectType, OJClass[] parameterTypes, OJClass situation) // { // try { // OJConstructor constructor = subjectType.getAcceptableConstructor( // parameterTypes, situation); // return constructor; // } catch (NoSuchMemberException e) { // throw newInternal(e); // } catch (SecurityException e) { // throw newInternal(e); // } // } // static Hashtable op2nameHashtable; // static Hashtable name2opHashtable; // static Hashtable name2SymbolHashtable; // static void addOp(int op, String name, String symbol) // { // op2nameHashtable.put(new Integer(op), name); // name2opHashtable.put(name, new Integer(op)); // name2SymbolHashtable.put(name, symbol); // } // static // { // op2nameHashtable = new Hashtable(); // name2opHashtable = new Hashtable(); // name2SymbolHashtable = new Hashtable(); // addOp(SaffronParserSym.BANG, "bang", "!"); // addOp(SaffronParserSym.PLUS, "plus", "+"); // addOp(SaffronParserSym.MINUS, "minus", "-"); // addOp(SaffronParserSym.ASTERISK, "multiply", "*"); // addOp(SaffronParserSym.SOLIDUS, "divide", "/"); // addOp(SaffronParserSym.AND, "logicalAnd", "&&"); // addOp(SaffronParserSym.OR, "logicalOr", "||"); // addOp(SaffronParserSym.EQ, "opEq", "=="); // addOp(SaffronParserSym.NE, "opNe", "!="); // addOp(SaffronParserSym.LE, "opLe", "<="); // addOp(SaffronParserSym.LT, "opLt", "<"); // addOp(SaffronParserSym.GE, "opGe", ">="); // addOp(SaffronParserSym.GT, "opGt", ">"); // addOp(SaffronParserSym.IN, "in", "in"); // addOp(SaffronParserSym.EXISTS, "exists", "exists"); // } // static String op2Name(int op) // { // return (String) op2nameHashtable.get(new Integer(op)); // } // static int name2Op(String name) // { // return ((Integer) name2opHashtable.get(name)).intValue(); // } // static String name2Symbol(String name) // { // return (String) name2SymbolHashtable.get(name); // } // static private Class primitive2wrapperClass(Class clazz) // { // return clazz == Boolean.TYPE ? java.lang.Boolean.class // : clazz == Byte.TYPE ? java.lang.Byte.class // : clazz == Character.TYPE ? java.lang.Character.class // : clazz == Short.TYPE ? java.lang.Short.class // : clazz == Integer.TYPE ? java.lang.Integer.class // : clazz == Long.TYPE ? java.lang.Long.class // : clazz == Float.TYPE ? java.lang.Float.class // : clazz == Double.TYPE ? java.lang.Double.class // : clazz == Void.TYPE ? java.lang.Void.class // : null; // } // static OJMethod getInfix(int op, OJClass[] parameterTypes) // { // saffron.Util.assert(parameterTypes.length == 2); // String name = op2Name(op); // saffron.Util.assert(name != null); // OJClass classBuiltin = OJClass.forClass(saffron.Builtin.class); // return getMethod(classBuiltin, name, parameterTypes, classBuiltin); // } // static OJMethod getPrefix(int op, OJClass[] parameterTypes) // { // saffron.Util.assert(parameterTypes.length == 1); // String name = op2Name(op); // saffron.Util.assert(name != null); // OJClass classBuiltin = OJClass.forClass(saffron.Builtin.class); // return getMethod(classBuiltin, name, parameterTypes, classBuiltin); // } // static OJMethod getCast() // { // String name = "cast"; // OJClass classBuiltin = OJClass.forClass(saffron.Builtin.class); // OJClass[] parameterTypes = { // OJClass.forClass(OJClass.class), OJClass.forClass(Object.class)}; // return getMethod(classBuiltin, name, parameterTypes, classBuiltin); // } // public static final Boolean getBoolean(boolean b) // { // return b ? Boolean.TRUE : Boolean.FALSE; // } public static int[] clone(int[] a) { int[] b = new int[a.length]; for (int i = 0; i < a.length; i++) { b[i] = a[i]; } return b; } public static int hash(int i, int j) { return i << 4 ^ j; } public static OJClass getExecutableClass(OJClass clazz) { if (clazz.isExecutable()) { return clazz; } // Openjava gives us a name like "abc.def.Ghi.Jkl", but // java.lang.Class.forName needs "abc.def.Ghi$Jkl", because (luckily) // the class is inner. String name = clazz.getName(); int dot = name.lastIndexOf('.'); if (dot >= 0) { name = name.substring(0, dot) + '$' + name.substring(dot + 1); } try { Class javaClass = Class.forName(name); OJClass clazz2 = OJClass.forClass(javaClass); return clazz2; } catch (ClassNotFoundException e) { throw Toolbox.newInternal( e, "while compiling class " + name); } } public static OJField getExecutableField(OJField field) { if (field.isExecutable()) { return field; } OJClass clazz = getExecutableClass(field.getDeclaringClass()); try { return clazz.getField(field.getName()); } catch (openjava.mop.NoSuchMemberException e) { throw newInternal( e, "while compiling field " + field); } } public static Object evaluate(Expression exp) { throw new UnsupportedOperationException(); } public static void evaluate(Expression[] exps, Object[] results) { for (int i = 0; i < exps.length; i++) { results[i] = evaluate(exps[i]); } } public static boolean evaluateBoolean(Expression exp) { Boolean b = (Boolean) evaluate(exp); return b.booleanValue(); } public static double getSelectivity(Expression exp) { return 0.5; } // public static boolean contains(Expression exp, Class clazz) // { // throw new UnsupportedOperationException(); // } public static boolean containsIn(Expression exp) { InFinder inFinder = new InFinder(); try { exp.accept(inFinder); } catch (ParseTreeException e) { throw newInternal(e); } return inFinder.found; } private static class InFinder extends GenericVisitor { private boolean found; public void visit(BinaryExpression p) throws ParseTreeException { if (p.getOperator() == BinaryExpression.IN) { found = true; } else { super.visit(p); } } }; /** @deprecated use {@link Vector#toArray} on Java2 */ public static Object[] toArray(Vector v) { Object[] objects = new Object[v.size()]; v.copyInto(objects); return objects; } /** * Equivalent to {@link Vector#toArray(Object[])}. **/ public static Object[] toArray(Vector v, Object a[]) { int elementCount = v.size(); if (a.length < elementCount) { a = (Object[]) Array.newInstance( a.getClass().getComponentType(), elementCount); } v.copyInto(a); if (a.length > elementCount) { a[elementCount] = null; } return a; } /** * Returns whether two integer arrays are equal. Neither must be null. **/ public static boolean equals(int[] a, int[] b) { if (a.length != b.length) { return false; } for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) { return false; } } return true; } /** * Returns a list of variables set by a relational expression or its * descendants. **/ public static Set getVariablesSet(Rel rel) { VariableSetVisitor visitor = new VariableSetVisitor(); go(visitor, rel); return visitor.variables; } private static class VariableSetVisitor extends RelVisitor { HashSet variables = new HashSet(); // implement RelVisitor public void visit(Rel p, int ordinal, Rel parent) { if (p instanceof RelSubset) { RelSubset subset = (RelSubset) p; variables.addAll(subset.getVariablesSet()); } else { String variable = p.getCorelVariable(); if (variable != null) { variables.add(variable); } super.visit(p, ordinal, parent); } } }; /** * Returns a list of variables used by a relational expression or its * descendants. The list may contain duplicates. **/ public static Set getVariablesUsed(Rel rel) { final VariableUsedVisitor visitor = new VariableUsedVisitor(); go(new VisitorRelVisitor(visitor) { // implement RelVisitor public void visit(Rel p, int ordinal, Rel parent) { if (p instanceof RelSubset) { RelSubset subset = (RelSubset) p; ((VariableUsedVisitor) visitor).variables.addAll( subset.getVariablesUsed()); } else { super.visit(p, ordinal, parent); } } }, rel); return visitor.variables; } private static class VariableUsedVisitor extends GenericVisitor { HashSet variables = new HashSet(); public void visit(Variable p) { variables.add(p.toString()); } }; private static final String[] emptyStringArray = new String[0]; /** * Returns a set of distinct variables set by <code>rel0</code> and used by * <code>rel1</code>. **/ public static String[] getVariablesSetAndUsed(Rel rel0, Rel rel1) { Set set = getVariablesSet(rel0); if (set.size() == 0) { return emptyStringArray; } Set used = getVariablesUsed(rel1); if (used.size() == 0) { return emptyStringArray; } Vector result = new Vector(); for (Iterator vars = set.iterator(); vars.hasNext();) { String s = (String) vars.next(); if (used.contains(s) && !result.contains(s)) { result.addElement(s); } } if (result.size() == 0) { return emptyStringArray; } String[] resultArray = new String[result.size()]; result.copyInto(resultArray); return resultArray; } // public static synchronized PrintWriter getDebug() // { // if (debugWriter == null) { // boolean autoFlush = true; // debugWriter = new PrintWriter(System.out, autoFlush); // } // return debugWriter; // } /** * Returns an array of this <code>ParseTree</code>'s children. Note that * it returns an empty array, not <code>null</code>, if there are no * children. */ // public static ParseTree[] getChildren(ParseTree p) // { // if (p instanceof Rel) { // Rel rel = (Rel) p; // return rel.getChildren(); // } else { // ChildCollector childCollector = new ChildCollector(); // try { // p.childrenAccept(childCollector); // } catch (ParseTreeException e) { // throw Toolbox.newInternal(e); // } // return childCollector.getChildren(); // } // } // private static class ChildCollector extends GenericVisitor // { // Vector v = new Vector(); // // implement GenericVisitor // public void visit(ParseTree p) // { // v.addElement(p); // } // public ParseTree[] getChildren() // { // ParseTree[] children = new ParseTree[v.size()]; // v.copyInto(children); // return children; // } // }; /** * Sets a {@link RelVisitor} going on a given relational expression, * and returns the result. **/ public static Rel go(RelVisitor visitor, Rel p) { RelHolder root = new RelHolder(p); try { visitor.visit(root, -1, null); } catch (Throwable e) { throw newInternal(e, "while visiting tree"); } return root.get(); } private static class RelHolder extends Rel { Rel p; RelHolder(Rel p) { super(p.getCluster()); this.p = p; } public Rel[] getInputs() { return new Rel[] {p}; } public void replaceInput(int ordinalInParent, Rel p) { Util.assert(ordinalInParent == 0); this.p = p; } Rel get() { return p; } public OJClass deriveRowType() { throw new UnsupportedOperationException(); } public Object clone() { throw new UnsupportedOperationException(); } }; // private static class Holder extends NonLeaf // { // Holder(ParseTree p) // { // set(p); // } // public void accept(ParseTreeVisitor visitor) throws ParseTreeException // { // visitor.visit(this); // } // ParseTree get() // { // return (ParseTree) elementAt(0); // } // }; // private static class Holder extends Rel // { // Rel[] inputs; // Holder(Rel[] inputs) // { // super((Environment) null); // this.inputs = inputs; // } // // implement QueryPart // public Object clone() throws CloneNotSupportedException // { // throw new CloneNotSupportedException(); // } // // implement Rel // public Rel[] getInputs() // { // return inputs; // } // // implement QueryPart // public void replaceChild(int ordinalInParent, Expression p) // { // inputs[ordinalInParent] = (Rel) p; // } // // implement Rel // public OJClass deriveRowType() // { // throw new UnsupportedOperationException(); // } // // implement Rel // public Object evaluate() // { // throw new UnsupportedOperationException(); // } // }; public static OJClass leastRestrictiveClass(OJClass clazz1, OJClass clazz2) { if (clazz1 == clazz2) { return clazz1; } if (clazz1.isAssignableFrom(clazz2)) { return clazz1; } if (clazz2.isAssignableFrom(clazz1)) { return clazz2; } return null; // todo: if D1 extends B1, and D2 extends B2, then // leastRestrictiveClass((B1,D2), (D1,B2)) should be (B1,B2). } /** * Returns a description of what variables are unbound inside * <code>rel</code>. **/ public static UnboundVariableCollector getUnboundVariables(Rel rel) { UnboundVariableCollector unboundVars = new UnboundVariableCollector( rel.getCluster().env); go(new VisitorRelVisitor(unboundVars), rel); return unboundVars; } /** * Computes <code>n * logn(n)</code> (or <code>n</code> if <code>n</code> * is small, so the result is never negative. **/ public static double nLogN(double d) { return d < Math.E ? d : (d * Math.log(d)); } /** * Properties object provides an environment for debugging information, * et cetera. It is a singleton. * * <p>It is populated from System properties if saffron is invoked * via a <code>main()</code> method, from a {@link ServletContext} if * saffron is invoked from a servlet, and so forth. * * <p>If there is a file called <code>saffron.properties</code>, it is * read. */ public static PropertiesPlus getProperties() { if (properties == null) { properties = new PropertiesPlus(); // read properties from the file "saffron.properties", if it exists File file = new File("saffron.properties"); if (file.exists()) { try { properties.load(new FileInputStream(file)); } catch (IOException e) { throw newInternal(e, "while reading from " + file); } } // copy in all system properties which start with "saffron." for (Enumeration keys = System.getProperties().keys(); keys.hasMoreElements(); ) { String key = (String) keys.nextElement(); String value = System.getProperty(key); if (key.startsWith("saffron.")) { properties.setProperty(key, value); } } } return properties; } /** * The singleton properties object. */ private static PropertiesPlus properties; /** * <code>PropertiesPlus</code> adds a couple of convenience methods to * {@link Properties}. */ public static class PropertiesPlus extends Properties { /** * Retrieves an integer property. Returns -1 if the property is not * found, or if its value is not an integer. */ public int getIntProperty(String key) { String value = getProperty(key); if (value == null) { return -1; } int i = Integer.valueOf(value).intValue(); return i; } /** * Retrieves a boolean property. Returns <code>true</code> if the * property exists, and its value is <code>1</code>, <code>true</code> * or <code>yes</code>; returns <code>false</code> otherwise. */ public boolean getBooleanProperty(String key) { String value = getProperty(key); if (value == null) { return false; } return value.equalsIgnoreCase("1") || value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"); } } /** * Applies properties to the right locations. **/ public static void applyProperties() { int debugLevel = getProperties().getIntProperty("saffron.debug.level"); String debugOut = getProperties().getProperty("saffron.debug.out"); if (debugLevel >= 0) { DebugOut.setDebugLevel(debugLevel); if (debugOut == null || debugOut.equals("")) { debugOut = "out"; } } if (debugOut != null && !debugOut.equals("")) { if (debugOut.equals("err")) { DebugOut.setDebugOut(System.err); } else if (debugOut.equals("out")) { DebugOut.setDebugOut(System.out); } else { try { File file = new File(debugOut); PrintStream ps = new PrintStream( new FileOutputStream(file), true); DebugOut.setDebugOut(ps); } catch (FileNotFoundException e) { throw Util.newInternal(e, "while setting debug output"); } } } } } // End Util.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#5 | 1818 | Julian Hyde |
saffron: Oops (forgot ParseTreeAction.java), Correlation now works, Smarter code generation (now burrow into synthetic classes, rather than invoking constructors). |
||
#4 | 1801 | Julian Hyde |
saffron: add ObjectSchema; rules can now be matched more than once; started to implement correlations in queries in from list. |
||
#3 | 1748 | Julian Hyde |
saffron: convert unit tests to JUnit; add CallingConvention.ITERABLE; lots of other stuff; release 0.1. |
||
#2 | 1474 | Julian Hyde |
saffron: Aggregations are working. Renamed 'aggregator' to 'aggregation'. |
||
#1 | 1467 | Julian Hyde |
saffron: First saffron check-in; incorporate my changes to openjava. |