View Javadoc
1   /*
2    * Copyright 2002-2012 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.Locale;
20  
21  import org.springframework.beans.BeansException;
22  import org.springframework.beans.factory.BeanFactory;
23  import org.springframework.beans.factory.DisposableBean;
24  import org.springframework.beans.factory.InitializingBean;
25  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
26  import org.springframework.beans.factory.xml.ResourceEntityResolver;
27  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
28  import org.springframework.context.ConfigurableApplicationContext;
29  import org.springframework.core.Ordered;
30  import org.springframework.core.io.Resource;
31  import org.springframework.web.context.support.GenericWebApplicationContext;
32  import org.springframework.web.servlet.View;
33  
34  /**
35   * A {@link org.springframework.web.servlet.ViewResolver} implementation that uses
36   * bean definitions in a dedicated XML file for view definitions, specified by
37   * resource location. The file will typically be located in the WEB-INF directory;
38   * the default is "/WEB-INF/views.xml".
39   *
40   * <p>This {@code ViewResolver} does not support internationalization at the level
41   * of its definition resources. Consider {@link ResourceBundleViewResolver} if you
42   * need to apply different view resources per locale.
43   *
44   * <p>Note: This {@code ViewResolver} implements the {@link Ordered} interface
45   * in order to allow for flexible participation in {@code ViewResolver} chaining.
46   * For example, some special views could be defined via this {@code ViewResolver}
47   * (giving it 0 as "order" value), while all remaining views could be resolved by
48   * a {@link UrlBasedViewResolver}.
49   *
50   * @author Juergen Hoeller
51   * @since 18.06.2003
52   * @see org.springframework.context.ApplicationContext#getResource
53   * @see ResourceBundleViewResolver
54   * @see UrlBasedViewResolver
55   */
56  public class XmlViewResolver extends AbstractCachingViewResolver
57  		implements Ordered, InitializingBean, DisposableBean {
58  
59  	/** Default if no other location is supplied */
60  	public final static String DEFAULT_LOCATION = "/WEB-INF/views.xml";
61  
62  
63  	private int order = Integer.MAX_VALUE;  // default: same as non-Ordered
64  
65  	private Resource location;
66  
67  	private ConfigurableApplicationContext cachedFactory;
68  
69  
70  	public void setOrder(int order) {
71  		this.order = order;
72  	}
73  
74  	@Override
75  	public int getOrder() {
76  		return this.order;
77  	}
78  
79  	/**
80  	 * Set the location of the XML file that defines the view beans.
81  	 * <p>The default is "/WEB-INF/views.xml".
82  	 * @param location the location of the XML file.
83  	 */
84  	public void setLocation(Resource location) {
85  		this.location = location;
86  	}
87  
88  	/**
89  	 * Pre-initialize the factory from the XML file.
90  	 * Only effective if caching is enabled.
91  	 */
92  	@Override
93  	public void afterPropertiesSet() throws BeansException {
94  		if (isCache()) {
95  			initFactory();
96  		}
97  	}
98  
99  
100 	/**
101 	 * This implementation returns just the view name,
102 	 * as XmlViewResolver doesn't support localized resolution.
103 	 */
104 	@Override
105 	protected Object getCacheKey(String viewName, Locale locale) {
106 		return viewName;
107 	}
108 
109 	@Override
110 	protected View loadView(String viewName, Locale locale) throws BeansException {
111 		BeanFactory factory = initFactory();
112 		try {
113 			return factory.getBean(viewName, View.class);
114 		}
115 		catch (NoSuchBeanDefinitionException ex) {
116 			// Allow for ViewResolver chaining...
117 			return null;
118 		}
119 	}
120 
121 	/**
122 	 * Initialize the view bean factory from the XML file.
123 	 * Synchronized because of access by parallel threads.
124 	 * @throws BeansException in case of initialization errors
125 	 */
126 	protected synchronized BeanFactory initFactory() throws BeansException {
127 		if (this.cachedFactory != null) {
128 			return this.cachedFactory;
129 		}
130 
131 		Resource actualLocation = this.location;
132 		if (actualLocation == null) {
133 			actualLocation = getApplicationContext().getResource(DEFAULT_LOCATION);
134 		}
135 
136 		// Create child ApplicationContext for views.
137 		GenericWebApplicationContext factory = new GenericWebApplicationContext();
138 		factory.setParent(getApplicationContext());
139 		factory.setServletContext(getServletContext());
140 
141 		// Load XML resource with context-aware entity resolver.
142 		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
143 		reader.setEnvironment(getApplicationContext().getEnvironment());
144 		reader.setEntityResolver(new ResourceEntityResolver(getApplicationContext()));
145 		reader.loadBeanDefinitions(actualLocation);
146 
147 		factory.refresh();
148 
149 		if (isCache()) {
150 			this.cachedFactory = factory;
151 		}
152 		return factory;
153 	}
154 
155 
156 	/**
157 	 * Close the view bean factory on context shutdown.
158 	 */
159 	@Override
160 	public void destroy() throws BeansException {
161 		if (this.cachedFactory != null) {
162 			this.cachedFactory.close();
163 		}
164 	}
165 
166 }