All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netlib.generate.JavaGenerator Maven / Gradle / Ivy

Go to download

Netlib for Java that can use either native libraries or pure Java implementations.

There is a newer version: 1.1
Show newest version
/*
 * Copyright ThinkTank Maths Limited 2006, 2007
 *
 * This file is free software: you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This file 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this file.
 * If not, see .
 * 
 * For the avoidance of doubt, source code generated by this program is not considered
 * a derivative work.
 */
package org.netlib.generate;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.netlib.util.StringW;
import org.netlib.util.booleanW;
import org.netlib.util.doubleW;
import org.netlib.util.floatW;
import org.netlib.util.intW;

/**
 * Due to the depressing number of LAPACK routines, it is much more efficient to
 * auto-generate the Java code for the wrapper and corresponding Java and JNI
 * implementations.
 * 

* Warning: this code is very monolithic and horrible. It was written in a hurry for a * one-off run. It is probably very hard to understand and not at all elegant. Efforts * have been best spent on making sure the output code is elegant as it is the stuff that * actually matters. * * @author Samuel Halliday */ class JavaGenerator { class Doublet { public A a; public B b; public Doublet(A a, B b) { this.a = a; this.b = b; } @Override public String toString() { return a + " " + b; } } interface IClassFilter { /** * @param className * @return true if the class with the given name is acceptable. */ public boolean isValid(String className); } private static final Map classDefs = new HashMap(); static { /* * The complete(ish) list of parameter types for F2J methods. Typically an array * is followed by an int specifying the offset. */ classDefs.put(String.class, "String"); classDefs.put(Integer.TYPE, "int"); classDefs.put(Double.TYPE, "double"); classDefs.put(Boolean.TYPE, "boolean"); classDefs.put(Float.TYPE, "float"); classDefs.put(intW.class, "intW"); classDefs.put(doubleW.class, "doubleW"); classDefs.put(booleanW.class, "booleanW"); classDefs.put(floatW.class, "floatW"); classDefs.put(StringW.class, "StringW"); classDefs.put(int[].class, "int[]"); classDefs.put(double[].class, "double[]"); classDefs.put(boolean[].class, "boolean[]"); classDefs.put(float[].class, "float[]"); } public static void main(String[] args) throws Exception { // create the BLAS wrapper JavaGenerator blas = new JavaGenerator("org.netlib.blas", "BLAS", "lib/f2j/jlapack-0.8-javadoc.zip"); writeToFile(blas.getAbstractWrapper(), "src/org/netlib/blas/BLAS.java"); writeToFile(blas.getJavaWrapper(), "src/org/netlib/blas/JBLAS.java"); writeToFile(blas.getJNIWrapper(), "src/org/netlib/blas/NativeBLAS.java"); writeToFile(blas.getJNIC(), "jni/org_netlib_blas_NativeBLAS.c"); // create the LAPACK wrapper JavaGenerator lapack = new JavaGenerator("org.netlib.lapack", "LAPACK", "lib/f2j/jlapack-0.8-javadoc.zip"); writeToFile(lapack.getAbstractWrapper(), "src/org/netlib/lapack/LAPACK.java"); writeToFile(lapack.getJavaWrapper(), "src/org/netlib/lapack/JLAPACK.java"); writeToFile(lapack.getJNIWrapper(), "src/org/netlib/lapack/NativeLAPACK.java"); writeToFile(lapack.getJNIC(), "jni/org_netlib_lapack_NativeLAPACK.c"); // create the ARPACK wrapper // TODO: add the ARPACK javadocs here JavaGenerator arpack = new JavaGenerator("org.netlib.arpack", "ARPACK", ""); writeToFile(arpack.getAbstractWrapper(), "src/org/netlib/arpack/ARPACK.java"); writeToFile(arpack.getJavaWrapper(), "src/org/netlib/arpack/JARPACK.java"); writeToFile(arpack.getJNIWrapper(), "src/org/netlib/arpack/NativeARPACK.java"); writeToFile(arpack.getJNIC(), "jni/org_netlib_arpack_NativeARPACK.c"); } static void writeToFile(String string, String filename) throws IOException { FileOutputStream out = new FileOutputStream(filename); OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); writer.write(string); writer.close(); } /** * The generated files are licenced under the BSD licence, the same as the netlib * sources. */ private final String COPYRIGHT = "/*\n * Copyright 2003-2007 Keith Seymour.\n" + " * Copyright 1992-2007 The University of Tennessee. All rights reserved.\n" + " * \n" + " * Redistribution and use in source and binary forms, with or without\n" + " * modification, are permitted provided that the following conditions are\n" + " * met:\n" + " * \n" + " * - Redistributions of source code must retain the above copyright\n" + " * notice, this list of conditions and the following disclaimer.\n" + " * \n" + " * - Redistributions in binary form must reproduce the above copyright\n" + " * notice, this list of conditions and the following disclaimer listed\n" + " * in this license in the documentation and/or other materials\n" + " * provided with the distribution.\n" + " * \n" + " * - Neither the name of the copyright holders nor the names of its\n" + " * contributors may be used to endorse or promote products derived from\n" + " * this software without specific prior written permission.\n" + " * \n" + " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" + " * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" + " * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" + " * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" + " * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" + " * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" + " * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" + " * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" + " * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" + " * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" + " * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + " * \n" + " * This file was auto-generated by the " + JavaGenerator.class.getCanonicalName() + "\n * program, a part of netlib-java.\n * \n" + " * @see http://code.google.com/p/netlib-java/\n" + " */\n"; private final String javadocs; private final String javaWrapper; private final String jniC; private final String jniWrapper; private final String pkg; private String post; private String pre; private final String topWrapper; private final String wrapperName; /** * Some F2J methods take parameters that I don't know how to deal with in the JNI, so * we'll simply make sure the wrapper always sends them to the F2J implementation. */ private final Set dontUseJNI = new HashSet(); /** * @param packageName * @param wrapperName * @param javadocs * @throws IOException */ JavaGenerator(String packageName, String wrapperName, String javadocs) throws IOException { pkg = packageName; this.javadocs = javadocs; this.wrapperName = wrapperName; // hack for fortran/C names. BLAS is different to the other netlib libs if (wrapperName.equals("BLAS")) { pre = "cblas_"; post = ""; } else { pre = ""; post = "_"; } List> classes = getClasses(pkg, new IClassFilter() { public boolean isValid(String className) { assert className != null; assert className.startsWith(pkg); String shortName = className.substring(pkg.length() + 1); if (shortName.toUpperCase().equals(shortName)) // all caps mean the "convenience" F2J libs // or the wrapper class we are trying to create! return false; if (shortName.startsWith("Native")) // these are the JNI classes return false; if (shortName.contains("$")) // inner classes return false; if (shortName.endsWith("Test")) // test cases return false; return true; } }); List methods = new ArrayList(); for (Class clazz : classes) { Method[] ms = clazz.getDeclaredMethods(); for (Method m : ms) { // F2J methods have the same name as their containing class String name = m.getName(); String className = clazz.getSimpleName(); if (!name.equals(className.toLowerCase())) continue; methods.add(m); break; } } StringBuilder topWrapper = new StringBuilder(); StringBuilder javaWrapper = new StringBuilder(); StringBuilder jniWrapper = new StringBuilder(); StringBuilder jniC = new StringBuilder(); topWrapper.append(COPYRIGHT); javaWrapper.append(COPYRIGHT); jniWrapper.append(COPYRIGHT); jniC.append(COPYRIGHT); topWrapper.append("package " + pkg + ";\n\n"); topWrapper.append("import java.util.logging.Logger;\n"); topWrapper.append("import org.netlib.util.StringW;\n"); topWrapper.append("import org.netlib.util.booleanW;\n"); topWrapper.append("import org.netlib.util.doubleW;\n"); topWrapper.append("import org.netlib.util.floatW;\n"); topWrapper.append("import org.netlib.util.intW;\n\n"); topWrapper.append("/**\n"); topWrapper.append(" * " + wrapperName + " provider which will attempt to access a native implementation\n"); topWrapper.append(" * and falling back to use F2J if none is available.\n *\n"); topWrapper.append(" * @see http://sourceforge.net/projects/f2j\n"); topWrapper.append(" * @see http://www.netlib.org/" + wrapperName.toLowerCase() + "/\n"); topWrapper.append(" * @author Samuel Halliday\n"); topWrapper.append(" */\n"); topWrapper.append("public abstract class " + wrapperName + " {\n\n"); topWrapper.append(topWrapperLoader(wrapperName)); javaWrapper.append("package " + pkg + ";\n\n"); javaWrapper.append("import java.util.logging.Logger;\n"); javaWrapper.append("import org.netlib.util.StringW;\n"); javaWrapper.append("import org.netlib.util.booleanW;\n"); javaWrapper.append("import org.netlib.util.doubleW;\n"); javaWrapper.append("import org.netlib.util.floatW;\n"); javaWrapper.append("import org.netlib.util.intW;\n\n"); javaWrapper.append("/**\n"); javaWrapper.append(" * " + wrapperName + " provider implementation which uses F2J.\n *\n"); javaWrapper.append(" * @see http://sourceforge.net/projects/f2j\n"); javaWrapper.append(" * @author Samuel Halliday\n"); javaWrapper.append(" */\n"); javaWrapper.append("final class J" + wrapperName + " extends " + wrapperName + " {\n\n"); javaWrapper.append("\tstatic final " + wrapperName + " INSTANCE = new J" + wrapperName + "();\n\n"); javaWrapper.append("\tprivate J" + wrapperName + "() {\n"); javaWrapper.append("\t}\n\n"); jniWrapper.append("package " + pkg + ";\n\n"); jniWrapper.append("import java.util.logging.Logger;\n"); jniWrapper.append("import org.netlib.util.StringW;\n"); jniWrapper.append("import org.netlib.util.booleanW;\n"); jniWrapper.append("import org.netlib.util.doubleW;\n"); jniWrapper.append("import org.netlib.util.floatW;\n"); jniWrapper.append("import org.netlib.util.intW;\n"); jniWrapper.append("import org.netlib.utils.JNIMethods;\n\n"); jniWrapper.append("/**\n"); jniWrapper.append(" * " + wrapperName + " provider implementation which uses the Java Native Interface to access\n"); jniWrapper.append(" * system netlib libraries.\n *\n"); jniWrapper.append(" * @see http://www.netlib.org/\n"); jniWrapper.append(" * @author Samuel Halliday\n"); jniWrapper.append(" */\n"); jniWrapper.append("final class Native" + wrapperName + " extends " + wrapperName + " {\n\n"); jniWrapper.append(jniWrapperLoader(wrapperName)); jniC.append("\n#include \"f2j_jni.h\"\n"); jniC.append("#include \"" + pkg.toLowerCase().replace(".", "_") + "_Native" + wrapperName + ".h\"\n\n"); for (Method method : methods) { System.out.println("Generating " + method.getName()); Type[] params = method.getGenericParameterTypes(); for (Type param : params) { if (classDefs.containsKey(param)) continue; System.err.println(method.getName() + " has a " + param + " parameter, so we'll not generate a JNI"); dontUseJNI.add(method.getName()); } String[] wrapper = createWrapper(method); topWrapper.append(wrapper[0]); javaWrapper.append(wrapper[1]); jniWrapper.append(wrapper[2]); jniC.append(wrapper[3]); } topWrapper.append("}\n"); javaWrapper.append("}\n"); jniWrapper.append("}\n"); // System.out.print(topWrapper); this.topWrapper = topWrapper.toString(); this.javaWrapper = javaWrapper.toString(); this.jniWrapper = jniWrapper.toString(); this.jniC = jniC.toString(); } /** * @return the Java source code for the top level abstract class for the package */ public String getAbstractWrapper() { return topWrapper; } /** * @return the Java source code for the F2J delegate class */ public String getJavaWrapper() { return javaWrapper; } /** * @return the C source code for the JNI code */ public String getJNIC() { return jniC; } /** * @return the Java source code for the JNI delegate class */ public String getJNIWrapper() { return jniWrapper; } /** * @param s * @return a capitalised version of the input */ private String capitalize(String s) { if (s.length() == 0) return s; return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); } /** * @param method * @param typeAndName * @return */ private String createJavaWrapper(Method method, List> typeAndName) { // no need for javadocs StringBuilder builder = new StringBuilder(); builder.append("\t@Override\n"); builder.append("\tpublic " + method.getReturnType().getName().toLowerCase() + " " + method.getName() + "("); for (int i = 0; i < typeAndName.size(); i++) { Doublet tm = typeAndName.get(i); String type = tm.a; String name = tm.b; builder.append(type + " " + name); if (i != typeAndName.size() - 1) builder.append(", "); } builder.append(") {\n\t\t"); if (!method.getReturnType().equals(Void.TYPE)) builder.append("return "); String n = method.getName(); builder.append(pkg + "." + capitalize(n) + "." + n + "("); for (int i = 0; i < typeAndName.size(); i++) { Doublet tm = typeAndName.get(i); String type = tm.a; String name = tm.b; builder.append(name); if (type.contains("[]")) { // offset is always zero builder.append(", 0"); } if (i != typeAndName.size() - 1) builder.append(", "); } builder.append(");\n\t}\n\n"); return builder.toString(); } /** * @param method * @param typeAndName * @return */ private String createJNICode(Method method, List> typeAndName) { List names = new ArrayList(); List types = new ArrayList(); for (Doublet tn : typeAndName) { types.add(tn.a); names.add(tn.b); } String name = pkg + ".Native" + wrapperName + "." + method.getName(); String rtn = method.getReturnType().getName().toLowerCase(); // cblas hack String pre = this.pre; String post = this.post; if (wrapperName.equals("BLAS") && method.getName().equals("lsame")) { pre = ""; post = "_"; } JNIGenerator jni = new JNIGenerator(pre, post, name, types, names, rtn, wrapperName.equals("BLAS") ? true : false); return jni.getTemplate() + "\n"; } /** * @param method * @param typeAndName * @return */ private String createJNIWrapper(Method method, List> typeAndName) { // no need for javadocs StringBuilder builder = new StringBuilder(); builder.append("\t@Override\n"); builder.append("\tpublic native " + method.getReturnType().getName().toLowerCase() + " " + method.getName() + "("); for (int i = 0; i < typeAndName.size(); i++) { Doublet tm = typeAndName.get(i); String type = tm.a; String name = tm.b; builder.append(type + " " + name); if (i != typeAndName.size() - 1) builder.append(", "); } builder.append(");\n\n"); return builder.toString(); } /** * @param javadocs * @param typeAndName * @return */ private String createTopJavaDocs(String javadocs, List> typeAndName) { StringBuilder builder = new StringBuilder(); builder.append("\t/**\n"); builder.append(javadocs); for (int i = 0; i < typeAndName.size(); i++) { builder.append("\t * @param " + typeAndName.get(i).b + "\n"); } builder.append("\t */\n"); return builder.toString(); } /** * @param method * @param typeAndName * @param javadocs * @return */ private String createTopWrapper(Method method, List> typeAndName, String javadocs) { StringBuilder builder = new StringBuilder(); builder.append(createTopJavaDocs(javadocs, typeAndName)); builder.append("\tpublic abstract " + method.getReturnType().toString().toLowerCase() + " " + method.getName() + "("); for (int i = 0; i < typeAndName.size(); i++) { builder.append(typeAndName.get(i).a + " " + typeAndName.get(i).b); if (i != typeAndName.size() - 1) builder.append(", "); } builder.append(");\n\n"); return builder.toString(); } /** * A list of methods not defined in headers on OS X Leopard or Ubuntu Gutsy. These are * most likely subroutines that should not be a part of the API, but we leave them in * anyway. */ static final Set notSupportedByJNI = new HashSet(Arrays.asList( /* These are BLAS/LAPACK not defined on OS X Leopard */ "disnan", "dlacn2", "dlag2s", "dlahr2", "dlaisnan", "dlaneg", "dlaqr0", "dlaqr1", "dlaqr2", "dlaqr3", "dlaqr4", "dlaqr5", "dlarra", "dlarrc", "dlarrd", "dlarrj", "dlarrk", "dlarrr", "dlazq3", "dlazq4", "dsgesv", "dstemr", "ilaver", "iparmq", "sisnan", "slag2d", "slahr2", "slaisnan", "slaneg", "slaqr0", "slaqr1", "slaqr2", "slaqr3", "slaqr4", "slaqr5", "slarra", "slarrc", "slarrj", "slarrr", "sstemr", "slacn2", "slarrd", "slarrk", "slazq3", "slazq4", /* These are BLAS not defined on Ubuntu Gutsy (LAPACK 3.0) */ "lsame", /* * These are LAPACK and not defined in LAPACK 3.0 * http://www.netlib.org/clapack/clapack.h */ "dlangb", "dlange", "dlangt", "dlanhs", "dlansb", "dlansp", "dlanst", "dlansy", "dlantb", "dlantp", "dlantr", "dlapy2", "dlapy3", "lsamen", "slangb", "slange", "slangt", "slanhs", "slansb", "slansp", "slanst", "slansy", "slantb", "slantp", "slantr", "slapy2", "slapy3", "dlamc3", "dsecnd", "second", "slamch", "slamc3", /* * The following is not defined in clapack.h bet really should be! * So we're leaving it in and we'll suffer the compile time warning. */ // "dlamch", /* these are not defined in the ARPACK headers */ "dmout", "dvout", "icnteq", "icopy", "iset", "iswap", "ivout", "smout", "svout", "dgetv0", "dlaqrb", "dnaitr", "dnapps", "dnaup2", "dnconv", "dneigh", "dngets", "dsaitr", "dsapps", "dsaup2", "dsconv", "dseigt", "dsesrt", "dsgets", "dsortc", "dsortr", "dstatn", "dstats", "dstqrb", "sgetv0", "slaqrb", "snaitr", "snapps", "snaup2", "snconv", "sneigh", "sngets", "ssaitr", "ssapps", "ssaup2", "ssconv", "sseigt", "ssesrt", "ssgets", "ssortc", "ssortr", "sstatn", "sstats", "sstqrb")); /** A list of methods where F2J has a different signature than in OS X Leopard */ static final List incompatibleWithJni = Arrays.asList("dlar1v", "dlarrb", "dlarre", "dlarrf", "dlarrv", "slar1v", "slarrb", "slarre", "slarrf", "slarrv"); /** * @param method * @return the 4D array of wrappers. The first is the abstract portion, the second is * the F2J wrapper, the third is the JNI wrapper and the forth is the C JNI * code. * @throws IOException */ private String[] createWrapper(Method method) throws IOException { String name = method.getName(); String[] parts = new String[4]; Map fromDocs = getParameterNames(method); String javadocs = fromDocs.keySet().iterator().next(); String[] names = fromDocs.values().iterator().next(); Class[] paramTypes = method.getParameterTypes(); List> typeAndName = typeAndName(paramTypes, names); // some exceptional methods if (notSupportedByJNI.contains(name) || incompatibleWithJni.contains(name) || dontUseJNI.contains(name)) { String javaWrapper = createJavaWrapper(method, typeAndName); String javaDocs = createTopJavaDocs(javadocs, typeAndName); parts[0] = javaWrapper.replace("@Override\n", javaDocs); System.err.println("Forcing F2J for " + name); parts[1] = ""; parts[2] = ""; parts[3] = ""; return parts; } parts[0] = createTopWrapper(method, typeAndName, javadocs); parts[1] = createJavaWrapper(method, typeAndName); parts[2] = createJNIWrapper(method, typeAndName); parts[3] = createJNICode(method, typeAndName); return parts; } /** * This convenience method will examine the classpath and find any classes which are * in the requested package. A filter can be specified to exclude results. * * @param packageName * @param filter * @return all classes in a given package * @see http://forum.java.sun.com/thread.jspa?threadID=757391&messageID=4326850 */ private List> getClasses(String packageName, IClassFilter filter) { String packagePath = packageName.replace('.', '/'); // ArrayList classpath = new ArrayList(); // String[] classpathString = System.getProperty("java.class.path").split(":"); // for (int i = 0 ; i < classpathString.length ; i++){ // if (classpathString[i] == null) // continue; // try { // URL url = new URL("file:" + classpathString[i]); // classpath.add(url); // } catch (MalformedURLException ex) { // Logger.getLogger(JavaGenerator.class.getName()). // log(Level.SEVERE, classpathString[i] + " " + ex.getMessage()); // } // } URL [] classpath = ((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs(); List> result = new ArrayList>(); System.out.println(Arrays.toString(classpath)); for (URL url : classpath) { File file; try { file = new File(url.toURI()); } catch (URISyntaxException e1) { continue; } if (file.getPath().endsWith(".jar")) { // class path is a jar file JarFile jarFile; try { jarFile = new JarFile(file); } catch (IOException e) { continue; } for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { String entryName = (entries.nextElement()).getName(); if (entryName.matches(packagePath + "/\\w*\\.class")) { // get only class files in package dir ClassLoader classLoader = new URLClassLoader(new URL[] { url }); String className = entryName.replace('/', '.').substring(0, entryName.lastIndexOf('.')); if (!filter.isValid(className)) continue; Class clazz; try { clazz = classLoader.loadClass(className); } catch (ClassNotFoundException e) { continue; } result.add(clazz); } } } else { // class path is a directory File packageDirectory = new File(file.getPath() + "/" + packagePath); for (File f : packageDirectory.listFiles()) { if (f.getPath().endsWith(".class")) { String className = packageName + "." + f.getName().substring(0, f.getName().lastIndexOf('.')); if (!filter.isValid(className)) continue; ClassLoader classLoader = new URLClassLoader(new URL[] { url }); Class clazz; try { clazz = classLoader.loadClass(className); } catch (ClassNotFoundException e) { continue; } result.add(clazz); } } } } return result; } /** * Note that we cannot use a library like Paranamer here because the information is * not in the bytecode. We look in the Javadocs! * * @param method * @return a singleton map from the javadoc description to the parameter names of the * method, in order. (Yes, I know this is a hack) * @throws IOException */ private Map getParameterNames(Method method) throws IOException { ZipInputStream in; try { in = new ZipInputStream(new FileInputStream(javadocs)); } catch (FileNotFoundException e) { // no javadocs available, just return arg1 ... argN int size = method.getGenericParameterTypes().length; String[] names = new String[size]; for (int i = 0; i < size; i++) { names[i] = "arg" + (i + 1); } String docs = "\t * No documentation was available when generating this method.\n\t * \n"; return Collections.singletonMap(docs, names); } ZipEntry entry; // deal with the capitalisation of LAPACK classes... clashes there String m = method.getName(); String p = pkg.replace(".", "/") + "/" + m.substring(0, 1).toUpperCase() + m.substring(1) + ".html"; try { while ((entry = in.getNextEntry()) != null) { String name = entry.getName(); if (name.endsWith(p)) { ByteArrayOutputStream out = new ByteArrayOutputStream(); // Transfer bytes from the ZIP file to the output stream byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } String javadoc = new String(out.toByteArray()); out.close(); String[] names = parseParameterNames(method, javadoc); String documentation = parseJavadocDescription(method, javadoc); return Collections.singletonMap(documentation, names); } } throw new RuntimeException("getParameterNames failed"); } finally { in.close(); } } private String jniWrapperLoader(String wrapperName) { StringBuilder b = new StringBuilder(); b.append("\t// singleton\n"); b.append("\tprotected static final Native" + wrapperName + " INSTANCE = new Native" + wrapperName + "();\n\n"); b.append("\t// indicates if the JNI loaded OK. If this is false, calls to the native\n"); b.append("\t// methods will fail with UnsatisfiedLinkError\n"); b.append("\tprotected final boolean isLoaded;\n\n"); b.append("\tprivate Native" + wrapperName + "() {\n"); b.append("\t\tString libname = JNIMethods.getPortableLibraryName(\"jni" + wrapperName.toLowerCase() + "\");\n"); b.append("\t\ttry {\n"); b.append("\t\t\tSystem.loadLibrary(libname);\n"); b.append("\t\t} catch (UnsatisfiedLinkError e) {\n"); b.append("\t\t\tisLoaded = false;\n"); b.append("\t\t\treturn;\n"); b.append("\t\t}\n"); b.append("\t\tisLoaded = true;\n"); b.append("\t}\n\n"); return b.toString(); } /** * @param method * @param javadoc * @return */ private String parseJavadocDescription(Method method, String javadoc) { Pattern pattern = Pattern.compile("[email protected] with any questions.\n

"); Matcher matcher = pattern.matcher(javadoc); boolean matched = matcher.find(); assert matched; int start = matcher.end(); int end = javadoc.indexOf("

", start); javadoc = javadoc.substring(start, end).replaceAll("\n \\*", "\n").replaceAll( "\n c", "\n"); return "
" + javadoc + "
\n"; } /** * @param method * @param javadoc * @return */ private String[] parseParameterNames(Method method, String javadoc) { int n = method.getParameterTypes().length; String[] names = new String[n]; // this is the worst regex code I've ever written... I'm being lazy int begin = javadoc.indexOf("METHOD SUMMARY"); Pattern pattern = Pattern.compile("\\Q>" + method.getName() + "(\\E"); Matcher matcher = pattern.matcher(javadoc); boolean matched = matcher.find(begin); assert matched; // this begin is the real beginning of our search begin = matcher.end(); // we need to cap the region to look at pattern = Pattern.compile("\\Q)
\\E"); matcher = pattern.matcher(javadoc); matched = matcher.find(begin); assert matched; int end = matcher.start(); pattern = Pattern.compile(" ([^,]*)(,|$)"); matcher = pattern.matcher(javadoc); matcher.region(begin, end); int cnt = 0; while (matcher.find()) { String name = matcher.group(1); names[cnt] = name; cnt++; } assert cnt == n; return names; // int n = method.getParameterTypes().length; // String[] names = new String[n]; // for (int i = 0; i < n; i++) { // names[i] = "arg" + (i + 1); // } // return names; } private String topWrapperLoader(String wrapperName) { // use static initialisation StringBuilder builder = new StringBuilder(); builder.append("\tstatic private final " + wrapperName + " current;\n"); builder.append("\tstatic {\n"); builder.append("\t\tLogger logger = Logger.getLogger(\"org.netlib." + wrapperName.toLowerCase() + "\");\n"); builder.append("\t\tif (Native" + wrapperName + ".INSTANCE.isLoaded) {\n"); builder.append("\t\t\tcurrent = Native" + wrapperName + ".INSTANCE;\n"); builder.append("\t\t\tlogger.config(\"Using JNI for " + wrapperName + "\");\n"); builder.append("\t\t} else {\n"); builder.append("\t\t\tcurrent = J" + wrapperName + ".INSTANCE;\n"); builder.append("\t\t\tlogger.config(\"Using F2J as JNI failed for " + wrapperName + "\");\n"); builder.append("\t\t}\n"); if ("LAPACK".equals(wrapperName)) { // workaround bug 5 builder.append("\t\tcurrent.slamch(\"E\");\n"); builder.append("\t\tcurrent.dlamch(\"E\");\n"); } builder.append("\t}\n\n"); builder.append("\tpublic static " + wrapperName + " getInstance() {\n"); builder.append("\t\treturn current;\n"); builder.append("\t}\n\n"); // // leading dimension helper methods // builder.append("\t/**\n"); // builder.append("\t * max(1, M) provided as a convenience for 'leading // dimension' calculations\n\t * \n"); // builder.append("\t * @param n\n"); // builder.append("\t */\n"); // builder.append("\tstatic public int ld(int n) {\n"); // builder.append("\t\treturn Math.max(1, n);\n"); // builder.append("\t}\n"); // builder.append("\t/**\n"); // builder.append("\t * max(1, max(M, N)) provided as a convenience for // 'leading dimension' calculations\n\t * \n"); // builder.append("\t * @param m\n"); // builder.append("\t * @param n\n"); // builder.append("\t */\n"); // builder.append("\tstatic public int ld(int m, int n) {\n"); // builder.append("\t\treturn Math.max(1, Math.max(m, n));\n"); // builder.append("\t}\n\n"); return builder.toString(); // the following is an alternative using lazy initialisation // StringBuilder builder = new StringBuilder(); // builder.append("\tstatic private volatile " + wrapperName // + " current = null;\n\n"); // builder.append("\tprivate static final Object currentLock = new Object();\n\n"); // builder.append("\tpublic static final " + wrapperName // + " getInstance() {\n"); // builder.append("\t\tsynchronized (currentLock) {\n"); // builder.append("\t\t\t// synchronised lazy initialisation\n"); // builder.append("\t\t\tif (current == null) {\n"); // builder.append("\t\t\t\tLogger logger = Logger.getLogger(\"org.netlib\");\n"); // builder.append("\t\t\t\t// test the JNI implementation\n"); // builder.append("\t\t\t\tif (Native" + wrapperName // + ".INSTANCE.isLoaded) {\n"); // builder.append("\t\t\t\t\tcurrent = Native" + wrapperName + ".INSTANCE;\n"); // builder.append("\t\t\t\t\tlogger.info(\"Using JNI for " + wrapperName + "\");\n"); // builder.append("\t\t\t\t} else {\n"); // builder.append("\t\t\t\t\t// otherwise use F2J\n"); // builder.append("\t\t\t\t\tcurrent = J" + wrapperName + ".INSTANCE;\n"); // builder.append("\t\t\t\t\tlogger.info(\"Using F2J as JNI failed for " // + wrapperName + "\");\n"); // builder.append("\t\t\t\t}\n"); // builder.append("\t\t\t}\n"); // builder.append("\t\t\treturn current;\n"); // builder.append("\t\t}\n"); // builder.append("\t}\n"); // return builder.toString(); } /** * @param paramTypes * @param names * @return */ private List> typeAndName(Class[] paramTypes, String[] names) { assert names.length == paramTypes.length; List> l = new ArrayList>(); Class lastType = Void.TYPE; for (int i = 0; i < names.length; i++) { Class type = paramTypes[i]; if (type.equals(Integer.TYPE) && (lastType.equals(double[].class) || lastType.equals(int[].class) || lastType.equals(boolean[].class) || lastType.equals(float[].class))) { lastType = type; continue; } String t = classDefs.get(type); if (t == null) t = "Object"; l.add(new Doublet(t, names[i])); lastType = type; } return l; } }



© 2015 - 2024 Weber Informatics LLC | Privacy Policy