001: package org.apache.turbine.services.assemblerbroker.util.python;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.File;
023:
024: import org.apache.commons.configuration.Configuration;
025:
026: import org.apache.commons.lang.StringUtils;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import org.apache.turbine.modules.Assembler;
032: import org.apache.turbine.services.assemblerbroker.TurbineAssemblerBroker;
033: import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
034:
035: import org.python.core.Py;
036: import org.python.util.PythonInterpreter;
037:
038: /**
039: * A factory that attempts to load a python class in the
040: * JPython interpreter and execute it as a Turbine screen.
041: * The JPython script should inherit from Turbine Screen or one
042: * of its subclasses.
043: *
044: * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
045: * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
046: * @version $Id: PythonBaseFactory.java 534527 2007-05-02 16:10:59Z tv $
047: */
048: public abstract class PythonBaseFactory implements AssemblerFactory {
049: /** Key for the python path */
050: public static final String PYTHON_PATH = "python.path";
051:
052: /** Global config file. This is executed before every screen */
053: public static final String PYTHON_CONFIG_FILE = "conf.py";
054:
055: /** Logging */
056: private static Log log = LogFactory.getLog(PythonBaseFactory.class);
057:
058: /** Our configuration */
059: private Configuration conf = TurbineAssemblerBroker.getService()
060: .getConfiguration();
061:
062: /**
063: * Get an Assembler.
064: *
065: * @param subDirectory subdirectory within python.path
066: * @param name name of the requested Assembler
067: * @return an Assembler
068: * @throws Exception generic exception
069: */
070: public Assembler getAssembler(String subDirectory, String name)
071: throws Exception {
072: String path = conf.getString(PYTHON_PATH);
073:
074: if (StringUtils.isEmpty(path)) {
075: throw new Exception(
076: "Python path not found - check your Properties");
077: }
078:
079: log.debug("Screen name for JPython: " + name);
080:
081: Assembler assembler = null;
082:
083: String confName = path + "/" + PYTHON_CONFIG_FILE;
084:
085: // The filename of the Python script
086: StringBuffer fName = new StringBuffer();
087:
088: fName.append(path);
089: fName.append("/");
090: fName.append(subDirectory);
091: fName.append("/");
092: fName.append(name.toLowerCase());
093: fName.append(".py");
094:
095: File f = new File(fName.toString());
096:
097: if (f.exists()) {
098: try {
099: // We try to open the Py Interpreter
100: PythonInterpreter interp = new PythonInterpreter();
101:
102: // Make sure the Py Interpreter use the right classloader
103: // This is necessary for servlet engines generally has
104: // their own classloader implementations and servlets aren't
105: // loaded in the system classloader. The python script will
106: // load java package
107: // org.apache.turbine.services.assemblerbroker.util.python;
108: // the new classes to it as well.
109: Py.getSystemState().setClassLoader(
110: this .getClass().getClassLoader());
111:
112: // We import the Python SYS module. Now we don't need to do this
113: // explicitely in the script. We always use the sys module to
114: // do stuff like loading java package
115: // org.apache.turbine.services.assemblerbroker.util.python;
116: interp.exec("import sys");
117:
118: // Now we try to load the script file
119: interp.execfile(confName);
120: interp.execfile(fName.toString());
121:
122: try {
123: // We create an instance of the screen class from the
124: // python script
125: interp.exec("scr = " + name + "()");
126: } catch (Throwable e) {
127: throw new Exception(
128: "\nCannot create an instance of the python class.\n"
129: + "You probably gave your class the wrong name.\n"
130: + "Your class should have the same name as your "
131: + "filename.\nFilenames should be all lowercase and "
132: + "classnames should start with a capital.\n"
133: + "Expected class name: " + name
134: + "\n");
135: }
136:
137: // Here we convert the python sceen instance to a java instance.
138: assembler = (Assembler) interp.get("scr",
139: Assembler.class);
140: } catch (Exception e) {
141: // We log the error here because this code is not widely tested
142: // yet. After we tested the code on a range of platforms this
143: // won't be usefull anymore.
144: log.error("PYTHON SCRIPT SCREEN LOADER ERROR:", e);
145: throw e;
146: }
147: }
148: return assembler;
149: }
150: }
|