KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > view > AbstractView


1 /*
2  * Copyright 2002-2007 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
17 package org.springframework.web.servlet.view;
18
19 import java.util.Collections JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Properties JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27 import javax.servlet.http.HttpServletResponse JavaDoc;
28
29 import org.springframework.beans.factory.BeanNameAware;
30 import org.springframework.util.CollectionUtils;
31 import org.springframework.web.context.support.WebApplicationObjectSupport;
32 import org.springframework.web.servlet.View;
33 import org.springframework.web.servlet.support.RequestContext;
34
35 /**
36  * Abstract base class for {@link org.springframework.web.servlet.View}
37  * implementations. Subclasses should be JavaBeans, to allow for
38  * convenient configuration as Spring-managed bean instances.
39  *
40  * <p>Provides support for static attributes, to be made available to the view,
41  * with a variety of ways to specify them. Static attributes will be merged
42  * with the given dynamic attributes (the model that the controller returned)
43  * for each render operation.
44  *
45  * <p>Extends {@link WebApplicationObjectSupport}, which will be helpful to
46  * some views. Subclasses just need to implement the actual rendering.
47  *
48  * @author Rod Johnson
49  * @author Juergen Hoeller
50  * @see #setAttributes
51  * @see #setAttributesMap
52  * @see #renderMergedOutputModel
53  */

