0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 1997-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.tools.build;
0028:
0029: import java.io.BufferedReader;
0030: import java.io.File;
0031: import java.io.FileInputStream;
0032: import java.io.FileOutputStream;
0033: import java.io.IOException;
0034: import java.io.InputStream;
0035: import java.io.InputStreamReader;
0036: import java.io.OutputStreamWriter;
0037: import java.io.PrintWriter;
0038: import java.util.ArrayList;
0039: import java.util.Collection;
0040: import java.util.HashMap;
0041: import java.util.List;
0042: import java.util.Map;
0043: import java.util.Set;
0044:
0045: public class MeasureWriter extends WriterBase {
0046: class Parser {
0047: private InputStream s;
0048: private Map<String, Map<String, Object>> table = new HashMap<String, Map<String, Object>>();
0049:
0050: public Parser(InputStream s) {
0051: this .s = s;
0052: }
0053:
0054: public Map<String, Object> getContext(String context) {
0055: Map<String, Object> o = table.get(context);
0056: if (o == null) {
0057: o = new HashMap<String, Object>();
0058: table.put(context, o);
0059: }
0060: return o;
0061: }
0062:
0063: public void put(String context, String key, String value) {
0064: Map<String, Object> ct = getContext(context);
0065: ct.put(key, value);
0066: }
0067:
0068: public void _put(String context, String key, Object value) {
0069: Map<String, Object> ct = getContext(context);
0070: ct.put(key, value);
0071: }
0072:
0073: public String get(String context, String key) {
0074: Map<String, Object> ct = getContext(context);
0075: return (String) ct.get(key);
0076: }
0077:
0078: public Object _get(String context, String key) {
0079: Map<String, Object> ct = getContext(context);
0080: return ct.get(key);
0081: }
0082:
0083: public Set<String> getContexts() {
0084: return table.keySet();
0085: }
0086:
0087: public void parse() throws IOException {
0088: parse(s, false);
0089: }
0090:
0091: public void parse(InputStream s, boolean included)
0092: throws IOException {
0093: InputStreamReader isr = new InputStreamReader(s);
0094: BufferedReader br = new BufferedReader(isr);
0095: String context = "global";
0096: int i;
0097:
0098: getContext(context);
0099: for (String line = br.readLine(); line != null; line = br
0100: .readLine()) {
0101: line = line.trim();
0102: if (line.length() == 0 || line.startsWith(";")) {
0103: // empty or comment line
0104: } else {
0105: while (line.endsWith("\\")) {
0106: String more = br.readLine();
0107: if (more == null)
0108: throw new IOException("Unexpected EOF");
0109: line = line.substring(0, line.length() - 1)
0110: + more.trim();
0111: }
0112:
0113: if (line.startsWith("includedefs")) {
0114: i = line.indexOf("=");
0115: if (i > 0) {
0116: String fileName = line.substring(i + 1,
0117: line.length()).trim();
0118: InputStream stream = getClass()
0119: .getClassLoader()
0120: .getResourceAsStream(fileName);
0121: try {
0122: parse(stream, true);
0123: } catch (Exception e) {
0124: System.err
0125: .println("Could not find resource "
0126: + fileName
0127: + " referenced by includedefs on classpath. Aborting.");
0128: System.exit(-1); // something better to do here than exit? should we continue?
0129: }
0130: if (stream != null)
0131: stream.close();
0132: } else {
0133: debug("Bad line \"" + line + "\"");
0134: }
0135: }
0136:
0137: if (line.startsWith("[") && line.endsWith("]")) { // new context
0138: context = line.substring(1, line.length() - 1);
0139: debug("Parsing Measure \"" + context + "\"");
0140: getContext(context); // setup the new context
0141: if (!included) {
0142: put(context, PGParser.PG_SOURCE,
0143: PGParser.PRIMARY);
0144: } else {
0145: put(context, PGParser.PG_SOURCE,
0146: PGParser.INCLUDED);
0147: }
0148: } else if ((i = line.indexOf("=")) >= 0) { // key/value pair
0149: String key = line.substring(0, i);
0150: String value = line.substring(i + 1, line
0151: .length());
0152: put(context, key, value);
0153: } else {
0154: debug("Bad line \"" + line + "\"");
0155: }
0156: }
0157: }
0158: }
0159: }
0160:
0161: class Writer {
0162: private PrintWriter filelist = null;
0163: private Parser p;
0164:
0165: public Writer(Parser p) {
0166: this .p = p;
0167: try {
0168: filelist = new PrintWriter(new OutputStreamWriter(
0169: new FileOutputStream(new File(getTargetDir(),
0170: getGenFileName()))));
0171: noteFile(getGenFileName());
0172: } catch (IOException ioe) {
0173: throw new RuntimeException();
0174: }
0175: }
0176:
0177: public void noteFile(String s) {
0178: println(filelist, s);
0179: }
0180:
0181: public void done() {
0182: filelist.close();
0183: }
0184:
0185: void grokGlobal() {
0186: }
0187:
0188: /**
0189: * convert a string like foo_bar_baz to FooBarBaz
0190: * @param s to convert
0191: * @return proper class name for s
0192: **/
0193: String toClassName(String s) {
0194: StringBuffer b = new StringBuffer();
0195: boolean isFirst = true;
0196:
0197: for (int i = 0; i < s.length(); i++) {
0198: char c = s.charAt(i);
0199: if (c == '_') {
0200: isFirst = true;
0201: } else {
0202: if (isFirst && Character.isLowerCase(c))
0203: c = Character.toUpperCase(c);
0204: isFirst = false;
0205: b.append(c);
0206: }
0207: }
0208:
0209: return b.toString();
0210: }
0211:
0212: /**
0213: * convert a string like foo_bar_baz to fooBarBaz
0214: * @param s to convert
0215: * @return variable name
0216: **/
0217: String toVariableName(String s) {
0218: StringBuffer b = new StringBuffer();
0219: boolean isFirst = true;
0220: boolean isStart = true;
0221:
0222: for (int i = 0; i < s.length(); i++) {
0223: char c = s.charAt(i);
0224: if (c == '_') {
0225: isFirst = true;
0226: } else {
0227: if (isStart && isFirst && Character.isLowerCase(c))
0228: c = Character.toUpperCase(c);
0229: isFirst = false;
0230: isStart = false;
0231: b.append(c);
0232: }
0233: }
0234:
0235: return b.toString();
0236: }
0237:
0238: /**
0239: * convert a string like foo_bar_baz to FOO_BAR_BAZ
0240: * @param s to convert
0241: * @return all caps name
0242: **/
0243: String toConstantName(String s) {
0244: StringBuffer b = new StringBuffer();
0245:
0246: for (int i = 0; i < s.length(); i++) {
0247: char c = s.charAt(i);
0248: if (Character.isLowerCase(c))
0249: c = Character.toUpperCase(c);
0250: b.append(c);
0251: }
0252:
0253: return b.toString();
0254: }
0255:
0256: String unpluralize(String s) {
0257: if (s.endsWith("s"))
0258: return s.substring(0, s.length() - 1);
0259: if (s.equals("feet"))
0260: return "foot";
0261: return s;
0262: }
0263:
0264: void writePrelude(PrintWriter out, String context,
0265: String className, String outname) {
0266: writeCR(out, deffilename);
0267: println(out, "/** Immutable implementation of " + className
0268: + ".");
0269: println(out, " **/");
0270: println(out);
0271: println(out);
0272: println(out, "package " + getPackageFromDir(getSourceDir())
0273: + ";");
0274: println(out, "import java.io.*;");
0275: doImports(out, "global");
0276: if (!context.equals("global"))
0277: doImports(out, context);
0278: println(out);
0279: }
0280:
0281: void doImports(PrintWriter out, String context) {
0282: String importstr = (String) p.get(context, "import");
0283: if (importstr != null) {
0284: List<String> imports = explode(importstr, ',');
0285: for (String importedClass : imports) {
0286: println(out, "import " + importedClass + ";");
0287: }
0288: }
0289: println(out);
0290: }
0291:
0292: List<String> explode(String s) {
0293: return explode(s, ' ');
0294: }
0295:
0296: List<String> explode(String s, char x) {
0297: List<String> r = new ArrayList<String>();
0298: int last = 0;
0299: for (int i = 0; i < s.length(); i++) {
0300: char c = s.charAt(i);
0301: if (c == x) {
0302: if (i > last)
0303: r.add(s.substring(last, i));
0304: last = i + 1;
0305: }
0306: }
0307: if (s.length() > last)
0308: r.add(s.substring(last));
0309: return r;
0310: }
0311:
0312: List<String> explodeC(String s, char burst) {
0313: List<String> r = new ArrayList<String>();
0314: int last = 0;
0315: for (int i = 0; i < s.length(); i++) {
0316: char c = s.charAt(i);
0317: if (c == burst) {
0318: if (i > last)
0319: r.add(s.substring(last, i));
0320: last = i + 1;
0321: }
0322: }
0323: if (s.length() > last)
0324: r.add(s.substring(last));
0325: return r;
0326: }
0327:
0328: /**
0329: * return the value factor required to convert a value from the base unit of
0330: * the context to the requested unit.
0331: * @param context to use
0332: * @param unit to convert to
0333: * @return string like 1.0d/3.14159
0334: **/
0335: String computeToFactor(String context, String unit) {
0336: String base = getBaseUnit(context);
0337: if (base.equals(unit))
0338: return "1.0d";
0339: String tobase = p.get(context, "to_" + unit);
0340: if (tobase != null) {
0341: return tobase;
0342: } else {
0343: String frombase = p.get(context, "from_" + unit);
0344: if (frombase == null) {
0345: // no info here! Try what we extend:
0346: return computeToFactor(p.get(context, "extends"),
0347: unit);
0348: }
0349: return "(1.0d/" + frombase + ")";
0350: }
0351: }
0352:
0353: /**
0354: * return the value factor required to convert a value from the requested unit
0355: * to the base unit of the context.
0356: * @param context to use
0357: * @param unit to convert to
0358: * @return string like 1.0d/3.14159
0359: **/
0360: String computeFromFactor(String context, String unit) {
0361: if (context == null) {
0362: System.err.println("Context is null for unit '" + unit
0363: + "'");
0364: return "1.0d";
0365: }
0366: String base = getBaseUnit(context);
0367: if (base.equals(unit))
0368: return "1.0d";
0369: String frombase = p.get(context, "from_" + unit);
0370: if (frombase != null) {
0371: return frombase;
0372: } else {
0373: String tobase = p.get(context, "to_" + unit);
0374: if (tobase == null) {
0375: // no info here! Try what we extend:
0376: return computeFromFactor(p.get(context, "extends"),
0377: unit);
0378: }
0379: return "(1.0d/" + tobase + ")";
0380: }
0381: }
0382:
0383: @SuppressWarnings("unchecked")
0384: List<String> getUnitV(String context) {
0385: List<String> v = (List<String>) p._get(context, "_units");
0386: if (v != null)
0387: return v;
0388:
0389: String units = p.get(context, "units");
0390: if (units != null) {
0391: v = explode(units);
0392: p._put(context, "_units", v);
0393: return v;
0394: }
0395: String ext = p.get(context, "extends");
0396: if (ext != null) {
0397: v = getUnitV(ext);
0398: if (v != null) {
0399: p._put(context, "_units", v);
0400: }
0401: return v;
0402: }
0403: return null;
0404: }
0405:
0406: String getBaseUnit(String context) {
0407: String base = p.get(context, "base");
0408: if (base == null) {
0409: Collection<String> units = getUnitV(context);
0410: if (units == null || units.isEmpty()) {
0411: System.err.println("Can't find any units within "
0412: + context);
0413: return "unknown";
0414: } else {
0415: return units.iterator().next();
0416: }
0417: } else {
0418: return base;
0419: }
0420: }
0421:
0422: void writeClass(PrintWriter out, String context,
0423: String className) {
0424: String isDep = p.get(context, "deprecated");
0425: if (isDep != null) {
0426: println(out, "/** @deprecated " + isDep + " **/");
0427: }
0428:
0429: String ext = p.get(context, "extends");
0430: if (ext == null)
0431: ext = "AbstractMeasure";
0432: boolean isFinal = !("false".equals(p.get(context, "final")));
0433: println(out, "public " + (isFinal ? "final " : "")
0434: + "class " + className + " extends " + ext
0435: + " implements Externalizable {");
0436: // get units
0437: List<String> units = getUnitV(context);
0438: String base = getBaseUnit(context);
0439: String baseabbrev = p.get(context, "baseabbrev");
0440: if (baseabbrev == null)
0441: baseabbrev = base;
0442:
0443: // write static factors
0444: println(out, " // Conversion factor constants");
0445: for (String unit : units) {
0446: if (!unit.equals(base)) {
0447: // f is the factor of (1 unit) = f * (1 baseunit);
0448: String fact1 = toConstantName(base + "_PER_" + unit);
0449: String fromf = computeFromFactor(context, unit);
0450: println(out, " public static final double "
0451: + fact1 + " = " + fromf + ";");
0452: String fact2 = toConstantName(unit + "_PER_" + base);
0453: String tof = computeToFactor(context, unit);
0454: println(out, " public static final double "
0455: + fact2 + " = " + tof + ";");
0456: }
0457: }
0458: println(out);
0459:
0460: // the storage
0461: println(out, " // the value is stored as " + base);
0462: println(out, " private double theValue;");
0463: println(out);
0464:
0465: println(out,
0466: " /** No-arg constructor is only for use by serialization **/");
0467: println(out, " public " + className + "() {}");
0468: println(out);
0469:
0470: // constructor
0471: println(out, " // private constructor");
0472: println(out, " private " + className + "(double v) {");
0473: println(out, " theValue = v;");
0474: println(out, " }");
0475: println(out);
0476:
0477: // public constructor
0478: println(out, " /** parameterized constructor **/");
0479: println(out, " public " + className
0480: + "(double v, int unit) {");
0481: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
0482: println(out, " theValue = v*getConvFactor(unit);");
0483: println(out, " else");
0484: println(out, " throw new UnknownUnitException();");
0485: println(out, " }");
0486: println(out);
0487:
0488: println(out,
0489: " /** takes strings of the form \"Number unit\" **/");
0490: println(out, " public " + className + "(String s) {");
0491: println(out, " int i = indexOfType(s);");
0492: println(out,
0493: " if (i < 0) throw new UnknownUnitException();");
0494: println(out,
0495: " double n = Double.valueOf(s.substring(0,i).trim()).doubleValue();");
0496: println(out,
0497: " String u = s.substring(i).trim().toLowerCase();");
0498: print(out, " ");
0499: for (String unit : units) {
0500: String unitName = toClassName(unit);
0501: String fexpr = "";
0502: if (!unit.equals(base)) {
0503: fexpr = "*" + toConstantName(base + "_PER_" + unit);
0504: }
0505: println(out, "if (u.equals(\"" + unitName.toLowerCase()
0506: + "\")) ");
0507: println(out, " theValue=n" + fexpr + ";");
0508: print(out, " else ");
0509: }
0510: println(out, "\n throw new UnknownUnitException();");
0511: println(out, " }");
0512: println(out);
0513:
0514: // Named type factory methods
0515: println(out, " // TypeNamed factory methods");
0516: for (String unit : units) {
0517: String unitName = toClassName(unit);
0518: String fexpr = "";
0519: if (!unit.equals(base)) {
0520: fexpr = "*" + toConstantName(base + "_PER_" + unit);
0521: }
0522: println(out, " public static final " + className
0523: + " new" + unitName + "(double v) {");
0524: println(out, " return new " + className + "(v"
0525: + fexpr + ");");
0526: println(out, " }");
0527: println(out, " public static final " + className
0528: + " new" + unitName + "(String s) {");
0529: println(out, " return new " + className
0530: + "((Double.valueOf(s).doubleValue())" + fexpr
0531: + ");");
0532: println(out, " }");
0533: }
0534: println(out);
0535:
0536: // common unit support - mostly a bogon
0537: println(out);
0538: println(out, " public int getCommonUnit() {");
0539: String cus = p.get(context, "common");
0540: if (cus == null) {
0541: println(out, " return 0;");
0542: } else {
0543: println(out, " return " + cus.toUpperCase() + ";");
0544: }
0545: println(out, " }");
0546: println(out);
0547: println(out,
0548: " public int getMaxUnit() { return MAXUNIT; }");
0549: println(out);
0550:
0551: println(out, " // unit names for getUnitName");
0552: println(out, " private static final String unitNames[]={");
0553: for (String unit : units) {
0554: println(out, " \"" + unit + "\",");
0555: }
0556: println(out, " };");
0557: println(out);
0558: println(out, " public String getUnitName(int unit) {");
0559: println(out, " return unitNames[unit];");
0560: println(out, " }");
0561: println(out);
0562:
0563: // index typed factory methods
0564: println(out, " // Index Typed factory methods");
0565: println(out, " static final double convFactor[]={");
0566: for (String unit : units) {
0567: String fexpr = "1.0";
0568: if (!unit.equals(base)) {
0569: fexpr = toConstantName(base + "_PER_" + unit);
0570: }
0571: println(out, " " + fexpr + ",");
0572: }
0573: println(out, " };");
0574: writeConvFactorAccessor(out);
0575: println(out, " // indexes into factor array");
0576: int i = 0;
0577: for (String unit : units) {
0578: String unitName = toConstantName(unit);
0579: println(out, " public static final int " + unitName
0580: + " = " + i + ";");
0581: i++;
0582: }
0583: println(out, " public static final int MAXUNIT = "
0584: + (i - 1) + ";");
0585: println(out);
0586: println(out, " // Index Typed factory methods");
0587: println(out, " public static final " + className + " new"
0588: + className + "(double v, int unit) {");
0589: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
0590: println(out, " return new " + className
0591: + "(v*getConvFactor(unit));");
0592: println(out, " else");
0593: println(out, " throw new UnknownUnitException();");
0594: println(out, " }");
0595: println(out);
0596: println(out, " public static final " + className + " new"
0597: + className + "(String s, int unit) {");
0598: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
0599: println(
0600: out,
0601: " return new "
0602: + className
0603: + "((Double.valueOf(s).doubleValue())*getConvFactor(unit));");
0604: println(out, " else");
0605: println(out, " throw new UnknownUnitException();");
0606: println(out, " }");
0607: println(out);
0608:
0609: // abstractmeasure-level concretefactory
0610: writeNewMeasureMethods(out, className);
0611:
0612: writeAddSubtractMethods(out, className);
0613: writeDivide(out, className);
0614:
0615: // getters
0616: println(out, " // Unit-based Reader methods");
0617: for (String unit : units) {
0618: String unitName = toClassName(unit);
0619: String fexpr = "";
0620: if (!unit.equals(base)) {
0621: //fexpr = "*"+toConstantName(unit+"_PER_"+base);
0622: fexpr = "/" + toConstantName(base + "_PER_" + unit);
0623: }
0624: println(out, " public double get" + unitName + "() {");
0625: println(out, " return (theValue" + fexpr + ");");
0626: println(out, " }");
0627: }
0628: println(out);
0629:
0630: // unit-as-argument getter
0631: println(out, " public double getValue(int unit) {");
0632: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
0633: println(out, " return (theValue/getConvFactor(unit));");
0634: println(out, " else");
0635: println(out, " throw new UnknownUnitException();");
0636: println(out, " }");
0637: println(out);
0638:
0639: // equals et al
0640: println(out, " public boolean equals(Object o) {");
0641: println(out, " return ( o instanceof " + className
0642: + " &&");
0643: println(out, " theValue == ((" + className
0644: + ") o).theValue);");
0645: println(out, " }");
0646: println(out, " public String toString() {");
0647: println(out, " return Double.toString(theValue) + \""
0648: + baseabbrev + "\";");
0649: println(out, " }");
0650: println(out, " public int hashCode() {");
0651: println(out,
0652: " return (new Double(theValue)).hashCode();");
0653: println(out, " }");
0654:
0655: println(out);
0656: println(out, " // serialization");
0657: println(out,
0658: " public void writeExternal(ObjectOutput out) throws IOException {\n"
0659: + " out.writeDouble(theValue);\n"
0660: + " }");
0661: println(out,
0662: " public void readExternal(ObjectInput in) throws IOException {\n"
0663: + " theValue = in.readDouble();\n"
0664: + " }");
0665:
0666: // that's all, folks
0667: println(out, "}");
0668:
0669: }
0670:
0671: /**
0672: * @see #writeClass
0673: * @see #writeClassDt
0674: * @param out to write to
0675: * @param className that we are writing right now, e.g. Volume
0676: */
0677: private void writeAddSubtractMethods(PrintWriter out,
0678: String className) {
0679: println(out, " // simple math : addition and subtraction");
0680:
0681: println(out, " public final Measure add(Measure toAdd) {");
0682: println(out, " if (!(toAdd instanceof " + className
0683: + ")) throw new IllegalArgumentException();");
0684: println(out, " return new " + className
0685: + "(theValue + toAdd.getNativeValue());");
0686: println(out, " }");
0687: println(out,
0688: " public final Measure subtract(Measure toSubtract) {");
0689: println(out, " if (!(toSubtract instanceof " + className
0690: + ")) throw new IllegalArgumentException();");
0691: println(out, " return new " + className
0692: + "(theValue - toSubtract.getNativeValue());");
0693: println(out, " }");
0694: println(out);
0695:
0696: println(out, " public final Measure scale(double scale) {");
0697: println(out, " return new " + className
0698: + "(theValue*scale,0);");
0699: println(out, " }");
0700: println(out);
0701: /* println(out," public <D extends Measure> GenericDerivative GenericDerivative(D denom) {");
0702: println(out," return new GenericDerivative<"+className+",D>(this, denom);");
0703: println(out," }");
0704: println(out);*/
0705:
0706: println(out, " public final Measure negate() {");
0707: println(out, " return new" + className
0708: + "(-1 * theValue,0);");
0709: println(out, " }");
0710: println(out);
0711: println(out, " public final Measure floor(int unit) {");
0712: println(out, " return new" + className
0713: + "(Math.floor(getValue(unit)),0);");
0714: println(out, " }");
0715: println(out);
0716: println(out,
0717: " public final Measure valueOf(double value) {");
0718: println(out, " return new " + className + "(value);");
0719: println(out, " }");
0720: println(out);
0721: println(out,
0722: " public final Measure valueOf(double value, int unit) {");
0723: println(out, " return new " + className
0724: + "(value, unit);");
0725: println(out, " }");
0726: println(out);
0727: println(out, " public final double getNativeValue() {");
0728: println(out, " return theValue;");
0729: println(out, " }");
0730: println(out);
0731: println(out, " public final int getNativeUnit() {");
0732: println(out, " return 0;");
0733: println(out, " }");
0734: println(out);
0735: }
0736:
0737: private void writeDivide(PrintWriter out, String className) {
0738: println(out,
0739: " public final Duration divide(Rate toRate) {");
0740: println(out,
0741: " Measure canonicalNumerator = toRate.getCanonicalNumerator();");
0742: println(out,
0743: " if (!(toRate.getCanonicalNumerator() instanceof "
0744: + className + ")) {");
0745: println(out,
0746: " throw new IllegalArgumentException(\"Expecting a "
0747: + className + "/Duration\");");
0748: println(out, " }");
0749: println(
0750: out,
0751: " int durationNativeUnit = toRate.getCanonicalDenominator().getNativeUnit(); // seconds");
0752: println(
0753: out,
0754: " double value = toRate.getValue(canonicalNumerator.getNativeUnit(), durationNativeUnit); // ?/seconds");
0755: println(
0756: out,
0757: " return new Duration(theValue/ value,durationNativeUnit); // ?/?/second = seconds");
0758: println(out, " }");
0759: println(out);
0760: }
0761:
0762: private void writeDivideDerivative(PrintWriter out,
0763: String className) {
0764: println(out,
0765: " public final Duration divide(Rate toRate) {");
0766: println(
0767: out,
0768: " throw new IllegalArgumentException(\"Call divideRate instead to divide one Rate by another.\");");
0769: println(out, " }");
0770: println(out);
0771: println(out,
0772: " public final double divideRate(Rate toRate) {");
0773: println(
0774: out,
0775: " if (toRate.getCanonicalNumerator().getClass() != getCanonicalNumerator().getClass() ||");
0776: println(
0777: out,
0778: " toRate.getCanonicalDenominator().getClass() != getCanonicalDenominator().getClass()) {");
0779: println(out,
0780: " throw new IllegalArgumentException(\"Expecting a "
0781: + className + "\" + ");
0782: println(
0783: out,
0784: " \", got a \" + toRate.getCanonicalNumerator().getClass() + \"/\" + toRate.getCanonicalDenominator().getClass());");
0785: println(out, " }");
0786: println(out, " return theValue/toRate.getNativeValue();");
0787: println(out, " }");
0788: println(out);
0789: }
0790:
0791: private void writeNewMeasureMethods(PrintWriter out,
0792: String className) {
0793: println(out,
0794: " // Support for AbstractMeasure-level constructor");
0795: println(out,
0796: " public static final AbstractMeasure newMeasure(String s, int unit) {");
0797: println(out, " return new" + className + "(s, unit);");
0798: println(out, " }");
0799: println(out,
0800: " public static final AbstractMeasure newMeasure(double v, int unit) {");
0801: println(out, " return new" + className + "(v, unit);");
0802: println(out, " }");
0803: }
0804:
0805: void writeClassDt(PrintWriter out, String context,
0806: String className) {
0807: List<String> mV = explodeC(p.get(context, "derivative"),
0808: '/');
0809: final String dC = mV.get(0);
0810: final String dtC = mV.get(1);
0811:
0812: String dB = getBaseUnit(dC);
0813: String dtB = getBaseUnit(dtC);
0814:
0815: String baseabbrev = p.get(context, "baseabbrev");
0816: if (baseabbrev == null) {
0817: String ab1 = p.get(dC, "baseabbrev");
0818: if (ab1 == null)
0819: ab1 = dB;
0820: String ab2 = p.get(dtC, "baseabbrev");
0821: if (ab2 == null)
0822: ab2 = dtB;
0823: baseabbrev = ab1 + "/" + ab2;
0824: }
0825:
0826: class UnitTuple {
0827: String num;
0828: String den;
0829: String sden;
0830: String factor;
0831:
0832: UnitTuple(String n, String d) {
0833: num = n;
0834: den = d;
0835: sden = unpluralize(den);
0836: String nF = computeToFactor(dC, n);
0837: String dF = computeToFactor(dtC, d);
0838: factor = "(" + nF + "/" + dF + ")";
0839: }
0840: }
0841:
0842: List<UnitTuple> tuples = new ArrayList<UnitTuple>();
0843: List<String> numV = getUnitV(dC);
0844: List<String> denV = getUnitV(dtC);
0845: for (String nU : numV) {
0846: for (String dU : denV) {
0847: tuples.add(new UnitTuple(nU, dU));
0848: }
0849: }
0850:
0851: String isDep = p.get(context, "deprecated");
0852: if (isDep != null) {
0853: println(out, "/** @deprecated " + isDep + " **/");
0854: }
0855:
0856: // the class def
0857: String ext = p.get(context, "extends");
0858: if (ext == null)
0859: ext = "AbstractMeasure";
0860: println(out, "public final class " + className
0861: + " extends " + ext);
0862: print(out, " implements Externalizable, Derivative");
0863: String denC = p.get(dtC, "denominator_class");
0864: if (denC != null) {
0865: print(out, ", " + denC);
0866: }
0867: println(out, " {");
0868:
0869: // the storage
0870: println(out, " // the value is stored as " + dB + "/"
0871: + unpluralize(dtB));
0872: println(out, " private double theValue;");
0873: println(out);
0874:
0875: println(out,
0876: " /** No-arg constructor is only for use by serialization **/");
0877: println(out, " public " + className + "() {}");
0878: println(out);
0879:
0880: // constructor
0881: println(out, " // private constructor");
0882: println(out, " private " + className + "(double v) {");
0883: println(out, " theValue = v;");
0884: println(out, " }");
0885: println(out);
0886:
0887: // public constructor
0888: println(out,
0889: " /** @param unit One of the constant units of "
0890: + className + " **/");
0891: println(out, " public " + className
0892: + "(double v, int unit) {");
0893: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
0894: println(out, " theValue = v/getConvFactor(unit);");
0895: println(out, " else");
0896: println(out, " throw new UnknownUnitException();");
0897: println(out, " }");
0898: println(out);
0899: println(
0900: out,
0901: " /** @param unit1 One of the constant units of "
0902: + dC
0903: + "\n"
0904: + " * @param unit2 One of the constant units of "
0905: + dtC + "\n" + " **/");
0906: println(out, " public " + className
0907: + "(double v, int unit1, int unit2) {");
0908: println(out, " if (unit1 >= 0 && unit1 <= " + dC
0909: + ".MAXUNIT &&\n"
0910: + " unit2 >= 0 && unit2 <= " + dtC
0911: + ".MAXUNIT)");
0912: println(out, " theValue = v*" + dC
0913: + ".getConvFactor(unit1)/" + dtC
0914: + ".getConvFactor(unit2);");
0915: println(out, " else");
0916: println(out, " throw new UnknownUnitException();");
0917: println(out, " }");
0918: println(out);
0919:
0920: println(out, " /** @param num An instance of " + dC
0921: + " to use as numerator\n"
0922: + " * @param den An instance of " + dtC
0923: + "to use as denominator\n" + " **/");
0924: println(out, " public " + className + "(" + dC + " num, "
0925: + dtC + " den) {");
0926: println(out,
0927: " theValue = num.getValue(0)/den.getValue(0);");
0928: println(out, " }");
0929: println(out);
0930:
0931: println(out,
0932: " /** takes strings of the form \"Number unit\" **/");
0933: println(out, " public " + className + "(String s) {");
0934: println(out, " int i = indexOfType(s);");
0935: println(out,
0936: " if (i < 0) throw new UnknownUnitException();");
0937: println(out,
0938: " double n = Double.valueOf(s.substring(0,i).trim()).doubleValue();");
0939: println(out,
0940: " String u = s.substring(i).trim().toLowerCase();");
0941: print(out, " ");
0942: for (UnitTuple ut : tuples) {
0943: println(out, "if (u.equals(\""
0944: + toClassName(ut.num + "per" + ut.sden)
0945: .toLowerCase() + "\")) ");
0946: println(out, " theValue=n/" + ut.factor + ";");
0947: print(out, " else ");
0948: }
0949: println(out, "\n throw new UnknownUnitException();");
0950: println(out, " }");
0951: println(out);
0952:
0953: // Named type factory methods
0954: println(out, " // TypeNamed factory methods");
0955: for (UnitTuple ut : tuples) {
0956: String unit = ut.num + "_per_" + ut.sden;
0957: String unitName = toClassName(unit);
0958: String fexpr = "*(1.0d/" + ut.factor + ")";
0959:
0960: println(out, " public static final " + className
0961: + " new" + unitName + "(double v) {");
0962: println(out, " return new " + className + "(v"
0963: + fexpr + ");");
0964: println(out, " }");
0965: println(out, " public static final " + className
0966: + " new" + unitName + "(String s) {");
0967: println(out, " return new " + className
0968: + "((Double.valueOf(s).doubleValue())" + fexpr
0969: + ");");
0970: println(out, " }");
0971: }
0972: println(out);
0973:
0974: // common unit support - mostly a bogon
0975: println(out);
0976: println(out, " public int getCommonUnit() {");
0977: String cus = p.get(context, "common");
0978: if (cus == null) {
0979: println(out, " return 0;");
0980: } else {
0981: List<String> v = explodeC(cus, '/');
0982: String n = v.get(0);
0983: String d = v.get(1);
0984: int i = 0;
0985: for (UnitTuple ut : tuples) {
0986: if (n.equals(ut.num) && d.equals(ut.sden)) {
0987: println(out, " return " + i + ";");
0988: break;
0989: }
0990: i++;
0991: }
0992: if (i == tuples.size()) {
0993: System.err
0994: .println("Couldn't find a matching tuple for \""
0995: + cus + "\".");
0996: println(out, " return 0;");
0997: }
0998: }
0999: println(out, " }");
1000: println(out);
1001:
1002: println(out,
1003: " public int getMaxUnit() { return MAXUNIT; }");
1004: println(out);
1005:
1006: println(out, " // unit names for getUnitName");
1007: println(out, " private static final String unitNames[]={");
1008: for (UnitTuple ut : tuples) {
1009: String unit = ut.num + "/" + ut.sden;
1010: println(out, " \"" + unit + "\",");
1011: }
1012: println(out, " };");
1013: println(out);
1014:
1015: println(out,
1016: " /** @param unit One of the constant units of "
1017: + className + " **/");
1018: println(out,
1019: " public final String getUnitName(int unit) {");
1020: println(out, " return unitNames[unit];");
1021: println(out, " }");
1022: println(out);
1023:
1024: // index typed factory methods
1025: println(out, " // Index Typed factory methods");
1026: println(out, " static final double convFactor[]={");
1027: for (UnitTuple ut : tuples) {
1028: println(out, " " + ut.factor + ",");
1029: }
1030: println(out, " };");
1031:
1032: writeConvFactorAccessor(out);
1033:
1034: println(out, " // indexes into factor array");
1035: int i = 0;
1036: for (UnitTuple ut : tuples) {
1037: String unit = ut.num + "_per_" + ut.sden;
1038: String unitName = toConstantName(unit);
1039: println(out, " public static final int " + unitName
1040: + " = " + i + ";");
1041: i++;
1042: }
1043:
1044: println(out, " static final int MAXUNIT = " + (i - 1)
1045: + ";");
1046: println(out);
1047: println(out, " // Index Typed factory methods");
1048: println(out,
1049: " /** @param unit One of the constant units of "
1050: + className + " **/");
1051: println(out, " public static final " + className + " new"
1052: + className + "(double v, int unit) {");
1053: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
1054: println(out, " return new " + className
1055: + "(v*getConvFactor(unit));");
1056: println(out, " else");
1057: println(out, " throw new UnknownUnitException();");
1058: println(out, " }");
1059: println(out);
1060: println(out,
1061: " /** @param unit One of the constant units of "
1062: + className + " **/");
1063: println(out, " public static final " + className + " new"
1064: + className + "(String s, int unit) {");
1065: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
1066: println(
1067: out,
1068: " return new "
1069: + className
1070: + "((Double.valueOf(s).doubleValue())*getConvFactor(unit));");
1071: println(out, " else");
1072: println(out, " throw new UnknownUnitException();");
1073: println(out, " }");
1074: println(out);
1075:
1076: println(out, " // Index Typed factory methods");
1077: println(
1078: out,
1079: " /** @param unit1 One of the constant units of "
1080: + dC
1081: + "\n"
1082: + " * @param unit2 One of the constant units of "
1083: + dtC + "\n" + " **/");
1084: println(out, " public static final " + className + " new"
1085: + className + "(double v, int unit1, int unit2) {");
1086: println(out, " if (unit1 >= 0 && unit1 <= " + dC
1087: + ".MAXUNIT &&\n"
1088: + " unit2 >= 0 && unit2 <= " + dtC
1089: + ".MAXUNIT)");
1090: println(out, " return new " + className + "(v*" + dC
1091: + ".getConvFactor(unit1)/" + dtC
1092: + ".getConvFactor(unit2));");
1093: println(out, " else");
1094: println(out, " throw new UnknownUnitException();");
1095: println(out, " }");
1096: println(out);
1097:
1098: println(out, " /** @param num An instance of " + dC
1099: + " to use as numerator\n"
1100: + " * @param den An instance of " + dtC
1101: + "to use as denominator\n" + " **/");
1102: println(out, " public static final " + className + " new"
1103: + className + "(" + dC + " num, " + dtC + " den) {");
1104: println(out, " return new " + className
1105: + "(num.getValue(0)/den.getValue(0));");
1106: println(out, " }");
1107: println(out);
1108:
1109: println(
1110: out,
1111: " /** @param unit1 One of the constant units of "
1112: + dC
1113: + "\n"
1114: + " * @param unit2 One of the constant units of "
1115: + dtC + "\n" + " **/");
1116: println(out, " public static final " + className + " new"
1117: + className + "(String s, int unit1, int unit2) {");
1118: println(out, " if (unit1 >= 0 && unit1 <= " + dC
1119: + ".MAXUNIT &&\n"
1120: + " unit2 >= 0 && unit2 <= " + dtC
1121: + ".MAXUNIT)");
1122: println(out, " return new " + className
1123: + "((Double.valueOf(s).doubleValue())*" + dC
1124: + ".getConvFactor(unit1)/" + dtC
1125: + ".getConvFactor(unit2));");
1126: println(out, " else");
1127: println(out, " throw new UnknownUnitException();");
1128: println(out, " }");
1129: println(out);
1130:
1131: // abstractmeasure-level concretefactory
1132: writeNewMeasureMethods(out, className);
1133:
1134: writeAddSubtractMethods(out, className);
1135: writeDivideDerivative(out, className);
1136: // getters
1137: println(out, " // Unit-based Reader methods");
1138: for (UnitTuple ut : tuples) {
1139: String unit = ut.num + "_per_" + ut.sden;
1140: String unitName = toClassName(unit);
1141: println(out, " public double get" + unitName + "() {");
1142: println(out, " return (theValue*" + ut.factor + ");");
1143: println(out, " }");
1144: }
1145: println(out);
1146:
1147: // unit-as-argument getter
1148: println(out,
1149: " /** @param unit One of the constant units of "
1150: + className + " **/");
1151: println(out, " public double getValue(int unit) {");
1152: println(out, " if (unit >= 0 && unit <= MAXUNIT)");
1153: println(out, " return (theValue*getConvFactor(unit));");
1154: println(out, " else");
1155: println(out, " throw new UnknownUnitException();");
1156: println(out, " }");
1157: println(out);
1158:
1159: println(
1160: out,
1161: " /** @param unit1 One of the constant units of "
1162: + dC
1163: + "\n"
1164: + " * @param unit2 One of the constant units of "
1165: + dtC + "\n" + " **/");
1166: println(out,
1167: " public double getValue(int unit1, int unit2) {");
1168: println(out, " if (unit1 >= 0 && unit1 <= " + dC
1169: + ".MAXUNIT &&\n"
1170: + " unit2 >= 0 && unit2 <= " + dtC
1171: + ".MAXUNIT)");
1172: println(out, " return (theValue*" + dtC
1173: + ".getConvFactor(unit2)/" + dC
1174: + ".getConvFactor(unit1));");
1175: println(out, " else");
1176: println(out, " throw new UnknownUnitException();");
1177: println(out, " }");
1178: println(out);
1179:
1180: // equals et al
1181: println(out, " public boolean equals(Object o) {");
1182: println(out, " return ( o instanceof " + className
1183: + " &&");
1184: println(out, " theValue == ((" + className
1185: + ") o).theValue);");
1186: println(out, " }");
1187: println(out, " public String toString() {");
1188: println(out, " return Double.toString(theValue) + \""
1189: + baseabbrev + "\";");
1190: println(out, " }");
1191: println(out, " public int hashCode() {");
1192: println(out,
1193: " return (new Double(theValue)).hashCode();");
1194: println(out, " }");
1195: println(out);
1196:
1197: // derivative implementation
1198: println(out, " // Derivative");
1199: println(out,
1200: " public final Class getNumeratorClass() { return "
1201: + dC + ".class; }");
1202: println(out,
1203: " public final Class getDenominatorClass() { return "
1204: + dtC + ".class; }");
1205: println(out);
1206:
1207: println(out, " private final static " + dC
1208: + " can_num = new " + dC + "(0.0,0);");
1209: println(out,
1210: " public final Measure getCanonicalNumerator() { return can_num; }");
1211: println(out, " private final static " + dtC
1212: + " can_den = new " + dtC + "(0.0,0);");
1213: println(out,
1214: " public final Measure getCanonicalDenominator() { return can_den; }");
1215: println(
1216: out,
1217: " public final Measure computeNumerator(Measure den) {\n"
1218: + " if (!(den instanceof "
1219: + dtC
1220: + ")) throw new IllegalArgumentException();\n"
1221: + " return new " + dC
1222: + "(theValue*den.getValue(0),0);\n" + " }");
1223: println(
1224: out,
1225: " public final Measure computeDenominator(Measure num) {\n"
1226: + " if (!(num instanceof "
1227: + dC
1228: + ")) throw new IllegalArgumentException();\n"
1229: + " return new " + dtC
1230: + "(num.getValue(0)/theValue,0);\n" + " }");
1231: println(out);
1232:
1233: println(out, " // serialization");
1234: println(out,
1235: " public void writeExternal(ObjectOutput out) throws IOException {\n"
1236: + " out.writeDouble(theValue);\n"
1237: + " }");
1238: println(out,
1239: " public void readExternal(ObjectInput in) throws IOException {\n"
1240: + " theValue = in.readDouble();\n"
1241: + " }");
1242:
1243: // that's all, folks
1244: println(out, "}");
1245:
1246: }
1247:
1248: private void writeConvFactorAccessor(PrintWriter out) {
1249: println(out, "");
1250: println(out,
1251: " public static final double getConvFactor(int i) { return convFactor[i]; }");
1252: println(out, "");
1253: }
1254:
1255: void writeClassDef(PrintWriter out, String context,
1256: String className) {
1257: String alias = p.get(context, "alias");
1258: if (alias != null) {
1259: writeClassDef(out, alias, className); // alias class
1260: } else if (p.get(context, "derivative") != null) {
1261: writeClassDt(out, context, className); // derivative class
1262: } else {
1263: writeClass(out, context, className); // "regular" class
1264: }
1265: }
1266:
1267: void writeMeasure(String context) throws Exception {
1268:
1269: String className = toClassName(context);
1270: String outname = className.toString() + ".java";
1271: noteFile(outname);
1272: if (cleanp) {
1273: (new File(outname)).delete();
1274: } else {
1275: debug("Writing Measure \"" + context + "\" to \""
1276: + outname + "\"");
1277: FileOutputStream fos = new FileOutputStream(new File(
1278: getTargetDir(), outname));
1279: OutputStreamWriter osw = new OutputStreamWriter(fos);
1280: PrintWriter out = new PrintWriter(osw);
1281:
1282: writePrelude(out, context, className, outname);
1283: writeClassDef(out, context, className);
1284: out.close();
1285: }
1286:
1287: // check to see if we need to write a denominator class
1288: String denC = p.get(context, "denominator_class");
1289: if (denC != null) {
1290: writeDenominatorClass(context, denC);
1291: }
1292: }
1293:
1294: void writeDenominatorClass(String context, String className)
1295: throws Exception {
1296: String outname = className + ".java";
1297: noteFile(outname);
1298: if (cleanp) {
1299: (new File(outname)).delete();
1300: return;
1301: }
1302: debug("Writing Derivative Measure Denominator Class \""
1303: + className + "\" for \"" + context + "\" to \""
1304: + outname + "\"");
1305: FileOutputStream fos = new FileOutputStream(new File(
1306: getTargetDir(), outname));
1307: OutputStreamWriter osw = new OutputStreamWriter(fos);
1308: PrintWriter out = new PrintWriter(osw);
1309:
1310: writePrelude(out, context, className, outname);
1311: println(
1312: out,
1313: "/** Implemented by Measures which represent derivatives with\n"
1314: + " * respect to "
1315: + toClassName(context)
1316: + ".\n"
1317: + " *\n"
1318: + " * Derivative.getDenominatorClass() will always\n"
1319: + " * return " + toClassName(context)
1320: + "\n" + " **/");
1321: println(out, "public interface " + className
1322: + " extends Derivative {");
1323: println(out, "}");
1324: out.close();
1325: }
1326:
1327: public void write() throws Exception {
1328: grokGlobal();
1329: for (String cname : p.getContexts()) {
1330: if (!cname.equals("global") && isPrimary(cname)) {
1331: try {
1332: writeMeasure(cname);
1333: } catch (Exception e) {
1334: System.err
1335: .println("Caught while processing context \""
1336: + cname + "\":");
1337: e.printStackTrace();
1338: }
1339: } else {
1340: debug("skipping included " + cname);
1341: }
1342: }
1343: }
1344:
1345: protected boolean isPrimary(String context) {
1346: String source = p.get(context, PGParser.PG_SOURCE);
1347: return (source != null)
1348: && (source.equals(PGParser.PRIMARY));
1349: }
1350: }
1351:
1352: /** arguments to the writer **/
1353: private String arguments[];
1354:
1355: private boolean isVerbose = false;
1356: private boolean cleanp = false;
1357:
1358: public void debug(String s) {
1359: if (isVerbose)
1360: System.err.println(s);
1361: }
1362:
1363: /**
1364: * @see #start
1365: * @param filename to process
1366: */
1367: private void processFile(String filename) {
1368: InputStream stream = null;
1369: try {
1370: setDirectories(filename);
1371: if (filename.equals("-")) {
1372: debug("Reading from standard input.");
1373: stream = new java.io.DataInputStream(System.in);
1374: } else {
1375: debug("Reading \"" + filename + "\".");
1376: deffilename = filename;
1377: stream = new FileInputStream(filename);
1378: }
1379:
1380: Parser p = new Parser(stream);
1381: p.parse();
1382: stream.close();
1383:
1384: Writer w = new Writer(p);
1385: w.write();
1386: w.done();
1387: } catch (Exception e) {
1388: System.err.println("While reading '" + filename
1389: + "', caught: " + e);
1390: e.printStackTrace();
1391: }
1392: }
1393:
1394: private void usage(String s) {
1395: System.err.println(s);
1396: System.err
1397: .println("Usage: MeasureWriter [-v] [--] file [file ...]");
1398: System.exit(1);
1399: }
1400:
1401: /**
1402: * @see #main
1403: */
1404: public void start() {
1405: boolean ignoreDash = false;
1406: String measuresFile = null;
1407:
1408: for (int i = 0; i < arguments.length; i++) {
1409: String arg = arguments[i];
1410: if (!ignoreDash && arg.startsWith("-")) { // parse flags
1411: if (arg.equals("--")) {
1412: ignoreDash = true;
1413: } else if (arg.equals("-v")) {
1414: isVerbose = (!isVerbose);
1415: } else if (arg.equals("-clean")) {
1416: cleanp = true;
1417: } else if (arg.equals("-d")) {
1418: targetDirName = arguments[++i];
1419: } else {
1420: usage("Unknown option \"" + arg + "\"");
1421: }
1422: } else {
1423: measuresFile = arg;
1424: }
1425: }
1426:
1427: if (measuresFile == null) {
1428: measuresFile = "measures.def";
1429: }
1430:
1431: processFile(measuresFile);
1432: }
1433:
1434: public String deffilename = null;
1435:
1436: public MeasureWriter(String args[]) {
1437: arguments = args;
1438: }
1439:
1440: public static void main(String args[]) {
1441: MeasureWriter mw = new MeasureWriter(args);
1442: mw.start();
1443: }
1444: }
|