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 import java.util.Collection;
25 import java.util.ArrayList;
26
27 import javax.portlet.PortletPreferences;
28 import javax.portlet.PreferencesValidator;
29 import javax.portlet.ValidatorException;
30
31 import groovy.lang.GroovyClassLoader;
32 import groovy.lang.GroovyCodeSource;
33 import org.codehaus.groovy.control.CompilationFailedException;
34
35 /***
36 * <p>
37 * GroovyPreferencesValidator parses and invokes a groovy-scripted validator. A groovy-scripted
38 * PreferencesValidator just need to be implemented like any other Java-based preferences validator.
39 *
40 * @author <a href="mailto:woon_san@yahoo.com">Woonsan Ko</a>
41 * @Id@
42 */
43 public class GroovyPreferencesValidator implements PreferencesValidator
44 {
45 public static final String SCRIPT_SOURCE_PREF_KEY = "validator-script-source";
46
47 public static final String SCRIPT_SOURCE_URL_ENCODING_PREF_KEY = "validator-script-source-uri-encoding";
48
49 public static final String AUTO_REFRESH_PREF_KEY = "validator-auto-refresh";
50
51 protected String scriptSourceUri;
52
53 protected String scriptSourceUriEncoding = "UTF-8";
54
55 protected boolean autoRefresh;
56
57 protected long parsedFileLastModified;
58
59 protected GroovyCodeSource groovyCodeSource;
60
61 protected PreferencesValidator scriptPreferencesValidatorInstance;
62
63 protected GroovyClassLoader groovyClassLoader;
64
65 public GroovyPreferencesValidator()
66 {
67 }
68
69 public void validate(PortletPreferences preferences) throws ValidatorException
70 {
71 if (this.groovyCodeSource == null)
72 {
73 initialize(preferences);
74 }
75
76 refreshPreferencesValidatorInstance();
77
78 this.scriptPreferencesValidatorInstance.validate(preferences);
79 }
80
81 public void initialize(PortletPreferences preferences) throws ValidatorException
82 {
83 this.groovyClassLoader = new GroovyClassLoader();
84
85 this.autoRefresh = "true".equals(preferences.getValue(AUTO_REFRESH_PREF_KEY, null));
86
87 String param = preferences.getValue(SCRIPT_SOURCE_URL_ENCODING_PREF_KEY, null);
88
89 if (param != null)
90 {
91 this.scriptSourceUriEncoding = param;
92 }
93
94 this.scriptSourceUri = preferences.getValue(SCRIPT_SOURCE_PREF_KEY, null);
95
96 if (this.scriptSourceUri == null)
97 {
98 Collection failedKeys = new ArrayList();
99 failedKeys.add(SCRIPT_SOURCE_PREF_KEY);
100 throw new ValidatorException("Configuration failed: " + SCRIPT_SOURCE_PREF_KEY + " should be set properly!", failedKeys);
101 }
102 else
103 {
104 try
105 {
106 if (this.scriptSourceUri.startsWith("file:"))
107 {
108 String decodedScriptSourceUri = this.scriptSourceUri;
109
110 try
111 {
112 decodedScriptSourceUri = URLDecoder.decode(this.scriptSourceUri, this.scriptSourceUriEncoding);
113 }
114 catch (UnsupportedEncodingException encodingEx)
115 {
116 Collection failedKeys = new ArrayList();
117 failedKeys.add(SCRIPT_SOURCE_URL_ENCODING_PREF_KEY);
118 throw new ValidatorException("Unsupported encoding: " + this.scriptSourceUriEncoding, failedKeys);
119 }
120
121 this.groovyCodeSource = new GroovyCodeSource(new File(decodedScriptSourceUri.substring(5)));
122 }
123 else if (this.scriptSourceUri.startsWith("classpath:"))
124 {
125 String resourceURL = this.groovyClassLoader.getResource(this.scriptSourceUri.substring(10))
126 .toString();
127
128 if (resourceURL.startsWith("file:"))
129 {
130 String decodedScriptSourceUri = resourceURL;
131
132 try
133 {
134 decodedScriptSourceUri = URLDecoder.decode(resourceURL, this.scriptSourceUriEncoding);
135 }
136 catch (UnsupportedEncodingException encodingEx)
137 {
138 Collection failedKeys = new ArrayList();
139 failedKeys.add(SCRIPT_SOURCE_URL_ENCODING_PREF_KEY);
140 throw new ValidatorException("Unsupported encoding: " + this.scriptSourceUriEncoding, failedKeys);
141 }
142
143 this.groovyCodeSource = new GroovyCodeSource(new File(decodedScriptSourceUri.substring(5)));
144 }
145 else
146 {
147 Collection failedKeys = new ArrayList();
148 failedKeys.add(SCRIPT_SOURCE_PREF_KEY);
149 throw new ValidatorException(SCRIPT_SOURCE_PREF_KEY
150 + " with 'classpath:' prefix should indicate to a local resource", failedKeys);
151 }
152 }
153 else
154 {
155 Collection failedKeys = new ArrayList();
156 failedKeys.add(SCRIPT_SOURCE_PREF_KEY);
157 throw new ValidatorException("Configuration failed: " + SCRIPT_SOURCE_PREF_KEY + " should be prefixed by 'file:' or 'classpath'.", failedKeys);
158 }
159 }
160 catch (FileNotFoundException e)
161 {
162 Collection failedKeys = new ArrayList();
163 failedKeys.add(SCRIPT_SOURCE_PREF_KEY);
164 throw new ValidatorException("File not found: " + this.scriptSourceUri, failedKeys);
165 }
166
167 this.groovyCodeSource.setCachable(!this.autoRefresh);
168 }
169 }
170
171 protected void refreshPreferencesValidatorInstance() throws ValidatorException
172 {
173 if (this.scriptPreferencesValidatorInstance == null)
174 {
175 try
176 {
177 createScriptPreferencesValidatorInstance();
178 }
179 catch (Exception ex)
180 {
181 Collection failedKeys = new ArrayList();
182 failedKeys.add(SCRIPT_SOURCE_PREF_KEY);
183 throw new ValidatorException("Could not compile script: " + this.scriptSourceUri, failedKeys);
184 }
185 }
186 else if (this.autoRefresh && isScriptFileModified())
187 {
188 synchronized (this.scriptPreferencesValidatorInstance)
189 {
190 try
191 {
192 createScriptPreferencesValidatorInstance();
193 }
194 catch (Exception ex)
195 {
196 Collection failedKeys = new ArrayList();
197 failedKeys.add(SCRIPT_SOURCE_PREF_KEY);
198 throw new ValidatorException("Could not compile script: " + this.scriptSourceUri, failedKeys);
199 }
200 }
201 }
202 }
203
204 protected boolean isScriptFileModified()
205 {
206 return (this.groovyCodeSource.getFile().lastModified() > this.parsedFileLastModified);
207 }
208
209 protected void createScriptPreferencesValidatorInstance() throws CompilationFailedException, InstantiationException,
210 IOException, IllegalAccessException, ValidatorException
211 {
212 Class scriptPreferencesValidatorClass = this.groovyClassLoader.parseClass(this.groovyCodeSource);
213 this.scriptPreferencesValidatorInstance = (PreferencesValidator) scriptPreferencesValidatorClass.newInstance();
214 this.parsedFileLastModified = this.groovyCodeSource.getFile().lastModified();
215 }
216 }