View Javadoc

    1   package org.apache.turbine.services.assemblerbroker.util.python;
    2
    3
    4   /*
    5    * Licensed to the Apache Software Foundation (ASF) under one
    6    * or more contributor license agreements.  See the NOTICE file
    7    * distributed with this work for additional information
    8    * regarding copyright ownership.  The ASF licenses this file
    9    * to you under the Apache License, Version 2.0 (the
    10   * "License"); you may not use this file except in compliance
    11   * with the License.  You may obtain a copy of the License at
    12   *
    13   *   http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing,
    16   * software distributed under the License is distributed on an
    17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    18   * KIND, either express or implied.  See the License for the
    19   * specific language governing permissions and limitations
    20   * under the License.
    21   */
    22
    23
    24  import java.io.File;
    25
    26  import org.apache.commons.configuration.Configuration;
    27  import org.apache.commons.lang.StringUtils;
    28  import org.apache.commons.logging.Log;
    29  import org.apache.commons.logging.LogFactory;
    30  import org.apache.turbine.modules.Assembler;
    31  import org.apache.turbine.modules.Loader;
    32  import org.apache.turbine.services.assemblerbroker.TurbineAssemblerBroker;
    33  import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
    34  import org.python.core.Py;
    35  import org.python.util.PythonInterpreter;
    36
    37  /**
    38   * A factory that attempts to load a python class in the
    39   * JPython interpreter and execute it as a Turbine screen.
    40   * The JPython script should inherit from Turbine Screen or one
    41   * of its subclasses.
    42   *
    43   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
    44   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    45   * @version $Id: PythonBaseFactory.java 1078552 2011-03-06 19:58:46Z tv $
    46   */
    47  public abstract class PythonBaseFactory<T extends Assembler>
    48          implements AssemblerFactory<T>
    49  {
    50      /** Key for the python path */
    51      public static final String PYTHON_PATH = "python.path";
    52
    53      /** Global config file. This is executed before every screen */
    54      public static final String PYTHON_CONFIG_FILE = "conf.py";
    55
    56      /** Logging */
    57      private static Log log = LogFactory.getLog(PythonBaseFactory.class);
    58
    59      /** Our configuration */
    60      private final Configuration conf =
    61          TurbineAssemblerBroker.getService().getConfiguration();
    62
    63      /**
    64       * Get an Assembler.
    65       *
    66       * @param subDirectory subdirectory within python.path
    67       * @param name name of the requested Assembler
    68       * @return an Assembler
    69       * @throws Exception generic exception
    70       */
    71      public T getAssembler(String subDirectory, String name)
    72              throws Exception
    73      {
    74          String path = conf.getString(PYTHON_PATH);
    75
    76          if (StringUtils.isEmpty(path))
    77          {
    78              throw new Exception(
    79                  "Python path not found - check your Properties");
    80          }
    81
    82          log.debug("Screen name for JPython: " + name);
    83
    84          T assembler = null;
    85
    86          String confName = path + "/" + PYTHON_CONFIG_FILE;
    87
    88          // The filename of the Python script
    89          StringBuffer fName = new StringBuffer();
    90
    91          fName.append(path);
    92          fName.append("/");
    93          fName.append(subDirectory);
    94          fName.append("/");
    95          fName.append(name.toLowerCase());
    96          fName.append(".py");
    97
    98          File f = new File(fName.toString());
    99
    100         if (f.exists())
    101         {
    102             try
    103             {
    104                 // We try to open the Py Interpreter
    105                 PythonInterpreter interp = new PythonInterpreter();
    106
    107                 // Make sure the Py Interpreter use the right classloader
    108                 // This is necessary for servlet engines generally has
    109                 // their own classloader implementations and servlets aren't
    110                 // loaded in the system classloader.  The python script will
    111                 // load java package
    112                 // org.apache.turbine.services.assemblerbroker.util.python;
    113                 // the new classes to it as well.
    114                 Py.getSystemState().setClassLoader(
    115                         this.getClass().getClassLoader());
    116
    117                 // We import the Python SYS module. Now we don't need to do this
    118                 // explicitely in the script.  We always use the sys module to
    119                 // do stuff like loading java package
    120                 // org.apache.turbine.services.assemblerbroker.util.python;
    121                 interp.exec("import sys");
    122
    123                 // Now we try to load the script file
    124                 interp.execfile(confName);
    125                 interp.execfile(fName.toString());
    126
    127                 try
    128                 {
    129                     // We create an instance of the screen class from the
    130                     // python script
    131                     interp.exec("scr = " + name + "()");
    132                 }
    133                 catch (Throwable e)
    134                 {
    135                     throw new Exception(
    136                         "\nCannot create an instance of the python class.\n"
    137                         + "You probably gave your class the wrong name.\n"
    138                         + "Your class should have the same name as your "
    139                         + "filename.\nFilenames should be all lowercase and "
    140                         + "classnames should start with a capital.\n"
    141                         + "Expected class name: " + name + "\n");
    142                 }
    143
    144                 // Here we convert the python sceen instance to a java instance.
    145                 assembler = (T) interp.get("scr", Assembler.class);
    146             }
    147             catch (Exception e)
    148             {
    149                 // We log the error here because this code is not widely tested
    150                 // yet. After we tested the code on a range of platforms this
    151                 // won't be useful anymore.
    152                 log.error("PYTHON SCRIPT SCREEN LOADER ERROR:", e);
    153                 throw e;
    154             }
    155         }
    156         return assembler;
    157     }
    158
    159     /**
    160      * Get the loader for this type of assembler
    161      *
    162      * @return a Loader
    163      */
    164     public abstract Loader<T> getLoader();
    165
    166     /**
    167      * Get the size of a possibly configured cache
    168      *
    169      * @return the size of the cache in bytes
    170      */
    171     public int getCacheSize()
    172
    173     {
    174         return getLoader().getCacheSize();
    175     }
    176 }