GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / commons / org / codehaus / groovy / grails / commons / GrailsResourceUtils.java
blob3536e8b3485f72ab2124cbe05789f2fb1cdec0c8
1 /*
2 * Copyright 2004-2005 the original author or authors.
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 package org.codehaus.groovy.grails.commons;
18 //import java.io.File;
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.codehaus.groovy.grails.exceptions.GrailsConfigurationException;
22 import org.springframework.core.io.Resource;
23 import org.springframework.core.io.UrlResource;
25 import java.io.File;
26 import java.io.IOException;
27 import java.net.MalformedURLException;
28 import java.net.URL;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
32 /**
33 * Utility methods for working with Grails resources and URLs that represent artifacts
34 * within a Grails application
36 * @author Graeme Rocher
38 * @since 0.2
40 * Created: 20th June 2006
42 public class GrailsResourceUtils {
44 //private static final String FS = File.separator;
46 /**
47 * The relative path to the WEB-INF directory
49 public static final String WEB_INF = "/WEB-INF";
51 /**
52 * The name of the Grails application directory
54 public static final String GRAILS_APP_DIR = "grails-app";
56 /**
57 * The name of the Web app dir within Grails
59 public static final String WEB_APP_DIR = "web-app";
61 /**
62 * The path to the views directory
64 public static final String VIEWS_DIR_PATH = GRAILS_APP_DIR + "/views/";
67 Domain path is always matched against the normalized File representation of an URL and
68 can therefore work with slashes as separators.
70 public static Pattern DOMAIN_PATH_PATTERN = Pattern.compile(".+/"+GRAILS_APP_DIR+"/domain/(.+)\\.groovy");
73 This pattern will match any resource within a given directory inside grails-app
75 public static Pattern RESOURCE_PATH_PATTERN = Pattern.compile(".+?/"+GRAILS_APP_DIR+"/(.+?)/(.+?\\.groovy)");
77 public static Pattern SPRING_SCRIPTS_PATH_PATTERN = Pattern.compile(".+?/"+GRAILS_APP_DIR+"/conf/spring/(.+?\\.groovy)");
79 public static Pattern[] COMPILER_ROOT_PATTERNS = {
80 SPRING_SCRIPTS_PATH_PATTERN,
81 RESOURCE_PATH_PATTERN
85 Resources are resolved against the platform specific path and must therefore obey the
86 specific File.separator.
88 public static final Pattern GRAILS_RESOURCE_PATTERN_FIRST_MATCH;
89 public static final Pattern GRAILS_RESOURCE_PATTERN_SECOND_MATCH;
90 public static final Pattern GRAILS_RESOURCE_PATTERN_THIRD_MATCH;
91 public static final Pattern GRAILS_RESOURCE_PATTERN_FOURTH_MATCH;
92 public static final Pattern GRAILS_RESOURCE_PATTERN_FIFTH_MATCH;
93 public static final Pattern GRAILS_RESOURCE_PATTERN_SIXTH_MATCH;
95 static {
96 String fs = File.separator;
97 if (fs.equals("\\")) fs = "\\\\"; // backslashes need escaping in regexes
99 GRAILS_RESOURCE_PATTERN_FIRST_MATCH = Pattern.compile(createGrailsResourcePattern(fs, GRAILS_APP_DIR +fs+ "conf" +fs + "spring"));
100 GRAILS_RESOURCE_PATTERN_THIRD_MATCH = Pattern.compile(createGrailsResourcePattern(fs, GRAILS_APP_DIR +fs +"\\w+"));
101 GRAILS_RESOURCE_PATTERN_FIFTH_MATCH = Pattern.compile(createGrailsResourcePattern(fs, "grails-tests"));
102 fs = "/";
103 GRAILS_RESOURCE_PATTERN_SECOND_MATCH = Pattern.compile(createGrailsResourcePattern(fs, GRAILS_APP_DIR +fs+ "conf" +fs + "spring"));
104 GRAILS_RESOURCE_PATTERN_FOURTH_MATCH = Pattern.compile(createGrailsResourcePattern(fs, GRAILS_APP_DIR +fs +"\\w+"));
105 GRAILS_RESOURCE_PATTERN_SIXTH_MATCH = Pattern.compile(createGrailsResourcePattern(fs, "grails-tests"));
108 public static final Pattern[] patterns = new Pattern[]{
109 GRAILS_RESOURCE_PATTERN_FIRST_MATCH,
110 GRAILS_RESOURCE_PATTERN_SECOND_MATCH,
111 GRAILS_RESOURCE_PATTERN_THIRD_MATCH,
112 GRAILS_RESOURCE_PATTERN_FOURTH_MATCH,
113 GRAILS_RESOURCE_PATTERN_FIFTH_MATCH,
114 GRAILS_RESOURCE_PATTERN_SIXTH_MATCH
116 private static final Log LOG = LogFactory.getLog(GrailsResourceUtils.class);
119 private static String createGrailsResourcePattern(String separator, String base) {
120 return ".+"+separator +base+separator +"(.+)\\.groovy";
125 * Checks whether the file referenced by the given url is a domain class
127 * @param url The URL instance
128 * @return True if it is a domain class
130 public static boolean isDomainClass(URL url) {
131 if (url == null) return false;
133 return DOMAIN_PATH_PATTERN.matcher(url.getFile()).find();
137 * Gets the class name of the specified Grails resource
139 * @param resource The Spring Resource
140 * @return The class name or null if the resource is not a Grails class
142 public static String getClassName(Resource resource) {
143 try {
144 return getClassName(resource.getFile().getAbsolutePath());
145 } catch (IOException e) {
146 throw new GrailsConfigurationException("I/O error reading class name from resource ["+resource+"]: " + e.getMessage(),e );
151 * Returns the class name for a Grails resource
153 * @param path The path to check
154 * @return The class name or null if it doesn't exist
156 public static String getClassName(String path) {
157 for (int i = 0; i < patterns.length; i++) {
158 Matcher m = patterns[i].matcher(path);
159 if(m.find()) {
160 return m.group(1).replaceAll("[/\\\\]", ".");
163 return null;
167 * Checks whether the specified path is a Grails path
169 * @param path The path to check
170 * @return True if it is a Grails path
172 public static boolean isGrailsPath(String path) {
173 for (int i = 0; i < patterns.length; i++) {
174 Matcher m = patterns[i].matcher(path);
175 if(m.find()) {
176 return true;
179 return false;
183 public static boolean isGrailsResource(Resource r) {
184 try {
185 return isGrailsPath(r.getURL().getFile());
186 } catch (IOException e) {
187 return false;
191 public static Resource getViewsDir(Resource resource) {
192 if(resource == null)return null;
194 try {
195 Resource appDir = getAppDir(resource);
196 return new UrlResource(appDir.getURL().toString()+"/views");
198 } catch (IOException e) {
199 if(LOG.isDebugEnabled()) {
200 LOG.debug("Error reading URL whilst resolving views dir from ["+resource+"]: " + e.getMessage(),e);
202 return null;
207 public static Resource getAppDir(Resource resource) {
208 if(resource == null)return null;
211 try {
212 String url = resource.getURL().toString();
214 int i = url.lastIndexOf(GRAILS_APP_DIR);
215 if(i > -1) {
216 url = url.substring(0, i+10);
217 return new UrlResource(url);
219 else {
220 return null;
222 } catch (MalformedURLException e) {
223 return null;
224 } catch (IOException e) {
225 if(LOG.isDebugEnabled()) {
226 LOG.debug("Error reading URL whilst resolving app dir from ["+resource+"]: " + e.getMessage(),e);
228 return null;
233 private static final Pattern PLUGIN_PATTERN = Pattern.compile(".+?(/plugins/.+?/"+GRAILS_APP_DIR+"/.+)");
236 * This method will take a Grails resource (one located inside the grails-app dir) and get its relative path inside the WEB-INF directory
237 * when deployed
239 * @param resource The Grails resource, which is a file inside the grails-app dir
240 * @return The relative URL of the file inside the WEB-INF dir at deployment time or null if it cannot be established
242 public static String getRelativeInsideWebInf(Resource resource) {
243 if(resource == null) return null;
245 try {
246 String url = resource.getURL().toString();
247 int i = url.indexOf(WEB_INF);
248 if(i > -1) {
249 return url.substring(i);
251 else {
252 Matcher m = PLUGIN_PATTERN.matcher(url);
253 if(m.find()) {
254 return WEB_INF +m.group(1);
256 else {
257 i = url.lastIndexOf(GRAILS_APP_DIR);
258 if(i > -1) {
259 return WEB_INF+"/" + url.substring(i);
264 } catch (IOException e) {
265 if(LOG.isDebugEnabled()) {
266 LOG.debug("Error reading URL whilst resolving relative path within WEB-INF from ["+resource+"]: " + e.getMessage(),e);
268 return null;
271 return null;
275 private static final Pattern PLUGIN_RESOURCE_PATTERN = Pattern.compile(".+?/(plugins/.+?)/"+GRAILS_APP_DIR+"/.+");
278 * Retrieves the static resource path for the given Grails resource artifact (controller/taglib etc.)
280 * @param resource The Resource
281 * @param contextPath The additonal context path to prefix
282 * @return The resource path
284 public static String getStaticResourcePathForResource(Resource resource, String contextPath) {
286 if(contextPath == null)contextPath = "";
287 if(resource == null)return contextPath;
289 String url;
290 try {
291 url = resource.getURL().toString();
292 } catch (IOException e) {
293 if(LOG.isDebugEnabled()) {
294 LOG.debug("Error reading URL whilst resolving static resource path from ["+resource+"]: " + e.getMessage(),e);
296 return contextPath;
299 Matcher m = PLUGIN_RESOURCE_PATTERN.matcher(url);
300 if(m.find()) {
301 return (contextPath.length() > 0 ? contextPath + "/" : "") + m.group(1);
304 return contextPath;
308 * Get the path relative to an artefact folder under grails-app i.e:
310 * Input: /usr/joe/project/grails-app/conf/BootStrap.groovy
311 * Output: BootStrap.groovy
313 * Input: /usr/joe/project/grails-app/domain/com/mystartup/Book.groovy
314 * Output: com/mystartup/Book.groovy
316 * @param path The path to evaluate
317 * @return The path relative to the root folder grails-app
319 public static String getPathFromRoot(String path) {
320 for (int i = 0; i < COMPILER_ROOT_PATTERNS.length; i++) {
321 Matcher m = COMPILER_ROOT_PATTERNS[i].matcher(path);
322 if(m.find()) {
323 return m.group(m.groupCount());
326 return null;