GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / web / org / codehaus / groovy / grails / web / mapping / DefaultUrlMappingInfo.java
blob244513817c31900389a478866931fedf4274f217
1 /* Copyright 2004-2005 Graeme Rocher
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 package org.codehaus.groovy.grails.web.mapping;
17 import groovy.lang.Closure;
18 import org.codehaus.groovy.grails.commons.GrailsClassUtils;
19 import org.codehaus.groovy.grails.web.mapping.exceptions.UrlMappingException;
20 import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
21 import org.codehaus.groovy.grails.web.util.WebUtils;
22 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
23 import org.springframework.web.context.request.RequestContextHolder;
25 import javax.servlet.http.HttpServletRequest;
26 import java.io.UnsupportedEncodingException;
27 import java.net.URLDecoder;
28 import java.util.*;
30 /**
31 * A Class that implements the UrlMappingInfo interface and holds information established from a matched
32 * URL
34 * @author Graeme Rocher
35 * @since 0.5
36 * <p/>
37 * <p/>
38 * Created: Mar 1, 2007
39 * Time: 7:19:35 AM
41 public class DefaultUrlMappingInfo implements UrlMappingInfo {
42 private Map params = Collections.EMPTY_MAP;
43 private Object controllerName;
44 private Object actionName;
45 private Object id;
46 private static final String ID_PARAM = "id";
47 private UrlMappingData urlData;
48 private Object viewName;
49 private URLDecoder decoder;
51 private DefaultUrlMappingInfo(Map params, UrlMappingData urlData) {
52 this.params = Collections.unmodifiableMap(params);
53 this.id = params.get(ID_PARAM);
54 this.urlData = urlData;
57 public DefaultUrlMappingInfo(Object controllerName, Object actionName, Object viewName, Map params, UrlMappingData urlData) {
58 this(params, urlData);
59 if (controllerName == null && viewName == null)
60 throw new IllegalArgumentException("URL mapping must either provide a controller or view name to map to!");
61 if (params == null) throw new IllegalArgumentException("Argument [params] cannot be null");
62 this.controllerName = controllerName;
63 this.actionName = actionName;
64 if (actionName == null)
65 this.viewName = viewName;
68 public DefaultUrlMappingInfo(Object viewName, Map params, UrlMappingData urlData) {
69 this(params, urlData);
70 this.viewName = viewName;
71 if (viewName == null) throw new IllegalArgumentException("Argument [viewName] cannot be null or blank");
75 public String toString() {
76 return urlData.getUrlPattern();
79 /**
80 * Populates request parameters for the given UrlMappingInfo instance using the GrailsWebRequest
82 * @param dispatchParams The Map instance
83 * @see org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
85 protected void populateParamsForMapping(Map dispatchParams) {
86 Collection keys = this.params.keySet();
87 keys = DefaultGroovyMethods.toList(keys);
88 Collections.sort((List) keys, new Comparator() {
90 public int compare(Object leftKey, Object rightKey) {
91 Object leftValue = params.get(leftKey);
92 Object rightValue = params.get(rightKey);
93 boolean leftIsClosure = leftValue instanceof Closure;
94 boolean rightIsClosure = rightValue instanceof Closure;
95 if (leftIsClosure && rightIsClosure) return 0;
96 else if (leftIsClosure && !rightIsClosure) return 1;
97 else if (rightIsClosure && !leftIsClosure) return -1;
98 return 0;
101 for (Iterator j = keys.iterator(); j.hasNext();) {
103 String name = (String) j.next();
104 Object param = this.params.get(name);
105 if(param instanceof Closure) {
106 param = evaluateNameForValue(param);
108 if (param instanceof String) {
109 try {
110 param = decoder.decode((String) param, "UTF-8");
111 } catch (UnsupportedEncodingException e) {
112 param = evaluateNameForValue(param);
115 dispatchParams.put(name, param);
120 public Map getParameters() {
121 return params;
124 public void configure(GrailsWebRequest webRequest) {
125 populateParamsForMapping(webRequest.getParams());
128 public String getControllerName() {
129 String controllerName = evaluateNameForValue(this.controllerName);
130 if (controllerName == null && getViewName() == null)
131 throw new UrlMappingException("Unable to establish controller name to dispatch for [" + this.controllerName + "]. Dynamic closure invocation returned null. Check your mapping file is correct, when assigning the controller name as a request parameter it cannot be an optional token!");
132 return controllerName;
135 public String getActionName() {
136 GrailsWebRequest webRequest = (GrailsWebRequest) RequestContextHolder.getRequestAttributes();
138 String name = webRequest!=null ? checkDispatchAction(webRequest.getCurrentRequest(), null) : null;
139 if(name == null) {
140 name = evaluateNameForValue(this.actionName);
142 return name;
145 public String getViewName() {
146 return evaluateNameForValue(this.viewName);
149 public String getId() {
150 return evaluateNameForValue(this.id);
153 private String evaluateNameForValue(Object value) {
154 GrailsWebRequest webRequest = (GrailsWebRequest) RequestContextHolder.getRequestAttributes();
155 return evaluateNameForValue(value, webRequest);
158 private String evaluateNameForValue(Object value, GrailsWebRequest webRequest) {
159 if (value == null) {
160 return null;
162 String name;
163 if (value instanceof Closure) {
164 Closure callable = (Closure) value;
165 Object result = ((Closure) callable.clone()).call();
166 name = result != null ? result.toString() : null;
167 } else if (value instanceof Map) {
168 Map httpMethods = (Map) value;
169 name = (String) httpMethods.get(webRequest.getCurrentRequest().getMethod());
170 } else {
171 name = value.toString();
173 return name;
176 private String checkDispatchAction(HttpServletRequest request, String actionName) {
177 for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) {
178 String name = (String) e.nextElement();
179 if (name.startsWith(WebUtils.DISPATCH_ACTION_PARAMETER)) {
180 // remove .x suffix in case of submit image
181 if (name.endsWith(".x") || name.endsWith(".y")) {
182 name = name.substring(0, name.length() - 2);
184 actionName = GrailsClassUtils.getPropertyNameRepresentation(name.substring((WebUtils.DISPATCH_ACTION_PARAMETER).length()));
185 break;
188 return actionName;