2 * Copyright 2004-2005 the original author or authors.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
;
26 import java
.io
.IOException
;
27 import java
.net
.MalformedURLException
;
29 import java
.util
.regex
.Matcher
;
30 import java
.util
.regex
.Pattern
;
33 * Utility methods for working with Grails resources and URLs that represent artifacts
34 * within a Grails application
36 * @author Graeme Rocher
40 * Created: 20th June 2006
42 public class GrailsResourceUtils
{
44 //private static final String FS = File.separator;
47 * The relative path to the WEB-INF directory
49 public static final String WEB_INF
= "/WEB-INF";
52 * The name of the Grails application directory
54 public static final String GRAILS_APP_DIR
= "grails-app";
57 * The name of the Web app dir within Grails
59 public static final String WEB_APP_DIR
= "web-app";
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
,
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
;
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"));
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
) {
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
);
160 return m
.group(1).replaceAll("[/\\\\]", ".");
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
);
183 public static boolean isGrailsResource(Resource r
) {
185 return isGrailsPath(r
.getURL().getFile());
186 } catch (IOException e
) {
191 public static Resource
getViewsDir(Resource resource
) {
192 if(resource
== null)return null;
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
);
207 public static Resource
getAppDir(Resource resource
) {
208 if(resource
== null)return null;
212 String url
= resource
.getURL().toString();
214 int i
= url
.lastIndexOf(GRAILS_APP_DIR
);
216 url
= url
.substring(0, i
+10);
217 return new UrlResource(url
);
222 } catch (MalformedURLException e
) {
224 } catch (IOException e
) {
225 if(LOG
.isDebugEnabled()) {
226 LOG
.debug("Error reading URL whilst resolving app dir from ["+resource
+"]: " + e
.getMessage(),e
);
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
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;
246 String url
= resource
.getURL().toString();
247 int i
= url
.indexOf(WEB_INF
);
249 return url
.substring(i
);
252 Matcher m
= PLUGIN_PATTERN
.matcher(url
);
254 return WEB_INF
+m
.group(1);
257 i
= url
.lastIndexOf(GRAILS_APP_DIR
);
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
);
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
;
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
);
299 Matcher m
= PLUGIN_RESOURCE_PATTERN
.matcher(url
);
301 return (contextPath
.length() > 0 ? contextPath
+ "/" : "") + m
.group(1);
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
);
323 return m
.group(m
.groupCount());