001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.servlet;
018:
019: import java.util.Map;
020:
021: import org.springframework.ui.ModelMap;
022:
023: /**
024: * Holder for both Model and View in the web MVC framework.
025: * Note that these are entirely distinct. This class merely holds
026: * both to make it possible for a controller to return both model
027: * and view in a single return value.
028: *
029: * <p>Represents a model and view returned by a handler, to be resolved
030: * by a DispatcherServlet. The view can take the form of a String
031: * view name which will need to be resolved by a ViewResolver object;
032: * alternatively a View object can be specified directly. The model
033: * is a Map, allowing the use of multiple objects keyed by name.
034: *
035: * @author Rod Johnson
036: * @author Juergen Hoeller
037: * @author Rob Harrop
038: * @see DispatcherServlet
039: * @see ViewResolver
040: * @see HandlerAdapter#handle
041: * @see org.springframework.web.servlet.mvc.Controller#handleRequest
042: */
043: public class ModelAndView {
044:
045: /** View instance or view name String */
046: private Object view;
047:
048: /** Model Map */
049: private ModelMap model;
050:
051: /**
052: * Indicates whether or not this instance has been cleared with a call to {@link #clear()}.
053: */
054: private boolean cleared;
055:
056: /**
057: * Default constructor for bean-style usage: populating bean
058: * properties instead of passing in constructor arguments.
059: * @see #setView(View)
060: * @see #setViewName(String)
061: */
062: public ModelAndView() {
063: }
064:
065: /**
066: * Convenient constructor when there is no model data to expose.
067: * Can also be used in conjunction with <code>addObject</code>.
068: * @param viewName name of the View to render, to be resolved
069: * by the DispatcherServlet's ViewResolver
070: * @see #addObject
071: */
072: public ModelAndView(String viewName) {
073: this .view = viewName;
074: }
075:
076: /**
077: * Convenient constructor when there is no model data to expose.
078: * Can also be used in conjunction with <code>addObject</code>.
079: * @param view View object to render
080: * @see #addObject
081: */
082: public ModelAndView(View view) {
083: this .view = view;
084: }
085:
086: /**
087: * Creates new ModelAndView given a view name and a model.
088: * @param viewName name of the View to render, to be resolved
089: * by the DispatcherServlet's ViewResolver
090: * @param model Map of model names (Strings) to model objects
091: * (Objects). Model entries may not be <code>null</code>, but the
092: * model Map may be <code>null</code> if there is no model data.
093: */
094: public ModelAndView(String viewName, Map model) {
095: this .view = viewName;
096: if (model != null) {
097: getModelMap().addAllObjects(model);
098: }
099: }
100:
101: /**
102: * Creates new ModelAndView given a View object and a model.
103: * <emphasis>Note: the supplied model data is copied into the internal
104: * storage of this class. You should not consider to modify the supplied
105: * Map after supplying it to this class</emphasis>
106: * @param view View object to render
107: * @param model Map of model names (Strings) to model objects
108: * (Objects). Model entries may not be <code>null</code>, but the
109: * model Map may be <code>null</code> if there is no model data.
110: */
111: public ModelAndView(View view, Map model) {
112: this .view = view;
113: if (model != null) {
114: getModelMap().addAllObjects(model);
115: }
116: }
117:
118: /**
119: * Convenient constructor to take a single model object.
120: * @param viewName name of the View to render, to be resolved
121: * by the DispatcherServlet's ViewResolver
122: * @param modelName name of the single entry in the model
123: * @param modelObject the single model object
124: */
125: public ModelAndView(String viewName, String modelName,
126: Object modelObject) {
127: this .view = viewName;
128: addObject(modelName, modelObject);
129: }
130:
131: /**
132: * Convenient constructor to take a single model object.
133: * @param view View object to render
134: * @param modelName name of the single entry in the model
135: * @param modelObject the single model object
136: */
137: public ModelAndView(View view, String modelName, Object modelObject) {
138: this .view = view;
139: addObject(modelName, modelObject);
140: }
141:
142: /**
143: * Set a view name for this ModelAndView, to be resolved by the
144: * DispatcherServlet via a ViewResolver. Will override any
145: * pre-existing view name or View.
146: */
147: public void setViewName(String viewName) {
148: this .view = viewName;
149: }
150:
151: /**
152: * Return the view name to be resolved by the DispatcherServlet
153: * via a ViewResolver, or <code>null</code> if we are using a View object.
154: */
155: public String getViewName() {
156: return (this .view instanceof String ? (String) this .view : null);
157: }
158:
159: /**
160: * Set a View object for this ModelAndView. Will override any
161: * pre-existing view name or View.
162: */
163: public void setView(View view) {
164: this .view = view;
165: }
166:
167: /**
168: * Return the View object, or <code>null</code> if we are using a view name
169: * to be resolved by the DispatcherServlet via a ViewResolver.
170: */
171: public View getView() {
172: return (this .view instanceof View ? (View) this .view : null);
173: }
174:
175: /**
176: * Indicate whether or not this <code>ModelAndView</code> has a view, either
177: * as a view name or as a direct {@link View} instance.
178: */
179: public boolean hasView() {
180: return (this .view != null);
181: }
182:
183: /**
184: * Return whether we use a view reference, i.e. <code>true</code>
185: * if the view has been specified via a name to be resolved by the
186: * DispatcherServlet via a ViewResolver.
187: */
188: public boolean isReference() {
189: return (this .view instanceof String);
190: }
191:
192: /**
193: * Return the model map. May return null.
194: * Called by DispatcherServlet for evaluation of the model.
195: */
196: protected Map getModelInternal() {
197: return this .model;
198: }
199:
200: /**
201: * Return the underlying <code>ModelMap</code> instance (never <code>null</code>).
202: */
203: public ModelMap getModelMap() {
204: if (this .model == null) {
205: this .model = new ModelMap();
206: }
207: return this .model;
208: }
209:
210: /**
211: * Return the model map. Never returns <code>null</code>.
212: * To be called by application code for modifying the model.
213: */
214: public Map getModel() {
215: return getModelMap();
216: }
217:
218: /**
219: * Add an object to the model using parameter name generation.
220: * @param modelObject the object to add to the model (never <code>null</code>)
221: * @see ModelMap#addObject(Object)
222: */
223: public ModelAndView addObject(Object modelObject) {
224: getModelMap().addObject(modelObject);
225: return this ;
226: }
227:
228: /**
229: * Add an object to the model.
230: * @param modelName name of the object to add to the model (never <code>null</code>)
231: * @param modelObject object to add to the model (can be <code>null</code>)
232: * @return this ModelAndView, convenient to allow usages like
233: * return modelAndView.addObject("foo", bar);
234: */
235: public ModelAndView addObject(String modelName, Object modelObject) {
236: getModelMap().addObject(modelName, modelObject);
237: return this ;
238: }
239:
240: /**
241: * Add all entries contained in the provided map to the model.
242: * @param modelMap a map of modelName -> modelObject pairs
243: * @return this ModelAndView, convenient to allow usages like
244: * return modelAndView.addAllObjects(myModelMap);
245: */
246: public ModelAndView addAllObjects(Map modelMap) {
247: getModelMap().addAllObjects(modelMap);
248: return this ;
249: }
250:
251: /**
252: * Clear the state of this ModelAndView object.
253: * The object will be empty afterwards.
254: * <p>Can be used to suppress rendering of a given ModelAndView object
255: * in the <code>postHandle</code> method of a HandlerInterceptor.
256: * @see #isEmpty()
257: * @see HandlerInterceptor#postHandle
258: */
259: public void clear() {
260: this .view = null;
261: this .model = null;
262: this .cleared = true;
263: }
264:
265: /**
266: * Return whether this ModelAndView object is empty
267: * i.e. whether it does not hold any view and does not contain a model.
268: */
269: public boolean isEmpty() {
270: return (this .view == null && this .model == null);
271: }
272:
273: /**
274: * Return whether this ModelAndView object is empty as a result of a call to {@link #clear}
275: * i.e. whether it does not hold any view and does not contain a model.
276: * Returns <code>false</code> if any additional state was added to the instance
277: * <strong>after</strong> the call to {@link #clear}.
278: * @see #clear()
279: */
280: public boolean wasCleared() {
281: return (this .cleared && isEmpty());
282: }
283:
284: /**
285: * Return diagnostic information about this model and view.
286: */
287: public String toString() {
288: StringBuffer buf = new StringBuffer("ModelAndView: ");
289: if (isReference()) {
290: buf.append("reference to view with name '").append(
291: this .view).append("'");
292: } else {
293: buf.append("materialized View is [").append(this .view)
294: .append(']');
295: }
296: buf.append("; model is ").append(this.model);
297: return buf.toString();
298: }
299: }
|