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

weka.core.scripting.Jython Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This version represents the developer version, the "bleeding edge" of development, you could say. New functionality gets added to this version.

There is a newer version: 3.9.6
Show newest version
/*
 *   This program 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 program 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 program.  If not, see .
 */

/*
 * Jython.java
 * Copyright (C) 2007-2012 University of Waikato, Hamilton, New Zealand
 */

package weka.core.scripting;

import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashSet;

import weka.core.RevisionHandler;
import weka.core.RevisionUtils;

/**
 * A helper class for Jython.
 * 
 * @author fracpete (fracpete at waikato dot ac dot nz)
 * @version $Revision: 10203 $
 */
public class Jython implements Serializable, RevisionHandler {

  /** for serialization */
  private static final long serialVersionUID = -6972298704460209252L;

  /** the classname of the Python interpreter */
  public final static String CLASS_PYTHONINERPRETER = "org.python.util.PythonInterpreter";

  /** the classname of the Python ObjectInputStream */
  public final static String CLASS_PYTHONOBJECTINPUTSTREAM = "org.python.util.PythonObjectInputStream";

  /** whether the Jython classes are in the Classpath */
  protected static boolean m_Present = false;
  static {
    try {
      Class.forName(CLASS_PYTHONINERPRETER);
      m_Present = true;
    } catch (Exception e) {
      m_Present = false;
    }
  }

  /** the interpreter */
  protected Object m_Interpreter;

  /**
   * default constructor, tries to instantiate a Python Interpreter
   */
  public Jython() {
    m_Interpreter = newInterpreter();
  }

  /**
   * returns the currently used Python Interpreter
   * 
   * @return the interpreter, can be null
   */
  public Object getInterpreter() {
    return m_Interpreter;
  }

  /**
   * executes the specified method on the current interpreter and returns the
   * result, if any.
   * 
   * @param methodName the name of the method
   * @param paramClasses the classes of the parameters
   * @param paramValues the values of the parameters
   * @return the return value of the method, if any (in that case null)
   */
  public Object invoke(String methodName, Class[] paramClasses,
    Object[] paramValues) {
    Object result;

    result = null;
    if (getInterpreter() != null) {
      result = invoke(getInterpreter(), methodName, paramClasses, paramValues);
    }

    return result;
  }

  /**
   * returns whether the Jython classes are present or not, i.e. whether the
   * classes are in the classpath or not
   * 
   * @return whether the Jython classes are available
   */
  public static boolean isPresent() {
    return m_Present;
  }

  /**
   * initializes and returns a Python Interpreter
   * 
   * @return the interpreter or null if Jython classes not present
   */
  public static Object newInterpreter() {
    Object result;

    result = null;

    if (isPresent()) {
      try {
        result = Class.forName(CLASS_PYTHONINERPRETER).newInstance();
      } catch (Exception e) {
        e.printStackTrace();
        result = null;
      }
    }

    return result;
  }

  /**
   * loads the module and returns a new instance of it as instance of the
   * provided Java class template.
   * 
   * @param file the Jython module file
   * @param template the template for the returned Java object
   * @return the Jython object
   */
  public static Object newInstance(File file, Class template) {
    return newInstance(file, template, new File[0]);
  }

