1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.portals.bridges.groovy;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.UnsupportedEncodingException;
23 import java.net.URLDecoder;
24
25 import javax.portlet.Portlet;
26 import javax.portlet.PortletConfig;
27 import javax.portlet.PortletException;
28 import javax.portlet.ActionRequest;
29 import javax.portlet.ActionResponse;
30 import javax.portlet.RenderRequest;
31 import javax.portlet.RenderResponse;
32
33 import groovy.lang.GroovyClassLoader;
34 import groovy.lang.GroovyCodeSource;
35 import org.codehaus.groovy.control.CompilationFailedException;
36
37 /***
38 * <p>
39 * GroovyPortlet parses and invokes a groovy-scripted portlet. A groovy-scripted
40 * portlet just need to be implemented like any other Java-based portlet. So, a
41 * groovy-scripted portlet can support full features of JSR-168 portlet.
42 *
43 * @author <a href="mailto:woon_san@yahoo.com">Woonsan Ko</a>
44 * @Id@
45 */
46 public class GroovyPortlet implements Portlet
47 {
48 public static final String SCRIPT_SOURCE_INIT_PARAM = "script-source";
49
50 public static final String SCRIPT_SOURCE_URL_ENCODING_INIT_PARAM = "script-source-uri-encoding";
51
52 public static final String AUTO_REFRESH_INIT_PARAM = "auto-refresh";
53
54 protected PortletConfig portletConfig;
55
56 protected String scriptSourceUri;
57
58 protected String scriptSourceUriEncoding = "UTF-8";
59
60 protected boolean autoRefresh;
61
62 protected long parsedFileLastModified;
63
64 protected GroovyCodeSource groovyCodeSource;
65
66 protected Portlet scriptPortletInstance;
67
68 protected GroovyClassLoader groovyClassLoader;
69
70 public GroovyPortlet()
71 {
72 }
73
74 public void init(PortletConfig config) throws PortletException
75 {
76 this.portletConfig = config;
77 this.groovyClassLoader = new GroovyClassLoader();
78
79 this.autoRefresh = "true".equals(config.getInitParameter(AUTO_REFRESH_INIT_PARAM));
80
81 String param = config.getInitParameter(SCRIPT_SOURCE_URL_ENCODING_INIT_PARAM);
82
83 if (param != null)
84 {
85 this.scriptSourceUriEncoding = param;
86 }
87
88 this.scriptSourceUri = config.getInitParameter(SCRIPT_SOURCE_INIT_PARAM);
89
90 if (this.scriptSourceUri == null)
91 {
92 throw new PortletException("Configuration failed: " + SCRIPT_SOURCE_INIT_PARAM + " should be set properly!");
93 }
94 else
95 {
96 try
97 {
98 if (this.scriptSourceUri.startsWith("file:"))
99 {
100 String decodedScriptSourceUri = this.scriptSourceUri;
101
102 try
103 {
104 decodedScriptSourceUri = URLDecoder.decode(this.scriptSourceUri, this.scriptSourceUriEncoding);
105 }
106 catch (UnsupportedEncodingException encodingEx)
107 {
108 throw new PortletException("Unsupported encoding: " + this.scriptSourceUriEncoding);
109 }
110
111 this.groovyCodeSource = new GroovyCodeSource(new File(decodedScriptSourceUri.substring(5)));
112 }
113 else if (this.scriptSourceUri.startsWith("classpath:"))
114 {
115 String resourceURL = this.groovyClassLoader.getResource(this.scriptSourceUri.substring(10))
116 .toString();
117
118 if (resourceURL.startsWith("file:"))
119 {
120 String decodedScriptSourceUri = resourceURL;
121
122 try
123 {
124 decodedScriptSourceUri = URLDecoder.decode(resourceURL, this.scriptSourceUriEncoding);
125 }
126 catch (UnsupportedEncodingException encodingEx)
127 {
128 throw new PortletException("Unsupported encoding: " + this.scriptSourceUriEncoding);
129 }
130
131 this.groovyCodeSource = new GroovyCodeSource(new File(decodedScriptSourceUri.substring(5)));
132 }
133 else
134 {
135 throw new PortletException(SCRIPT_SOURCE_INIT_PARAM
136 + " with 'classpath:' prefix should indicate to a local resource");
137 }
138 }
139 else
140 {
141 this.groovyCodeSource = new GroovyCodeSource(new File(config.getPortletContext().getRealPath(
142 this.scriptSourceUri)));
143 }
144 }
145 catch (FileNotFoundException e)
146 {
147 throw new PortletException("File not found: " + this.scriptSourceUri, e);
148 }
149
150 this.groovyCodeSource.setCachable(!this.autoRefresh);
151 }
152
153 refreshPortletInstance();
154
155 if (this.scriptPortletInstance == null)
156 {
157 throw new PortletException("Groovy script portlet is not available!");
158 }
159 }
160
161 public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException
162 {
163 refreshPortletInstance();
164
165 if (this.scriptPortletInstance == null)
166 {
167 throw new PortletException("Groovy script portlet is not available!");
168 }
169 else
170 {
171 this.scriptPortletInstance.processAction(request, response);
172 }
173 }
174
175 public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException
176 {
177 refreshPortletInstance();
178
179 if (this.scriptPortletInstance == null)
180 {
181 throw new PortletException("Groovy script portlet is not available!");
182 }
183 else
184 {
185 this.scriptPortletInstance.render(request, response);
186 }
187 }
188
189 public void destroy()
190 {
191 if (this.scriptPortletInstance != null)
192 {
193 this.scriptPortletInstance.destroy();
194 }
195 }
196
197 protected void refreshPortletInstance() throws PortletException
198 {
199 if (this.scriptPortletInstance == null)
200 {
201 try
202 {
203 createScriptPortletInstance();
204 }
205 catch (Exception ex)
206 {
207 throw new PortletException("Could not compile script: " + this.scriptSourceUri, ex);
208 }
209 }
210 else if (this.autoRefresh && isScriptFileModified())
211 {
212 synchronized (this.scriptPortletInstance)
213 {
214 try
215 {
216 createScriptPortletInstance();
217 }
218 catch (Exception ex)
219 {
220 throw new PortletException("Could not compile script: " + this.scriptSourceUri, ex);
221 }
222 }
223 }
224 }
225
226 protected boolean isScriptFileModified()
227 {
228 return (this.groovyCodeSource.getFile().lastModified() > this.parsedFileLastModified);
229 }
230
231 protected void createScriptPortletInstance() throws CompilationFailedException, InstantiationException,
232 IOException, IllegalAccessException, PortletException
233 {
234 Class scriptPortletClass = this.groovyClassLoader.parseClass(this.groovyCodeSource);
235 this.scriptPortletInstance = (Portlet) scriptPortletClass.newInstance();
236 this.parsedFileLastModified = this.groovyCodeSource.getFile().lastModified();
237 this.scriptPortletInstance.init(this.portletConfig);
238 }
239 }