4471 |
05 Sep 08 |
jari |
1 |
/** |
4471 |
05 Sep 08 |
jari |
$Id $ |
4471 |
05 Sep 08 |
jari |
3 |
|
4471 |
05 Sep 08 |
jari |
Copyright (C) Authors contributing to this file. |
4471 |
05 Sep 08 |
jari |
5 |
|
4471 |
05 Sep 08 |
jari |
This file is part of BASE - BioArray Software Environment. |
4471 |
05 Sep 08 |
jari |
Available at http://base.thep.lu.se/ |
4471 |
05 Sep 08 |
jari |
8 |
|
4471 |
05 Sep 08 |
jari |
BASE is free software; you can redistribute it and/or |
4471 |
05 Sep 08 |
jari |
modify it under the terms of the GNU General Public License |
4480 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
4471 |
05 Sep 08 |
jari |
of the License, or (at your option) any later version. |
4471 |
05 Sep 08 |
jari |
13 |
|
4471 |
05 Sep 08 |
jari |
BASE is distributed in the hope that it will be useful, |
4471 |
05 Sep 08 |
jari |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
4471 |
05 Sep 08 |
jari |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4471 |
05 Sep 08 |
jari |
GNU General Public License for more details. |
4471 |
05 Sep 08 |
jari |
18 |
|
4471 |
05 Sep 08 |
jari |
You should have received a copy of the GNU General Public License |
4512 |
11 Sep 08 |
jari |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
4471 |
05 Sep 08 |
jari |
21 |
*/ |
4471 |
05 Sep 08 |
jari |
22 |
package net.sf.basedb.clients.web.extensions; |
4471 |
05 Sep 08 |
jari |
23 |
|
4471 |
05 Sep 08 |
jari |
24 |
import java.io.File; |
4471 |
05 Sep 08 |
jari |
25 |
import java.io.FileNotFoundException; |
4471 |
05 Sep 08 |
jari |
26 |
import java.lang.reflect.Method; |
4471 |
05 Sep 08 |
jari |
27 |
import java.net.URL; |
4471 |
05 Sep 08 |
jari |
28 |
import java.net.URLClassLoader; |
4471 |
05 Sep 08 |
jari |
29 |
import java.util.regex.Matcher; |
4471 |
05 Sep 08 |
jari |
30 |
import java.util.regex.Pattern; |
4471 |
05 Sep 08 |
jari |
31 |
|
4471 |
05 Sep 08 |
jari |
32 |
import org.apache.jasper.JasperException; |
4471 |
05 Sep 08 |
jari |
33 |
import org.apache.jasper.JspCompilationContext; |
4471 |
05 Sep 08 |
jari |
34 |
import org.apache.jasper.compiler.JDTCompiler; |
4471 |
05 Sep 08 |
jari |
35 |
import org.apache.jasper.servlet.JspServletWrapper; |
5840 |
01 Nov 11 |
nicklas |
36 |
import org.apache.juli.logging.Log; |
5840 |
01 Nov 11 |
nicklas |
37 |
import org.apache.juli.logging.LogFactory; |
4471 |
05 Sep 08 |
jari |
38 |
|
4471 |
05 Sep 08 |
jari |
39 |
/** |
4471 |
05 Sep 08 |
jari |
Class that enabled compilation of custom JSP pages that are |
4471 |
05 Sep 08 |
jari |
part of an extension that uses classes from the extension JAR |
4471 |
05 Sep 08 |
jari |
file (eg. a JAR file in the /WEB-INF/extensions directory). |
4471 |
05 Sep 08 |
jari |
<p> |
4471 |
05 Sep 08 |
jari |
44 |
|
4471 |
05 Sep 08 |
jari |
To make this compiler work the following is required: |
4471 |
05 Sep 08 |
jari |
<ul> |
4471 |
05 Sep 08 |
jari |
<li>The JSP file must have a '.xjsp' extension. |
4471 |
05 Sep 08 |
jari |
<li>This compiler class must be installed in Tomcat's /lib |
4471 |
05 Sep 08 |
jari |
directory. |
4471 |
05 Sep 08 |
jari |
<li>The '.xjsp' extensions must be mapped to the regular JSP servlet |
4471 |
05 Sep 08 |
jari |
with the 'compilerClass' parameter set to this class. |
4471 |
05 Sep 08 |
jari |
</ul> |
4471 |
05 Sep 08 |
jari |
53 |
|
7612 |
01 Mar 19 |
nicklas |
Note! This feature is experimental. We only test it at unregular intervals |
7612 |
01 Mar 19 |
nicklas |
and since it depends on internal implementation details of Tomcat it may |
7612 |
01 Mar 19 |
nicklas |
or may not work with future or older versions of Tomcat. |
4471 |
05 Sep 08 |
jari |
57 |
|
4471 |
05 Sep 08 |
jari |
@author nicklas |
4471 |
05 Sep 08 |
jari |
@version 2.7 |
4471 |
05 Sep 08 |
jari |
@base.modified $Date:2008-03-20 12:15:25 +0100 (Thu, 20 Mar 2008) $ |
4471 |
05 Sep 08 |
jari |
61 |
*/ |
4471 |
05 Sep 08 |
jari |
62 |
public class XJspCompiler |
4471 |
05 Sep 08 |
jari |
63 |
extends JDTCompiler |
4471 |
05 Sep 08 |
jari |
64 |
{ |
4471 |
05 Sep 08 |
jari |
65 |
|
4471 |
05 Sep 08 |
jari |
66 |
/** |
4471 |
05 Sep 08 |
jari |
The location where the extensions resources are extracted. |
4471 |
05 Sep 08 |
jari |
68 |
*/ |
4471 |
05 Sep 08 |
jari |
69 |
public static final String RESOURCES_URL = "/extensions"; |
4471 |
05 Sep 08 |
jari |
70 |
|
4471 |
05 Sep 08 |
jari |
71 |
/** |
4471 |
05 Sep 08 |
jari |
Path to JSP must match: /extensions/[jar-file-name]/[jsp-path].xjsp |
4471 |
05 Sep 08 |
jari |
group(1) = JAR name, group(2) = JSP path |
4471 |
05 Sep 08 |
jari |
74 |
*/ |
4471 |
05 Sep 08 |
jari |
75 |
private static final Pattern PATH_MATCH = |
4471 |
05 Sep 08 |
jari |
76 |
Pattern.compile(RESOURCES_URL + "/([^/]+)/(.+\\.xjsp)"); |
5840 |
01 Nov 11 |
nicklas |
77 |
|
5840 |
01 Nov 11 |
nicklas |
78 |
private final Log log; |
5840 |
01 Nov 11 |
nicklas |
79 |
|
5746 |
15 Sep 11 |
nicklas |
// The path to the plug-ins directory |
5746 |
15 Sep 11 |
nicklas |
81 |
private File pluginsDir; |
4471 |
05 Sep 08 |
jari |
// If this JSP is an extensions JSP |
4471 |
05 Sep 08 |
jari |
83 |
private boolean isXJsp; |
4471 |
05 Sep 08 |
jari |
// The extensions JAR file |
4471 |
05 Sep 08 |
jari |
85 |
private File extensionsJar; |
4471 |
05 Sep 08 |
jari |
// The last modified time of the currently loaded extensions JAR file |
4471 |
05 Sep 08 |
jari |
87 |
private long lastModified; |
4471 |
05 Sep 08 |
jari |
88 |
|
4471 |
05 Sep 08 |
jari |
89 |
public XJspCompiler() |
5840 |
01 Nov 11 |
nicklas |
90 |
{ |
5840 |
01 Nov 11 |
nicklas |
91 |
log = LogFactory.getLog(XJspCompiler.class); |
5840 |
01 Nov 11 |
nicklas |
92 |
} |
4471 |
05 Sep 08 |
jari |
93 |
|
4471 |
05 Sep 08 |
jari |
94 |
/** |
4471 |
05 Sep 08 |
jari |
From the JDTCompiler class and it's superclasses |
4471 |
05 Sep 08 |
jari |
96 |
------------------------------------------------ |
4471 |
05 Sep 08 |
jari |
97 |
*/ |
4471 |
05 Sep 08 |
jari |
98 |
/** |
4471 |
05 Sep 08 |
jari |
Initialises the compiler. The JSP name is matched against the |
4471 |
05 Sep 08 |
jari |
required pattern and the name of the extensions JAR file is |
4471 |
05 Sep 08 |
jari |
extracted from the request path. |
4471 |
05 Sep 08 |
jari |
102 |
*/ |
4471 |
05 Sep 08 |
jari |
103 |
@Override |
5746 |
15 Sep 11 |
nicklas |
104 |
public void init(JspCompilationContext ctxt, JspServletWrapper jsw) |
4471 |
05 Sep 08 |
jari |
105 |
{ |
5746 |
15 Sep 11 |
nicklas |
106 |
super.init(ctxt, jsw); |
4471 |
05 Sep 08 |
jari |
107 |
String jspName = ctxt.getJspFile(); |
5746 |
15 Sep 11 |
nicklas |
108 |
if (log.isDebugEnabled()) |
5746 |
15 Sep 11 |
nicklas |
109 |
{ |
5746 |
15 Sep 11 |
nicklas |
110 |
log.debug("Initialising XJSP compiler for file: " + jspName); |
5746 |
15 Sep 11 |
nicklas |
111 |
} |
4471 |
05 Sep 08 |
jari |
112 |
Matcher m = PATH_MATCH.matcher(jspName); |
4471 |
05 Sep 08 |
jari |
113 |
if (m.matches()) |
4471 |
05 Sep 08 |
jari |
114 |
{ |
4471 |
05 Sep 08 |
jari |
115 |
String jarName = m.group(1); |
5746 |
15 Sep 11 |
nicklas |
116 |
File pluginsDir = getPluginsDir(); |
5746 |
15 Sep 11 |
nicklas |
117 |
extensionsJar = new File(pluginsDir, jarName); |
4471 |
05 Sep 08 |
jari |
118 |
isXJsp = extensionsJar.exists(); |
5746 |
15 Sep 11 |
nicklas |
119 |
} |
4471 |
05 Sep 08 |
jari |
120 |
if (log.isDebugEnabled()) |
4471 |
05 Sep 08 |
jari |
121 |
{ |
5746 |
15 Sep 11 |
nicklas |
122 |
log.debug("JAR=" + extensionsJar + "; isXJsp=" + isXJsp); |
4471 |
05 Sep 08 |
jari |
123 |
} |
4471 |
05 Sep 08 |
jari |
124 |
} |
4471 |
05 Sep 08 |
jari |
125 |
|
4471 |
05 Sep 08 |
jari |
126 |
/** |
4471 |
05 Sep 08 |
jari |
Called when a JSP page needs recompiling. We check if the extension JAR file |
4471 |
05 Sep 08 |
jari |
has been modified and update the class loader if it has. |
4471 |
05 Sep 08 |
jari |
129 |
*/ |
4471 |
05 Sep 08 |
jari |
130 |
@Override |
7612 |
01 Mar 19 |
nicklas |
131 |
public void compile(boolean compileClass, boolean jspcMode) |
4471 |
05 Sep 08 |
jari |
132 |
throws FileNotFoundException, JasperException, Exception |
4471 |
05 Sep 08 |
jari |
133 |
{ |
4471 |
05 Sep 08 |
jari |
134 |
if (log.isDebugEnabled()) |
4471 |
05 Sep 08 |
jari |
135 |
{ |
4471 |
05 Sep 08 |
jari |
136 |
log.debug("Generate class for file: " + ctxt.getJspFile() + |
4471 |
05 Sep 08 |
jari |
137 |
"; JAR=" + extensionsJar + "; isXJsp=" + isXJsp); |
4471 |
05 Sep 08 |
jari |
138 |
} |
4471 |
05 Sep 08 |
jari |
139 |
setContextClassLoader(); |
7612 |
01 Mar 19 |
nicklas |
140 |
super.compile(compileClass, jspcMode); |
4471 |
05 Sep 08 |
jari |
141 |
} |
4471 |
05 Sep 08 |
jari |
142 |
|
4471 |
05 Sep 08 |
jari |
143 |
/** |
4471 |
05 Sep 08 |
jari |
Checks if the extensions JAR file has been modified. If not, |
4471 |
05 Sep 08 |
jari |
calls super.isOutDated(checkClass) |
4471 |
05 Sep 08 |
jari |
146 |
*/ |
4471 |
05 Sep 08 |
jari |
147 |
@Override |
4471 |
05 Sep 08 |
jari |
148 |
public boolean isOutDated(boolean checkClass) |
4471 |
05 Sep 08 |
jari |
149 |
{ |
4471 |
05 Sep 08 |
jari |
150 |
if (isXJsp && lastModified != extensionsJar.lastModified()) |
4471 |
05 Sep 08 |
jari |
151 |
{ |
4471 |
05 Sep 08 |
jari |
152 |
return true; |
4471 |
05 Sep 08 |
jari |
153 |
} |
4471 |
05 Sep 08 |
jari |
154 |
return super.isOutDated(checkClass); |
4471 |
05 Sep 08 |
jari |
155 |
} |
4471 |
05 Sep 08 |
jari |
156 |
// --------------------------------------------- |
4471 |
05 Sep 08 |
jari |
157 |
|
4471 |
05 Sep 08 |
jari |
158 |
/** |
4471 |
05 Sep 08 |
jari |
Sets the context class loader if this JSP page is an |
4471 |
05 Sep 08 |
jari |
extension JSP page and if the extensions JAR file has been |
4471 |
05 Sep 08 |
jari |
modified since the last time the class loader was set. |
4471 |
05 Sep 08 |
jari |
This method does nothing if the JSP file is not an extensions |
4471 |
05 Sep 08 |
jari |
JSP file, or if the JAR file hasn't changed since the last |
4471 |
05 Sep 08 |
jari |
use. |
4471 |
05 Sep 08 |
jari |
165 |
*/ |
4471 |
05 Sep 08 |
jari |
166 |
protected void setContextClassLoader() |
4471 |
05 Sep 08 |
jari |
167 |
throws Exception |
4471 |
05 Sep 08 |
jari |
168 |
{ |
4471 |
05 Sep 08 |
jari |
169 |
if (!isXJsp || lastModified == extensionsJar.lastModified()) return; |
4471 |
05 Sep 08 |
jari |
170 |
|
4471 |
05 Sep 08 |
jari |
171 |
if (log.isDebugEnabled()) |
4471 |
05 Sep 08 |
jari |
172 |
{ |
4471 |
05 Sep 08 |
jari |
173 |
log.debug("Setting class loader for file: " + ctxt.getJspFile() + |
4471 |
05 Sep 08 |
jari |
174 |
"; JAR=" + extensionsJar + "; isXJsp=" + isXJsp); |
4471 |
05 Sep 08 |
jari |
175 |
} |
4471 |
05 Sep 08 |
jari |
176 |
|
4471 |
05 Sep 08 |
jari |
177 |
URLClassLoader classLoader = getExtensionClassLoader(); |
4471 |
05 Sep 08 |
jari |
178 |
ctxt.setClassLoader(classLoader); |
4471 |
05 Sep 08 |
jari |
179 |
lastModified = extensionsJar.lastModified(); |
4471 |
05 Sep 08 |
jari |
180 |
} |
4471 |
05 Sep 08 |
jari |
181 |
|
4471 |
05 Sep 08 |
jari |
182 |
/** |
4471 |
05 Sep 08 |
jari |
Get a class loader that can load classes from the current web application |
4471 |
05 Sep 08 |
jari |
as well as the extensions JAR file. The class loader for the current |
4471 |
05 Sep 08 |
jari |
web application can be found in JspRuntimeContext.getParentClassLoader(). |
4471 |
05 Sep 08 |
jari |
The extensions class loader is loaded from JarClassLoader in BASE. |
4471 |
05 Sep 08 |
jari |
187 |
*/ |
4471 |
05 Sep 08 |
jari |
188 |
protected URLClassLoader getExtensionClassLoader() |
4471 |
05 Sep 08 |
jari |
189 |
throws Exception |
4471 |
05 Sep 08 |
jari |
190 |
{ |
4471 |
05 Sep 08 |
jari |
191 |
ClassLoader webAppLoader = getWebAppClassLoader(); |
4471 |
05 Sep 08 |
jari |
192 |
|
4471 |
05 Sep 08 |
jari |
// Get a reference to the JarClassLoader.getInstance(String, boolean) method |
4471 |
05 Sep 08 |
jari |
194 |
Class<?> jarClass = Class.forName("net.sf.basedb.util.JarClassLoader", true, webAppLoader); |
4471 |
05 Sep 08 |
jari |
195 |
Method getInstance = jarClass.getMethod("getInstance", String.class, boolean.class); |
4471 |
05 Sep 08 |
jari |
196 |
|
4471 |
05 Sep 08 |
jari |
// Call JarClassLoader.getInstance(jarPath, true) |
4471 |
05 Sep 08 |
jari |
198 |
ClassLoader jarLoader = (ClassLoader)getInstance.invoke(null, extensionsJar.getAbsolutePath(), true); |
4471 |
05 Sep 08 |
jari |
199 |
return new URLClassLoader(new URL[0], jarLoader); |
4471 |
05 Sep 08 |
jari |
200 |
} |
4471 |
05 Sep 08 |
jari |
201 |
|
4471 |
05 Sep 08 |
jari |
202 |
/** |
4471 |
05 Sep 08 |
jari |
Get the class loader for the web application this JSP is |
4471 |
05 Sep 08 |
jari |
located in. Default implementation returns JspRuntimeContext.getParentClassLoader() |
4471 |
05 Sep 08 |
jari |
205 |
*/ |
4471 |
05 Sep 08 |
jari |
206 |
protected ClassLoader getWebAppClassLoader() |
4471 |
05 Sep 08 |
jari |
207 |
{ |
5746 |
15 Sep 11 |
nicklas |
208 |
return getCompilationContext().getRuntimeContext().getParentClassLoader(); |
4471 |
05 Sep 08 |
jari |
209 |
} |
4471 |
05 Sep 08 |
jari |
210 |
|
5746 |
15 Sep 11 |
nicklas |
211 |
/** |
5746 |
15 Sep 11 |
nicklas |
Get the path to the plug-in directory from BASE. |
5746 |
15 Sep 11 |
nicklas |
@since 3.0 |
5746 |
15 Sep 11 |
nicklas |
214 |
*/ |
5746 |
15 Sep 11 |
nicklas |
215 |
protected File getPluginsDir() |
5746 |
15 Sep 11 |
nicklas |
216 |
{ |
5746 |
15 Sep 11 |
nicklas |
217 |
if (pluginsDir == null) |
5746 |
15 Sep 11 |
nicklas |
218 |
{ |
5746 |
15 Sep 11 |
nicklas |
219 |
try |
5746 |
15 Sep 11 |
nicklas |
220 |
{ |
5746 |
15 Sep 11 |
nicklas |
221 |
ClassLoader webAppLoader = getWebAppClassLoader(); |
5746 |
15 Sep 11 |
nicklas |
222 |
Class<?> appClass = Class.forName("net.sf.basedb.core.Application", true, webAppLoader); |
5746 |
15 Sep 11 |
nicklas |
223 |
Method getPluginsDirectory = appClass.getMethod("getPluginsDirectory"); |
5746 |
15 Sep 11 |
nicklas |
224 |
pluginsDir = (File)getPluginsDirectory.invoke(null); |
5746 |
15 Sep 11 |
nicklas |
225 |
} |
5746 |
15 Sep 11 |
nicklas |
226 |
catch (Exception ex) |
5746 |
15 Sep 11 |
nicklas |
227 |
{ |
5746 |
15 Sep 11 |
nicklas |
228 |
log.error("Could not get plug-ins directory", ex); |
5746 |
15 Sep 11 |
nicklas |
229 |
} |
5746 |
15 Sep 11 |
nicklas |
230 |
} |
5746 |
15 Sep 11 |
nicklas |
231 |
return pluginsDir; |
5746 |
15 Sep 11 |
nicklas |
232 |
} |
4471 |
05 Sep 08 |
jari |
233 |
|
4471 |
05 Sep 08 |
jari |
234 |
} |