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.portlet;
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 DispatcherPortlet. 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 Juergen Hoeller
036: * @since 2.0
037: * @see org.springframework.web.portlet.DispatcherPortlet
038: * @see org.springframework.web.servlet.ViewResolver
039: * @see org.springframework.web.portlet.HandlerAdapter
040: * @see org.springframework.web.portlet.mvc.Controller
041: */
042: public class ModelAndView {
043:
044: /** View instance or view name String */
045: private Object view;
046:
047: /** Model Map */
048: private ModelMap model;
049:
050: /**
051: * Indicates whether or not this instance has been cleared with a call to {@link #clear()}.
052: */
053: private boolean cleared;
054:
055: /**
056: * Default constructor for bean-style usage: populating bean
057: * properties instead of passing in constructor arguments.
058: * @see #setView(Object)
059: * @see #setViewName(String)
060: */
061: public ModelAndView() {
062: }
063:
064: /**
065: * Convenient constructor when there is no model data to expose.
066: * Can also be used in conjunction with <code>addObject</code>.
067: * @param viewName name of the View to render, to be resolved
068: * by the DispatcherPortlet's ViewResolver
069: * @see #addObject
070: */
071: public ModelAndView(String viewName) {
072: this .view = viewName;
073: }
074:
075: /**
076: * Convenient constructor when there is no model data to expose.
077: * Can also be used in conjunction with <code>addObject</code>.
078: * @param view View object to render (usually a Servlet MVC View object)
079: * @see #addObject
080: */
081: public ModelAndView(Object view) {
082: this .view = view;
083: }
084:
085: /**
086: * Create a new ModelAndView given a view name and a model.
087: * @param viewName name of the View to render, to be resolved
088: * by the DispatcherPortlet's ViewResolver
089: * @param model Map of model names (Strings) to model objects
090: * (Objects). Model entries may not be <code>null</code>, but the
091: * model Map may be <code>null</code> if there is no model data.
092: */
093: public ModelAndView(String viewName, Map model) {
094: this .view = viewName;
095: if (model != null) {
096: getModelMap().addAllObjects(model);
097: }
098: }
099:
100: /**
101: * Create a new ModelAndView given a View object and a model.
102: * @param view View object to render (usually a Servlet MVC View object)
103: * @param model Map of model names (Strings) to model objects
104: * (Objects). Model entries may not be <code>null</code>, but the
105: * model Map may be <code>null</code> if there is no model data.
106: */
107: public ModelAndView(Object view, Map model) {
108: this .view = view;
109: if (model != null) {
110: getModelMap().addAllObjects(model);
111: }
112: }
113:
114: /**
115: * Convenient constructor to take a single model object.
116: * @param viewName name of the View to render, to be resolved
117: * by the DispatcherPortlet's ViewResolver
118: * @param modelName name of the single entry in the model
119: * @param modelObject the single model object
120: */
121: public ModelAndView(String viewName, String modelName,
122: Object modelObject) {
123: this .view = viewName;
124: addObject(modelName, modelObject);
125: }
126:
127: /**
128: * Convenient constructor to take a single model object.
129: * @param view View object to render (usually a Servlet MVC View object)
130: * @param modelName name of the single entry in the model
131: * @param modelObject the single model object
132: */
133: public ModelAndView(Object view, String modelName,
134: Object modelObject) {
135: this .view = view;
136: addObject(modelName, modelObject);
137: }
138:
139: /**
140: * Set a view name for this ModelAndView, to be resolved by the
141: * DispatcherPortlet via a ViewResolver. Will override any
142: * pre-existing view name or View.
143: */
144: public void setViewName(String viewName) {
145: this .view = viewName;
146: }
147:
148: /**
149: * Return the view name to be resolved by the DispatcherPortlet
150: * via a ViewResolver, or <code>null</code> if we are using a view object.
151: */
152: public String getViewName() {
153: return (this .view instanceof String ? (String) this .view : null);
154: }
155:
156: /**
157: * Set a View object for this ModelAndView. Will override any
158: * pre-existing view name or View.
159: * <p>The given View object will usually be a Servlet MVC View object.
160: * This is nevertheless typed as Object to avoid a Servlet API dependency
161: * in the Portlet ModelAndView class.
162: */
163: public void setView(Object 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 DispatcherPortlet via a ViewResolver.
170: */
171: public Object getView() {
172: return (!(this .view instanceof String) ? 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 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: * DispatcherPortlet 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 DispatcherPortlet 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
231: * @param modelObject object to add to the model (never <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>postHandleRender</code> method of a HandlerInterceptor.
256: * @see #isEmpty()
257: * @see HandlerInterceptor#postHandleRender
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:
300: }
|