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 }