54 public abstract class AbstractView extends WebApplicationObjectSupport implements View, BeanNameAware {
55
56     /** Default content type. Overridable as bean property. */
57     public static final String JavaDoc DEFAULT_CONTENT_TYPE = "text/html; charset=ISO-8859-1";
58
59
60     private String JavaDoc beanName;
61
62     private String JavaDoc contentType = DEFAULT_CONTENT_TYPE;
63
64     private String JavaDoc requestContextAttribute;
65
66     /** Map of static attributes, keyed by attribute name (String) */
67     private final Map JavaDoc staticAttributes = new HashMap JavaDoc();
68
69
70     /**
71      * Set the view's name. Helpful for traceability.
72      * Framework code must call this when constructing views.
73      * @param beanName the view's name. May not be <code>null</code>.
74      * Views should use this for log messages.
75      */

76     public void setBeanName(String JavaDoc beanName) {
77         this.beanName = beanName;
78     }
79
80     /**
81      * Return the view's name. Should never be <code>null</code>,
82      * if the view was correctly configured.
83      */

84     public String JavaDoc getBeanName() {
85         return beanName;
86     }
87
88     /**
89      * Set the content type for this view.
90      * Default is "text/html; charset=ISO-8859-1".
91      * <p>May be ignored by subclasses if the view itself is assumed
92      * to set the content type, e.g. in case of JSPs.
93      * @param contentType content type for this view
94      * @see #DEFAULT_CONTENT_TYPE
95      */

96     public void setContentType(String JavaDoc contentType) {
97         this.contentType = contentType;
98     }
99
100     /**
101      * Return the content type for this view.
102      */

103     public String JavaDoc getContentType() {
104         return this.contentType;
105     }
106
107     /**
108      * Set the name of the RequestContext attribute for this view.
109      * Default is none.
110      */

111     public void setRequestContextAttribute(String JavaDoc requestContextAttribute) {
112         this.requestContextAttribute = requestContextAttribute;
113     }
114
115     /**
116      * Return the name of the RequestContext attribute, if any.
117      */

118     public String JavaDoc getRequestContextAttribute() {
119         return this.requestContextAttribute;
120     }
121
122     /**
123      * Set static attributes as a CSV string.
124      * Format is: attname0={value1},attname1={value1}
125      */

126     public void setAttributesCSV(String JavaDoc propString) throws IllegalArgumentException JavaDoc {
127         if (propString != null) {
128             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(propString, ",");
129             while (st.hasMoreTokens()) {
130                 String JavaDoc tok = st.nextToken();
131                 int eqIdx = tok.indexOf("=");
132                 if (eqIdx == -1) {
133                     throw new IllegalArgumentException JavaDoc("Expected = in attributes CSV string '" + propString + "'");
134                 }
135                 if (eqIdx >= tok.length() - 2) {
136                     throw new IllegalArgumentException JavaDoc(
137                             "At least 2 characters ([]) required in attributes CSV string '" + propString + "'");
138                 }
139                 String JavaDoc name = tok.substring(0, eqIdx);
140                 String JavaDoc value = tok.substring(eqIdx + 1);
141
142                 // Delete first and last characters of value: { and }
143
value = value.substring(1);
144                 value = value.substring(0, value.length() - 1);
145
146                 addStaticAttribute(name, value);
147             }
148         }
149     }
150
151     /**
152      * Set static attributes for this view from a
153      * <code>java.util.Properties</code> object.
154      * <p>This is the most convenient way to set static attributes. Note that
155      * static attributes can be overridden by dynamic attributes, if a value
156      * with the same name is included in the model.
157      * <p>Can be populated with a String "value" (parsed via PropertiesEditor)
158      * or a "props" element in XML bean definitions.
159      * @see org.springframework.beans.propertyeditors.PropertiesEditor
160      */

161     public void setAttributes(Properties JavaDoc attributes) {
162         CollectionUtils.mergePropertiesIntoMap(attributes, this.staticAttributes);
163     }
164
165     /**
166      * Set static attributes for this view from a Map. This allows to set
167      * any kind of attribute values, for example bean references.
168      * <p>Can be populated with a "map" or "props" element in XML bean definitions.
169      * @param attributes Map with name Strings as keys and attribute objects as values
170      */

171     public void setAttributesMap(Map JavaDoc attributes) {
172         if (attributes != null) {
173             Iterator JavaDoc it = attributes.entrySet().iterator();
174             while (it.hasNext()) {
175                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
176                 Object JavaDoc key = entry.getKey();
177                 if (!(key instanceof String JavaDoc)) {
178                     throw new IllegalArgumentException JavaDoc(
179                             "Invalid attribute key [" + key + "]: only Strings allowed");
180                 }
181                 addStaticAttribute((String JavaDoc) key, entry.getValue());
182             }
183         }
184     }
185
186     /**
187      * Allow Map access to the static attributes of this view,
188      * with the option to add or override specific entries.
189      * <p>Useful for specifying entries directly, for example via
190      * "attributesMap[myKey]". This is particularly useful for
191      * adding or overriding entries in child view definitions.
192      */

193     public Map JavaDoc getAttributesMap() {
194         return this.staticAttributes;
195     }
196
197     /**
198      * Add static data to this view, exposed in each view.
199      * <p>Must be invoked before any calls to <code>render</code>.
200      * @param name the name of the attribute to expose
201      * @param value the attribute value to expose
202      * @see #render
203      */

204     public void addStaticAttribute(String JavaDoc name, Object JavaDoc value) {
205         this.staticAttributes.put(name, value);
206         if (logger.isDebugEnabled()) {
207             logger.debug("Set static attribute with name '" + name + "' and value [" + value +
208                     "] on view with name '" + getBeanName() + "'");
209         }
210     }
211
212     /**
213      * Return the static attributes for this view. Handy for testing.
214      * <p>Returns an unmodifiable Map, as this is not intended for
215      * manipulating the Map but rather just for checking the contents.
216      * @return the static attributes in this view
217      */

218     public Map JavaDoc getStaticAttributes() {
219         return Collections.unmodifiableMap(this.staticAttributes);
220     }
221
222
223     /**
224      * Prepares the view given the specified model, merging it with static
225      * attributes and a RequestContext attribute, if necessary.
226      * Delegates to renderMergedOutputModel for the actual rendering.
227      * @see #renderMergedOutputModel
228      */

229     public void render(Map JavaDoc model, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
230         if (logger.isDebugEnabled()) {
231             logger.debug("Rendering view with name '" + this.beanName + "' with model " + model +
232                 " and static attributes " + this.staticAttributes);
233         }
234
235         // Consolidate static and dynamic model attributes.
236
Map JavaDoc mergedModel = new HashMap JavaDoc(this.staticAttributes.size() + (model != null ? model.size() : 0));
237         mergedModel.putAll(this.staticAttributes);
238         if (model != null) {
239             mergedModel.putAll(model);
240         }
241
242         // Expose RequestContext?
243
if (this.requestContextAttribute != null) {
244             mergedModel.put(this.requestContextAttribute, createRequestContext(request, mergedModel));
245         }
246
247         renderMergedOutputModel(mergedModel, request, response);
248     }
249
250     /**
251      * Create a RequestContext to expose under the specified attribute name.
252      * <p>Default implementation creates a standard RequestContext instance for the
253      * given request and model. Can be overridden in subclasses for custom instances.
254      * @param request current HTTP request
255      * @param model combined output Map (never <code>null</code>),
256      * with dynamic values taking precedence over static attributes
257      * @return the RequestContext instance
258      * @see #setRequestContextAttribute
259      * @see org.springframework.web.servlet.support.RequestContext
260      */

261     protected RequestContext createRequestContext(HttpServletRequest JavaDoc request, Map JavaDoc model) {
262         return new RequestContext(request, model);
263     }
264
265     /**
266      * Subclasses must implement this method to actually render the view.
267      * <p>The first step will be preparing the request: In the JSP case,
268      * this would mean setting model objects as request attributes.
269      * The second step will be the actual rendering of the view,
270      * for example including the JSP via a RequestDispatcher.
271      * @param model combined output Map (never <code>null</code>),
272      * with dynamic values taking precedence over static attributes
273      * @param request current HTTP request
274      * @param response current HTTP response
275      * @throws Exception if rendering failed
276      */

277     protected abstract void renderMergedOutputModel(
278             Map JavaDoc model, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc;
279
280
281     /**
282      * Expose the model objects in the given map as request attributes.
283      * Names will be taken from the model Map.
284      * This method is suitable for all resources reachable by {@link javax.servlet.RequestDispatcher}.
285      * @param model Map of model objects to expose
286      * @param request current HTTP request
287      */

288     protected void exposeModelAsRequestAttributes(Map JavaDoc model, HttpServletRequest JavaDoc request) throws Exception JavaDoc {
289         Iterator JavaDoc it = model.entrySet().iterator();
290         while (it.hasNext()) {
291             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
292             if (!(entry.getKey() instanceof String JavaDoc)) {
293                 throw new IllegalArgumentException JavaDoc(
294                         "Invalid key [" + entry.getKey() + "] in model Map: only Strings allowed as model keys");
295             }
296             String JavaDoc modelName = (String JavaDoc) entry.getKey();
297             Object JavaDoc modelValue = entry.getValue();
298             if (modelValue != null) {
299                 request.setAttribute(modelName, modelValue);
300                 if (logger.isDebugEnabled()) {
301                     logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
302                             "] to request in view with name '" + getBeanName() + "'");
303                 }
304             }
305             else {
306                 request.removeAttribute(modelName);
307                 if (logger.isDebugEnabled()) {
308                     logger.debug("Removed model object '" + modelName +
309                             "' from request in view with name '" + getBeanName() + "'");
310                 }
311             }
312         }
313     }
314
315
316     public String JavaDoc toString() {
317         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(getClass().getName());
318         if (getBeanName() != null) {
319             sb.append(": name '").append(getBeanName()).append("'");
320         }
321         else {
322             sb.append(": unnamed");
323         }
324         return sb.toString();
325     }
326
327 }
328
Popular Tags