View Javadoc

1   /*
2    * Copyright 2011 FatWire Corporation. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.fatwire.gst.foundation.groovy;
18  
19  import groovy.util.GroovyScriptEngine;
20  import groovy.util.ResourceException;
21  import groovy.util.ScriptException;
22  
23  import java.io.File;
24  import java.io.FileFilter;
25  import java.net.MalformedURLException;
26  import java.net.URI;
27  import java.net.URL;
28  
29  import javax.servlet.ServletContext;
30  
31  import org.apache.commons.lang.StringUtils;
32  import org.apache.commons.logging.Log;
33  import org.codehaus.groovy.control.CompilationFailedException;
34  
35  import com.fatwire.gst.foundation.facade.logging.LogUtil;
36  
37  /**
38   * Loader for groovy script classes, configured via the ServletContext
39   * 
40   * @author Dolf Dijkstra
41   * @since Mar 28, 2011
42   */
43  /*
44   * alternative method:
45   * http://groovy.codehaus.org/Alternate+Spring-Groovy-Integration
46   */
47  public class DiskGroovyLoader implements GroovyLoader {
48  
49      private Log logger = LogUtil.getLog(getClass());
50      private GroovyScriptEngine groovyScriptEngine;
51  
52      private File scriptPath;
53      private String configPath = "/WEB-INF/gsf-groovy";
54      private int minimumRecompilationInterval = 0;
55  
56      public DiskGroovyLoader() {
57          super();
58  
59      }
60  
61      public DiskGroovyLoader(ServletContext servletContext) {
62          bootEngine(servletContext.getRealPath(configPath));
63  
64      }
65  
66      public void bootEngine(String path) {
67          scriptPath = new File(path).getAbsoluteFile();
68          scriptPath.mkdirs();
69          if (!scriptPath.exists() || !scriptPath.isDirectory())
70              throw new IllegalStateException("The realPath " + scriptPath + " is not a directory.");
71          URI u = scriptPath.toURI();
72          URL[] paths;
73          try {
74              paths = new URL[] { u.toURL() };
75              groovyScriptEngine = new GroovyScriptEngine(paths, Thread.currentThread().getContextClassLoader());
76              groovyScriptEngine.getConfig().setRecompileGroovySource(true);
77              groovyScriptEngine.getConfig().setMinimumRecompilationInterval(minimumRecompilationInterval);
78          } catch (MalformedURLException e) {
79              throw new IllegalStateException("The realPath " + scriptPath + " can't be made into a URL. "
80                      + e.getMessage(), e);
81          }
82  
83      }
84  
85      @Override
86      public Object load(final String name) throws Exception {
87  
88          Class<?> c;
89          try {
90              c = groovyScriptEngine.loadScriptByName(toScriptName(name));
91          } catch (ResourceException e) {
92  
93              if (logger.isDebugEnabled())
94                  logger.debug("GroovyScriptEngine was not able to load " + name + " as a script: " + e.getMessage()
95                          + ". Now trying as a class.");
96              String className = name.replace('/', '.');
97              try {
98                  c = groovyScriptEngine.getGroovyClassLoader().loadClass(className);
99              } catch (ClassNotFoundException cnfe) {
100                 if (logger.isDebugEnabled())
101                     logger.debug("GroovyClassLoader was not able to load " + className + ": " + cnfe.getMessage()
102                             + ". Aborting.");
103                 return null;
104 
105             }
106         }
107 
108         return c.newInstance();
109     }
110 
111     protected String toScriptName(String name) {
112         if (name.endsWith(".groovy")) {
113             return StringUtils.removeEnd(name, ".groovy").replace('.', '/') + ".groovy";
114         } else
115             return name.replace('.', '/') + ".groovy";
116     }
117 
118     protected String toClassName(String name) {
119 
120         return name.replace('/', '.').replace('\\', '.').substring(0, name.length() - 7);
121     }
122 
123     public void precompile() {
124         doDir(scriptPath);
125 
126     }
127 
128     protected void doDir(File dir) {
129         File[] listFiles = dir.listFiles(new FileFilter() {
130 
131             @Override
132             public boolean accept(File pathname) {
133                 return pathname.isDirectory() || pathname.getName().endsWith(".groovy");
134             }
135 
136         });
137         for (File file : listFiles) {
138             if (file.isDirectory()) {
139                 doDir(file);
140             } else {
141                 String name = file.getAbsolutePath().substring(scriptPath.getAbsolutePath().length() + 1);
142                 try {
143 
144                     groovyScriptEngine.loadScriptByName(name);
145                 } catch (CompilationFailedException e) {
146                     logger.warn(e.getMessage() + " on " + name + " during precompilation.");
147                 } catch (ResourceException e) {
148                     logger.warn(e.getMessage() + " on " + name + " during precompilation.");
149                 } catch (ScriptException e) {
150                     logger.warn(e.getMessage() + " on " + name + " during precompilation.");
151                 }
152             }
153         }
154     }
155 
156     /**
157      * @return the configPath
158      */
159     public String getConfigPath() {
160         return configPath;
161     }
162 
163     /**
164      * @param configPath the configPath to set
165      */
166     public void setConfigPath(String configPath) {
167         this.configPath = configPath;
168     }
169 
170     /**
171      * @return the minimumRecompilationInterval
172      */
173     public int getMinimumRecompilationInterval() {
174         return minimumRecompilationInterval;
175     }
176 
177     /**
178      * Sets the minimumRecompilationInterval of the GroovyScriptEngine
179      * configuration.
180      * 
181      * @param minimumRecompilationInterval the minimumRecompilationInterval to
182      *            set
183      */
184     public void setMinimumRecompilationInterval(int minimumRecompilationInterval) {
185         this.minimumRecompilationInterval = minimumRecompilationInterval;
186         GroovyScriptEngine g = getGroovyScriptEngine();
187         if (g != null) {
188             g.getConfig().setMinimumRecompilationInterval(minimumRecompilationInterval);
189         }
190     }
191 
192     public GroovyScriptEngine getGroovyScriptEngine() {
193         return groovyScriptEngine;
194     }
195 
196     public void setGroovyScriptEngine(GroovyScriptEngine groovyScrptEngine) {
197         this.groovyScriptEngine = groovyScrptEngine;
198     }
199 
200 }