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 }