001/* 002 * Copyright 2002-2018 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.tags; 018 019import javax.servlet.jsp.JspException; 020import javax.servlet.jsp.JspTagException; 021import javax.servlet.jsp.tagext.TagSupport; 022import javax.servlet.jsp.tagext.TryCatchFinally; 023 024import org.apache.commons.logging.Log; 025import org.apache.commons.logging.LogFactory; 026 027import org.springframework.lang.Nullable; 028import org.springframework.util.Assert; 029import org.springframework.web.servlet.support.JspAwareRequestContext; 030import org.springframework.web.servlet.support.RequestContext; 031 032/** 033 * Superclass for all tags that require a {@link RequestContext}. 034 * 035 * <p>The {@code RequestContext} instance provides easy access 036 * to current state like the 037 * {@link org.springframework.web.context.WebApplicationContext}, 038 * the {@link java.util.Locale}, the 039 * {@link org.springframework.ui.context.Theme}, etc. 040 * 041 * <p>Mainly intended for 042 * {@link org.springframework.web.servlet.DispatcherServlet} requests; 043 * will use fallbacks when used outside {@code DispatcherServlet}. 044 * 045 * @author Rod Johnson 046 * @author Juergen Hoeller 047 * @see org.springframework.web.servlet.support.RequestContext 048 * @see org.springframework.web.servlet.DispatcherServlet 049 */ 050@SuppressWarnings("serial") 051public abstract class RequestContextAwareTag extends TagSupport implements TryCatchFinally { 052 053 /** 054 * {@link javax.servlet.jsp.PageContext} attribute for the 055 * page-level {@link RequestContext} instance. 056 */ 057 public static final String REQUEST_CONTEXT_PAGE_ATTRIBUTE = 058 "org.springframework.web.servlet.tags.REQUEST_CONTEXT"; 059 060 061 /** Logger available to subclasses. */ 062 protected final Log logger = LogFactory.getLog(getClass()); 063 064 065 @Nullable 066 private RequestContext requestContext; 067 068 069 /** 070 * Create and expose the current RequestContext. 071 * Delegates to {@link #doStartTagInternal()} for actual work. 072 * @see #REQUEST_CONTEXT_PAGE_ATTRIBUTE 073 * @see org.springframework.web.servlet.support.JspAwareRequestContext 074 */ 075 @Override 076 public final int doStartTag() throws JspException { 077 try { 078 this.requestContext = (RequestContext) this.pageContext.getAttribute(REQUEST_CONTEXT_PAGE_ATTRIBUTE); 079 if (this.requestContext == null) { 080 this.requestContext = new JspAwareRequestContext(this.pageContext); 081 this.pageContext.setAttribute(REQUEST_CONTEXT_PAGE_ATTRIBUTE, this.requestContext); 082 } 083 return doStartTagInternal(); 084 } 085 catch (JspException | RuntimeException ex) { 086 logger.error(ex.getMessage(), ex); 087 throw ex; 088 } 089 catch (Exception ex) { 090 logger.error(ex.getMessage(), ex); 091 throw new JspTagException(ex.getMessage()); 092 } 093 } 094 095 /** 096 * Return the current RequestContext. 097 */ 098 protected final RequestContext getRequestContext() { 099 Assert.state(this.requestContext != null, "No current RequestContext"); 100 return this.requestContext; 101 } 102 103 /** 104 * Called by doStartTag to perform the actual work. 105 * @return same as TagSupport.doStartTag 106 * @throws Exception any exception, any checked one other than 107 * a JspException gets wrapped in a JspException by doStartTag 108 * @see javax.servlet.jsp.tagext.TagSupport#doStartTag 109 */ 110 protected abstract int doStartTagInternal() throws Exception; 111 112 113 @Override 114 public void doCatch(Throwable throwable) throws Throwable { 115 throw throwable; 116 } 117 118 @Override 119 public void doFinally() { 120 this.requestContext = null; 121 } 122 123}