GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / web / org / codehaus / groovy / grails / web / sitemesh / GrailsLayoutDecoratorMapper.java
blob81efe8be69ced23700f53351b29e5ebbabcf6965
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.web.sitemesh;
18 import com.opensymphony.module.sitemesh.Config;
19 import com.opensymphony.module.sitemesh.Decorator;
20 import com.opensymphony.module.sitemesh.DecoratorMapper;
21 import com.opensymphony.module.sitemesh.Page;
22 import com.opensymphony.module.sitemesh.mapper.AbstractDecoratorMapper;
23 import com.opensymphony.module.sitemesh.mapper.DefaultDecorator;
24 import groovy.lang.GroovyObject;
25 import org.apache.commons.lang.ArrayUtils;
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.codehaus.groovy.grails.commons.GrailsApplication;
30 import org.codehaus.groovy.grails.commons.GrailsResourceUtils;
31 import org.codehaus.groovy.grails.web.metaclass.ControllerDynamicMethods;
32 import org.codehaus.groovy.grails.web.pages.GroovyPageResourceLoader;
33 import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes;
34 import org.springframework.context.ApplicationContext;
35 import org.springframework.core.io.Resource;
36 import org.springframework.core.io.ResourceLoader;
37 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
38 import org.springframework.web.context.support.WebApplicationContextUtils;
40 import javax.servlet.ServletContext;
41 import javax.servlet.http.HttpServletRequest;
42 import java.io.IOException;
43 import java.util.Collections;
44 import java.util.HashMap;
45 import java.util.Map;
46 import java.util.Properties;
48 /**
49 * Implements the SiteMesh decorator mapper interface and allows grails views to map to grails layouts
51 * @author Graeme Rocher
52 * @since Oct 10, 2005
54 public class GrailsLayoutDecoratorMapper extends AbstractDecoratorMapper implements DecoratorMapper {
56 private static final String DEFAULT_DECORATOR_PATH = GrailsApplicationAttributes.PATH_TO_VIEWS+"/layouts";
57 private static final String DEFAULT_VIEW_TYPE = ".gsp";
59 private static final Log LOG = LogFactory.getLog( GrailsLayoutDecoratorMapper.class );
62 private Map decoratorMap = new HashMap();
63 private ServletContext servletContext;
65 public void init(Config config, Properties properties, DecoratorMapper parent) throws InstantiationException {
66 super.init(config,properties,parent);
67 this.servletContext = config.getServletContext();
71 public Decorator getDecorator(HttpServletRequest request, Page page) {
72 if(LOG.isDebugEnabled()) {
73 LOG.debug("Evaluating layout for request: " + request.getRequestURI());
75 String layoutName = page.getProperty("meta.layout");
77 if(StringUtils.isBlank(layoutName)) {
78 GroovyObject controller = (GroovyObject)request.getAttribute(GrailsApplicationAttributes.CONTROLLER);
79 if(controller != null) {
81 String controllerName = (String)controller.getProperty(ControllerDynamicMethods.CONTROLLER_NAME_PROPERTY);
82 String actionUri = (String)controller.getProperty(ControllerDynamicMethods.ACTION_URI_PROPERTY);
84 if(LOG.isDebugEnabled())
85 LOG.debug("Found controller in request, location layout for controller ["+controllerName+"] and action ["+actionUri+"]");
88 Decorator d = getNamedDecorator(request, actionUri.substring(1));
89 if(d!=null) {
90 return d;
91 } else if(!StringUtils.isBlank(controllerName)) {
92 if(LOG.isDebugEnabled())
93 LOG.debug("Action layout not found, trying controller");
95 d = getNamedDecorator(request, controllerName);
96 if(d != null) {
97 return d;
99 else {
100 return parent != null ? super.getDecorator(request, page) : null;
106 else {
107 return parent != null ? super.getDecorator(request, page) : null;
111 if(LOG.isDebugEnabled()) {
112 LOG.debug("Evaluated layout for page: " + layoutName);
114 Decorator d = getNamedDecorator(request, layoutName);
115 if(d != null) {
116 return d;
118 else {
119 return parent != null ? super.getDecorator(request, page) : null;
123 public Decorator getNamedDecorator(HttpServletRequest request, String name) {
124 if(StringUtils.isBlank(name))return null;
126 if(decoratorMap.containsKey(name)) {
127 return (Decorator)decoratorMap.get(name);
129 else {
130 String decoratorName = name;
131 if(!name.matches("(.+)(\\.)(\\w{2}|\\w{3})")) {
132 name += DEFAULT_VIEW_TYPE;
134 String decoratorPage = DEFAULT_DECORATOR_PATH + '/' + name;
136 ResourceLoader resourceLoader = establishResourceLoader();
139 Resource res = resourceLoader.getResource(decoratorPage);
140 if(!res.exists()) {
142 PathMatchingResourcePatternResolver matcher = new PathMatchingResourcePatternResolver(resourceLoader);
143 String pattern = GrailsResourceUtils.WEB_INF + "/plugins/*/grails-app/views/layouts/" + name;
145 if(LOG.isDebugEnabled())
146 LOG.debug("No decorator found at " + decoratorPage+". Trying plug-ins with pattern: " + pattern);
148 try {
149 Resource[] layouts = matcher.getResources(pattern);
150 if(layouts.length>0) {
151 if(layouts.length>1) {
152 LOG.warn("Multiple matching layouts found in plug-ins for name ["+name+"] using first from ["+ ArrayUtils.toString(layouts) +"]");
154 String url = layouts[0].getURL().toString();
155 url = GrailsResourceUtils.WEB_INF + url.substring(url.indexOf("/plugins"),url.length());
156 Decorator d = new DefaultDecorator(name, request.getRequestURI(), url, Collections.EMPTY_MAP);
157 decoratorMap.put(decoratorName, d);
158 return d;
160 } catch (IOException e) {
161 // ignore, if there was a problem here its going to be a FNFE which is ok
163 catch (IllegalArgumentException e) {
164 // ignore, this is thrown when the plugins dir doesn't exist
166 return null;
168 else {
169 if(LOG.isDebugEnabled())
170 LOG.debug("Using decorator " + decoratorPage);
172 Decorator d = new DefaultDecorator(decoratorName,request.getRequestURI(),decoratorPage, Collections.EMPTY_MAP);
173 decoratorMap.put(decoratorName,d);
174 return d;
179 private ResourceLoader establishResourceLoader() {
180 ResourceLoader resourceLoader;
181 ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
182 GrailsApplication application = null;
183 if(ctx.containsBean(GrailsApplication.APPLICATION_ID)) {
184 application = (GrailsApplication)ctx.getBean(GrailsApplication.APPLICATION_ID);
186 if(application == null) {
187 resourceLoader = ctx;
189 else if(ctx.containsBean(GroovyPageResourceLoader.BEAN_ID) && !application.isWarDeployed()) {
190 resourceLoader = (ResourceLoader)ctx.getBean(GroovyPageResourceLoader.BEAN_ID);
192 else {
193 resourceLoader = ctx;
195 return resourceLoader;