View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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 }