  /**
   * loads the module and returns a new instance of it as instance of the
   * provided Java class template. The paths are added to 'sys.path' - can be
   * used if the module depends on other Jython modules.
   * 
   * @param file the Jython module file
   * @param template the template for the returned Java object
   * @param paths additional paths to add to "sys.path"
   * @return the Jython object
   */
  public static Object newInstance(File file, Class template, File[] paths) {
    Object result;
    String tempName;
    String instanceName;
    String javaClassName;
    String objectDef;
    int i;
    String[] tmpPaths;
    HashSet currentPaths;
    String filename;
    Object interpreter;

    result = null;

    if (!isPresent()) {
      return result;
    }

    interpreter = newInterpreter();
    if (interpreter == null) {
      return result;
    }

    // add paths to sys.path
    if (paths.length > 0) {
      invoke(interpreter, "exec", new Class[] { String.class },
        new Object[] { "import sys" });

      // determine currently set paths
      instanceName = "syspath";
      invoke(interpreter, "exec", new Class[] { String.class },
        new Object[] { instanceName + " = sys.path" });
      currentPaths = new HashSet();
      try {
        tmpPaths = (String[]) invoke(interpreter, "get", new Class[] {
          String.class, Class.class }, new Object[] { instanceName,
          String[].class });
        for (i = 0; i < tmpPaths.length; i++) {
          currentPaths.add(tmpPaths[i]);
        }
      } catch (Exception ex) {
        ex.printStackTrace();
      }

      // add only new paths
      for (i = 0; i < paths.length; i++) {
        if (!currentPaths.contains(paths[i].getAbsolutePath())) {
          invoke(interpreter, "exec", new Class[] { String.class },
            new Object[] { "sys.path.append('" + paths[i].getAbsolutePath()
              + "')" });
        }
      }
    }

    // get object
    filename = file.getAbsolutePath();
    invoke(interpreter, "execfile", new Class[] { String.class },
      new Object[] { filename });
    tempName = filename.substring(filename.lastIndexOf("/") + 1);
    tempName = tempName.substring(0, tempName.indexOf("."));
    instanceName = tempName.toLowerCase();
    javaClassName = tempName.substring(0, 1).toUpperCase()
      + tempName.substring(1);
    objectDef = "=" + javaClassName + "()";
    invoke(interpreter, "exec", new Class[] { String.class },
      new Object[] { instanceName + objectDef });
    try {
      result = invoke(interpreter, "get", new Class[] { String.class,
        Class.class }, new Object[] { instanceName, template });
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return result;
  }

  /**
   * executes the specified method and returns the result, if any
   * 
   * @param o the object the method should be called from, e.g., a Python
   *          Interpreter
   * @param methodName the name of the method
   * @param paramClasses the classes of the parameters
   * @param paramValues the values of the parameters
   * @return the return value of the method, if any (in that case null)
   */
  public static Object invoke(Object o, String methodName,
    Class[] paramClasses, Object[] paramValues) {
    Method m;
    Object result;

    result = null;

    try {
      m = o.getClass().getMethod(methodName, paramClasses);
      result = m.invoke(o, paramValues);
    } catch (Exception e) {
      e.printStackTrace();
      result = null;
    }

    return result;
  }

  /**
   * deserializes the Python Object from the stream
   * 
   * @param in the stream to use
   * @return the deserialized object
   */
  public static Object deserialize(InputStream in) {
    Class cls;
    Class[] paramTypes;
    Constructor constr;
    Object[] arglist;
    Object obj;
    Object result;

    result = null;

    try {
      cls = Class.forName(CLASS_PYTHONOBJECTINPUTSTREAM);
      paramTypes = new Class[] { InputStream.class };
      constr = cls.getConstructor(paramTypes);
      arglist = new Object[] { in };
      obj = constr.newInstance(arglist);
      result = invoke(obj, "readObject", new Class[] {}, new Object[] {});
    } catch (Exception e) {
      e.printStackTrace();
    }

    return result;
  }

  /**
   * Returns the revision string.
   * 
   * @return the revision
   */
  @Override
  public String getRevision() {
    return RevisionUtils.extract("$Revision: 10203 $");
  }

  /**
   * If no arguments are given, it just prints the presence of the Jython
   * classes, otherwise it expects a Jython filename to execute.
   * 
   * @param args commandline arguments
   */
  public static void main(String[] args) {
    if (args.length == 0) {
      System.out.println("Jython present: " + isPresent());
    } else {
      Jython jython = new Jython();
      if (jython.getInterpreter() == null) {
        System.err.println("Cannot instantiate Python Interpreter!");
      } else {
        jython.invoke("execfile", new Class[] { String.class },
          new Object[] { args[0] });
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy