/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * 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 * Lesser General Public License for more details. */ package org.openplans.filterfunctionwriter; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * Basic idea: 1. for each method in the Math class (or whatever class you * specify - see main() ) 2. make a .java file put the header in (ie. includes, * etc...) put the actual code in (see "emit()" below) put the footer in (ie. * finish the class "}") print the entries that should be put in the service * info file to the command line Create tests that show the functions work as * they should. * * @author dblasby * @author Kasper Kaergaard, to adapt for the Math package, and make unit tests * (this should be combined with the original makefunction for something * more generic, but don't have the time right now). */ public class MakeFunctionMathClasses { private static final String PACKAGE_DECLARATION = "package org.geotools.filter.function.math;"; private static final String PATH_AND_FILE_NAME_PREFIX = "src/org/geotools/filter/function/math/FilterFunction_"; private static final String LICENSE = "/*\n" + " * GeoTools - The Open Source Java GIS Toolkit\n" + " * http://geotools.org\n" + " *\n" + " * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)\n" + " * \n" + " * This library is free software; you can redistribute it and/or\n" + " * modify it under the terms of the GNU Lesser General Public\n" + " * License as published by the Free Software Foundation;\n" + " * version 2.1 of the License.\n" + " *\n" + " * This library is distributed in the hope that it will be useful,\n" + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + " * Lesser General Public License for more details.\n" + " */"; public static void main(String[] args) { MakeFunctionMathClasses cg = new MakeFunctionMathClasses(); cg.handleClass(Math.class); // parent of all geometry types } public void handleClass(Class c) { try { Method[] methods = c.getDeclaredMethods(); File testFile = new File(PATH_AND_FILE_NAME_PREFIX + "Test" + ".java"); PrintStream testPrintStream = new PrintStream(new FileOutputStream( testFile)); createTestFileHeader(testPrintStream); for (int t = 0; t < methods.length; t++) { Method method = methods[t]; Type type = method.getGenericReturnType(); if (!type.toString().equals("void")) { String name = method.getName(); File f = new File(PATH_AND_FILE_NAME_PREFIX + name + ".java"); int count = 2; while (f.exists()) { name = method.getName() + "_" + count; f = new File(PATH_AND_FILE_NAME_PREFIX + name + ".java"); count++; } PrintStream ps = new PrintStream(new FileOutputStream(f)); emitHeader(method, ps, name); emitCode(method, ps); emitFooter(method, ps); ps.close(); PrintStream printStream = System.out; writeServiceInfo(method, printStream, name); writeTestMethodInTestFile(testPrintStream, method, name); } } writeFooterInTestFile(testPrintStream); testPrintStream.close(); } catch (Exception e) { e.printStackTrace(); } } private void writeFooterInTestFile(PrintStream ps) { ps.println("}"); } private void writeTestMethodInTestFile(PrintStream ps, Method method, String name) { try { int argsCount = method.getParameterTypes().length; double[] values = new double[] { 1, -1, 2, -2, Math.PI, 0.5 * Math.PI }; String[] literalNames = new String[] { "literal_1", "literal_m1", "literal_2", "literal_m2", "literal_pi", "literal_05pi" }; ps.println(""); ps.println("public void test" + name + "(){"); ps.println(" try {"); ps.println(""); ps.println(" FunctionExpression " + name + "Function = filterFactory.createFunctionExpression(\"" + name + "\");"); ps.println(" assertEquals(\"Name is, \",\"" + name + "\"," + name + "Function.getName());"); ps.println(" assertEquals(\"Number of arguments, \"," + argsCount + "," + name + "Function.getArgCount());"); ps.println(""); ps.println(" Expression[] expressions = new Expression[" + argsCount + "];"); if (method.getParameterTypes().length > 0) { for (int i = 0; i < 6; i++) { String argument = "(" + values[i]; ps.println(" expressions[" + 0 + "] = " + literalNames[i] + ";"); for (int j = 1; j < argsCount; j++) { int k = i + j; if (k > 5) { k = 0; } argument = argument + "," + values[k]; ps.println(" expressions[" + j + "] = " + literalNames[k] + ";"); } argument = argument + ")"; ps.println(" " + name + "Function.setParameters(java.util.Arrays.asList(expressions));"); if (isNumber(method.getReturnType())) { if ((method.getReturnType() == int.class)) { ps .println(" assertEquals(\"" + method.getName() + " of " + argument + ":\" ,(int)Math." + method.getName() + argument + " ,((Integer) " + name + "Function.getValue(null)).intValue(),0.00001);"); } else if ((method.getReturnType() == double.class)) { ps.println(" double good" + i + " = Math." + method.getName() + argument + ";"); ps.println(" if(Double.isNaN(good" + i + ")){"); ps .println(" assertTrue(\"" + method.getName() + " of " + argument + ":\" ,Double.isNaN(((Double) " + name + "Function.getValue(null)).doubleValue()));"); ps.println(" }else{"); ps .println(" assertEquals(\"" + method.getName() + " of " + argument + ":\" ,(double)Math." + method.getName() + argument + " ,((Double) " + name + "Function.getValue(null)).doubleValue(),0.00001);"); ps.println(" }"); } else if ((method.getReturnType() == long.class)) { ps .println(" assertEquals(\"" + method.getName() + " of " + argument + ":\" ,(long)Math." + method.getName() + argument + " ,((Long) " + name + "Function.getValue(null)).longValue(),0.00001);"); } else if ((method.getReturnType() == float.class)) { ps .println(" assertEquals(\"" + method.getName() + " of " + argument + ":\" ,(float)Math." + method.getName() + argument + " ,((Float) " + name + "Function.getValue(null)).floatValue(),0.00001);"); } else { throw new IllegalArgumentException( "dont know how to handle this - " + method.getParameterTypes()[0]); } } else { throw new IllegalArgumentException( "dont know how to handle this - " + method.getParameterTypes()[0]); } } } ps.println("} catch (FactoryConfigurationError e) {"); ps.println(" e.printStackTrace();"); ps.println(" fail(\"Unexpected exception: \"+e.getMessage());"); ps.println("}"); ps.println("}"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Method name: " + method.getName()); System.out.println("Parameter Types: " + method.getParameterTypes().length); } catch (Exception e) { e.printStackTrace(); } } private void createTestFileHeader(PrintStream ps) { ps.println("package org.geotools.filter.function.math;"); ps.println(""); ps.println(""); ps.println("import org.geotools.factory.FactoryConfigurationError;"); ps.println("import org.geotools.filter.Expression;"); ps.println("import org.geotools.filter.FilterFactoryFinder;"); ps.println("import org.geotools.filter.FilterFactoryImpl;"); ps.println("import org.geotools.filter.FunctionExpression;"); ps.println("import org.geotools.filter.LiteralExpression;"); ps.println("import org.geotools.filter.LiteralExpressionImpl;"); ps.println(""); ps.println("import junit.framework.TestCase;"); ps.println(""); ps.println("public class FilterFunction_Test extends TestCase{"); ps.println(""); ps.println("private LiteralExpressionImpl literal_1 = null;"); ps.println("private LiteralExpression literal_m1;"); ps.println("private LiteralExpression literal_2;"); ps.println("private LiteralExpression literal_m2;"); ps.println("private LiteralExpression literal_pi;"); ps.println("private LiteralExpression literal_05pi;"); ps.println("private FilterFactoryImpl filterFactory;"); ps.println("protected void setUp() throws Exception {"); ps.println("super.setUp();"); ps .println("filterFactory = (FilterFactoryImpl) FilterFactoryFinder.createFilterFactory();"); ps .println("literal_1 = (LiteralExpressionImpl) filterFactory.createLiteralExpression();"); ps.println("literal_pi = filterFactory.createLiteralExpression();"); ps.println("literal_05pi = filterFactory.createLiteralExpression();"); ps.println("literal_m1 = filterFactory.createLiteralExpression();"); ps.println("literal_2 = filterFactory.createLiteralExpression();"); ps.println("literal_m2 = filterFactory.createLiteralExpression();"); ps.println(""); ps.println("literal_1.setLiteral(new Double(1));"); ps.println("literal_m1.setLiteral(new Double(-1));"); ps.println("literal_2.setLiteral(new Double(2));"); ps.println("literal_m2.setLiteral(new Double(-2));"); ps.println("literal_pi.setLiteral(new Double(Math.PI));"); ps.println("literal_05pi.setLiteral(new Double(0.5*Math.PI));"); ps .println("assertEquals(\"Literal Expression 0.0\",new Double(1.0), literal_1.getLiteral());"); ps .println("assertEquals(\"Literal Expression pi\",new Double(Math.PI), literal_pi.getLiteral());"); ps .println("assertEquals(\"Literal Expression 05pi\",new Double(0.5*Math.PI), literal_05pi.getLiteral());"); ps.println(""); ps.println("}"); ps.println(""); ps.println("protected void tearDown() throws Exception {"); ps.println(" super.tearDown();"); ps.println("}"); } public void emitHeader(Method m, PrintStream printstream, String name) { printstream.println(PACKAGE_DECLARATION); printstream.println(LICENSE); printstream.println(""); printstream.println(""); printstream .println("//this code is autogenerated - you shouldnt be modifying it!"); printstream.println(""); printstream.println("import org.geotools.feature.Feature;"); // printstream.println("import org.geotools.filter.Expression;"); // /printstream.println("import org.geotools.filter.FilterFactory;"); // /printstream.println("import // org.geotools.filter.FunctionExpression;"); printstream .println("import org.geotools.filter.FunctionExpressionImpl;"); // printstream.println("import org.geotools.filter.LiteralExpression;"); printstream.println(""); printstream.println(""); printstream.println("public class " + "FilterFunction_" + name + " extends FunctionExpressionImpl"); printstream.println("{"); printstream.println(""); printstream.println(""); printstream.println(" public FilterFunction_" + name + "(){"); printstream.println(" super(\"" + name + "\");"); printstream.println(" }"); printstream.println(""); printstream.println(""); printstream.println(" public int getArgCount(){"); printstream.println(" return " + m.getParameterTypes().length + ";"); printstream.println(" }"); printstream.println(""); printstream.println(""); } public void emitFooter(Method m, PrintStream printstream) { printstream.println("}"); printstream.println(""); } public void emitCode(Method m, PrintStream printstream) { printstream.println(" public Object evaluate(Feature feature){"); // variable decs for (int t = 0; t < m.getParameterTypes().length; t++) { printstream.println(" " + formatClassName(m.getParameterTypes()[t]) + " arg" + t + ";"); } printstream.println(""); printstream.println(""); // assignments for (int t = 0; t < m.getParameterTypes().length; t++) { printstream .println(" try{ //attempt to get value and perform conversion"); printstream.print(" arg" + t + " = "); if (isNumber(m.getParameterTypes()[t])) { if ((m.getParameterTypes()[t] == int.class)) { printstream.println("((Number) getExpression(" + t + ").evaluate(feature)).intValue();"); } else if ((m.getParameterTypes()[t] == double.class)) { printstream.println("((Number) getExpression(" + t + ").evaluate(feature)).doubleValue();"); } else if ((m.getParameterTypes()[t] == long.class)) { printstream.println("((Number) getExpression(" + t + ").evaluate(feature)).longValue();"); } else if ((m.getParameterTypes()[t] == float.class)) { printstream.println("((Number) getExpression(" + t + ").evaluate(feature)).floatValue();"); } else { throw new IllegalArgumentException( "dont know how to handle this - " + m.getParameterTypes()[t]); } } else if ((m.getParameterTypes()[t] == boolean.class)) { printstream.println("((Boolean) getExpression(" + t + ").evaluate(feature)).booleanValue();"); } else if ((m.getParameterTypes()[t] == String.class)) { printstream .println("(getExpression(" + t + ").evaluate(feature)).toString(); // extra protection for strings"); } else // class { printstream.println("(" + formatClassName(m.getParameterTypes()[t]) + ") getExpression(" + t + ").evaluate(feature);"); } printstream.println(" }"); printstream.println(" catch (Exception e){"); printstream.println(" // probably a type error"); printstream .println(" throw new IllegalArgumentException(\"Filter Function problem for function " + m.getName() + " argument #" + t + " - expected type " + formatClassName(m.getParameterTypes()[t]) + "\");"); printstream.println(" }"); printstream.println(""); } // perform computation if (isNumber(m.getReturnType())) { if (m.getReturnType() == int.class) { printstream.print(" return new Integer(Math." + m.getName() + "("); } if (m.getReturnType() == double.class) { printstream.print(" return new Double(Math." + m.getName() + "("); } if (m.getReturnType() == long.class) { printstream.print(" return new Long(Math." + m.getName() + "("); } if (m.getReturnType() == float.class) { printstream.print(" return new Float(Math." + m.getName() + "("); } } else if (m.getReturnType() == boolean.class) { printstream.print(" return new Boolean(Math." + m.getName() + "("); } else // class { printstream.print(" return (Math." + m.getName() + "("); } for (int t = 0; t < m.getParameterTypes().length; t++) { if (t != 0) { printstream.print(","); } printstream.print("arg" + (t)); } printstream.println(" ));"); printstream.println("}"); } public void writeServiceInfo(Method m, PrintStream printstream, String name) { printstream.println("org.geotools.filter.function.math.FilterFunction_" + name); } /** * DOCUMENT ME! * * @param class1 * * @return */ private boolean isNumber(Class class1) { if ((class1 == int.class) || (class1 == double.class) || (class1 == float.class) || (class1 == long.class)) { return true; } return false; } public String formatClassName(Class c) { String fullName = c.getName(); int indx = fullName.lastIndexOf('.'); if (indx == -1) { return fullName; } else { return fullName.substring(indx + 1); } } }