001/* 002 * Copyright 2002-2017 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 * https://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 017package org.springframework.web.servlet.view.tiles3; 018 019import java.util.Locale; 020import java.util.Map; 021 022import javax.servlet.ServletContext; 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025 026import org.apache.tiles.TilesContainer; 027import org.apache.tiles.access.TilesAccess; 028import org.apache.tiles.renderer.DefinitionRenderer; 029import org.apache.tiles.request.AbstractRequest; 030import org.apache.tiles.request.ApplicationContext; 031import org.apache.tiles.request.Request; 032import org.apache.tiles.request.render.Renderer; 033import org.apache.tiles.request.servlet.ServletRequest; 034import org.apache.tiles.request.servlet.ServletUtil; 035 036import org.springframework.lang.Nullable; 037import org.springframework.util.Assert; 038import org.springframework.web.context.request.RequestAttributes; 039import org.springframework.web.context.request.RequestContextHolder; 040import org.springframework.web.context.request.ServletRequestAttributes; 041import org.springframework.web.servlet.support.JstlUtils; 042import org.springframework.web.servlet.support.RequestContext; 043import org.springframework.web.servlet.support.RequestContextUtils; 044import org.springframework.web.servlet.view.AbstractUrlBasedView; 045 046/** 047 * {@link org.springframework.web.servlet.View} implementation that renders 048 * through the Tiles Request API. The "url" property is interpreted as name of a 049 * Tiles definition. 050 * 051 * @author Nicolas Le Bas 052 * @author mick semb wever 053 * @author Rossen Stoyanchev 054 * @author Sebastien Deleuze 055 * @since 3.2 056 */ 057public class TilesView extends AbstractUrlBasedView { 058 059 @Nullable 060 private Renderer renderer; 061 062 private boolean exposeJstlAttributes = true; 063 064 private boolean alwaysInclude = false; 065 066 @Nullable 067 private ApplicationContext applicationContext; 068 069 070 /** 071 * Set the {@link Renderer} to use. 072 * If not set, by default {@link DefinitionRenderer} is used. 073 */ 074 public void setRenderer(Renderer renderer) { 075 this.renderer = renderer; 076 } 077 078 /** 079 * Whether to expose JSTL attributes. By default set to {@code true}. 080 * @see JstlUtils#exposeLocalizationContext(RequestContext) 081 */ 082 protected void setExposeJstlAttributes(boolean exposeJstlAttributes) { 083 this.exposeJstlAttributes = exposeJstlAttributes; 084 } 085 086 /** 087 * Specify whether to always include the view rather than forward to it. 088 * <p>Default is "false". Switch this flag on to enforce the use of a 089 * Servlet include, even if a forward would be possible. 090 * @since 4.1.2 091 * @see TilesViewResolver#setAlwaysInclude 092 */ 093 public void setAlwaysInclude(boolean alwaysInclude) { 094 this.alwaysInclude = alwaysInclude; 095 } 096 097 @Override 098 public void afterPropertiesSet() throws Exception { 099 super.afterPropertiesSet(); 100 101 ServletContext servletContext = getServletContext(); 102 Assert.state(servletContext != null, "No ServletContext"); 103 this.applicationContext = ServletUtil.getApplicationContext(servletContext); 104 105 if (this.renderer == null) { 106 TilesContainer container = TilesAccess.getContainer(this.applicationContext); 107 this.renderer = new DefinitionRenderer(container); 108 } 109 } 110 111 112 @Override 113 public boolean checkResource(final Locale locale) throws Exception { 114 Assert.state(this.renderer != null, "No Renderer set"); 115 116 HttpServletRequest servletRequest = null; 117 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); 118 if (requestAttributes instanceof ServletRequestAttributes) { 119 servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest(); 120 } 121 122 Request request = new ServletRequest(this.applicationContext, servletRequest, null) { 123 @Override 124 public Locale getRequestLocale() { 125 return locale; 126 } 127 }; 128 129 return this.renderer.isRenderable(getUrl(), request); 130 } 131 132 @Override 133 protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, 134 HttpServletResponse response) throws Exception { 135 136 Assert.state(this.renderer != null, "No Renderer set"); 137 138 exposeModelAsRequestAttributes(model, request); 139 if (this.exposeJstlAttributes) { 140 JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext())); 141 } 142 if (this.alwaysInclude) { 143 request.setAttribute(AbstractRequest.FORCE_INCLUDE_ATTRIBUTE_NAME, true); 144 } 145 146 Request tilesRequest = createTilesRequest(request, response); 147 this.renderer.render(getUrl(), tilesRequest); 148 } 149 150 /** 151 * Create a Tiles {@link Request}. 152 * <p>This implementation creates a {@link ServletRequest}. 153 * @param request the current request 154 * @param response the current response 155 * @return the Tiles request 156 */ 157 protected Request createTilesRequest(final HttpServletRequest request, HttpServletResponse response) { 158 return new ServletRequest(this.applicationContext, request, response) { 159 @Override 160 public Locale getRequestLocale() { 161 return RequestContextUtils.getLocale(request); 162 } 163 }; 164 } 165 166}