Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
PythonBaseFactory |
|
| 3.3333333333333335;3,333 |
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.configuration2.Configuration; | |
27 | import org.apache.commons.lang3.StringUtils; | |
28 | import org.apache.logging.log4j.LogManager; | |
29 | import org.apache.logging.log4j.Logger; | |
30 | import org.apache.turbine.modules.Assembler; | |
31 | import org.apache.turbine.modules.Loader; | |
32 | import org.apache.turbine.services.TurbineServices; | |
33 | import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService; | |
34 | import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory; | |
35 | import org.python.core.Py; | |
36 | import org.python.util.PythonInterpreter; | |
37 | ||
38 | /** | |
39 | * A factory that attempts to load a python class in the | |
40 | * JPython interpreter and execute it as a Turbine screen. | |
41 | * The JPython script should inherit from Turbine Screen or one | |
42 | * of its subclasses. | |
43 | * | |
44 | * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a> | |
45 | * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> | |
46 | * @param <T> the specialized assembler type | |
47 | */ | |
48 | 0 | public abstract class PythonBaseFactory<T extends Assembler> |
49 | implements AssemblerFactory<T> | |
50 | { | |
51 | /** Key for the python path */ | |
52 | public static final String PYTHON_PATH = "python.path"; | |
53 | ||
54 | /** Global config file. This is executed before every screen */ | |
55 | public static final String PYTHON_CONFIG_FILE = "conf.py"; | |
56 | ||
57 | /** Logging */ | |
58 | 0 | private static Logger log = LogManager.getLogger(PythonBaseFactory.class); |
59 | ||
60 | /** Our configuration */ | |
61 | 0 | private final Configuration conf = TurbineServices.getInstance().getConfiguration(AssemblerBrokerService.SERVICE_NAME); |
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 | 0 | String path = conf.getString(PYTHON_PATH); |
75 | ||
76 | 0 | if (StringUtils.isEmpty(path)) |
77 | { | |
78 | 0 | throw new Exception( |
79 | "Python path not found - check your Properties"); | |
80 | } | |
81 | ||
82 | 0 | log.debug("Screen name for JPython: {}", name); |
83 | ||
84 | 0 | T assembler = null; |
85 | ||
86 | 0 | String confName = path + "/" + PYTHON_CONFIG_FILE; |
87 | ||
88 | // The filename of the Python script | |
89 | 0 | StringBuilder fName = new StringBuilder(); |
90 | ||
91 | 0 | fName.append(path); |
92 | 0 | fName.append("/"); |
93 | 0 | fName.append(subDirectory); |
94 | 0 | fName.append("/"); |
95 | 0 | fName.append(name.toLowerCase()); |
96 | 0 | fName.append(".py"); |
97 | ||
98 | 0 | File f = new File(fName.toString()); |
99 | ||
100 | 0 | if (f.exists()) |
101 | { | |
102 | // We try to open the Py Interpreter | |
103 | 0 | try (PythonInterpreter interp = new PythonInterpreter()) |
104 | { | |
105 | // Make sure the Py Interpreter use the right classloader | |
106 | // This is necessary for servlet engines generally has | |
107 | // their own classloader implementations and servlets aren't | |
108 | // loaded in the system classloader. The python script will | |
109 | // load java package | |
110 | // org.apache.turbine.services.assemblerbroker.util.python; | |
111 | // the new classes to it as well. | |
112 | 0 | Py.getSystemState().setClassLoader(this.getClass().getClassLoader()); |
113 | ||
114 | // We import the Python SYS module. Now we don't need to do this | |
115 | // explicitly in the script. We always use the sys module to | |
116 | // do stuff like loading java package | |
117 | // org.apache.turbine.services.assemblerbroker.util.python; | |
118 | 0 | interp.exec("import sys"); |
119 | ||
120 | // Now we try to load the script file | |
121 | 0 | interp.execfile(confName); |
122 | 0 | interp.execfile(fName.toString()); |
123 | ||
124 | try | |
125 | { | |
126 | // We create an instance of the screen class from the | |
127 | // python script | |
128 | 0 | interp.exec("scr = " + name + "()"); |
129 | } | |
130 | 0 | catch (Throwable e) |
131 | { | |
132 | 0 | throw new Exception( |
133 | "\nCannot create an instance of the python class.\n" | |
134 | + "You probably gave your class the wrong name.\n" | |
135 | + "Your class should have the same name as your " | |
136 | + "filename.\nFilenames should be all lowercase and " | |
137 | + "classnames should start with a capital.\n" | |
138 | + "Expected class name: " + name + "\n"); | |
139 | 0 | } |
140 | ||
141 | // Here we convert the python screen instance to a java instance. | |
142 | @SuppressWarnings("unchecked") // Cast from Object necessary | |
143 | 0 | T t = (T) interp.get("scr", Assembler.class); |
144 | 0 | assembler = t; |
145 | 0 | } |
146 | 0 | catch (Exception e) |
147 | { | |
148 | // We log the error here because this code is not widely tested | |
149 | // yet. After we tested the code on a range of platforms this | |
150 | // won't be useful anymore. | |
151 | 0 | log.error("PYTHON SCRIPT SCREEN LOADER ERROR:", e); |
152 | 0 | throw e; |
153 | 0 | } |
154 | } | |
155 | 0 | return assembler; |
156 | } | |
157 | ||
158 | /** | |
159 | * Get the loader for this type of assembler | |
160 | * | |
161 | * @return a Loader | |
162 | */ | |
163 | @Override | |
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 | @Override | |
172 | public int getCacheSize() | |
173 | ||
174 | { | |
175 | 0 | return getLoader().getCacheSize(); |
176 | } | |
177 | } |