Java tutorial
/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.taglib; import ch.entwine.weblounge.common.impl.request.RequestUtils; import ch.entwine.weblounge.common.impl.request.WebloungeRequestImpl; import ch.entwine.weblounge.common.impl.request.WebloungeResponseImpl; import ch.entwine.weblounge.common.request.WebloungeRequest; import ch.entwine.weblounge.common.request.WebloungeResponse; import ch.entwine.weblounge.common.site.Environment; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.TryCatchFinally; /** * Base class for weblounge tags which implements most of the standard * <code>HTML 4</code> tag attributes. */ public class WebloungeTag extends BodyTagSupport implements TryCatchFinally { /** Serial version id */ private static final long serialVersionUID = 1754816467985401658L; /** The logging facility */ private static final Logger logger = LoggerFactory.getLogger(WebloungeTag.class); /** Css class attribute */ protected String css = null; /** Css style attribute */ protected String style = null; /** lang attribute */ protected String lang = null; /** dir (reading direction) attribute */ protected String dir = null; /** Html title */ protected String title = null; /** Html name */ protected String name = null; /** OnClick Event */ protected String onclick = null; /** OnDblClick Event */ protected String ondblclick = null; /** OnMouseDown Event */ protected String onmousedown = null; /** OnMouseUp Event */ protected String onmouseup = null; /** OnMouseMove Event */ protected String onmousemove = null; /** OnMouseOver Event */ protected String onmouseover = null; /** OnMouseOut Event */ protected String onmouseout = null; /** OnKeyDown Event */ protected String onkeydown = null; /** OnKeyPress Event */ protected String onkeypress = null; /** OnKeyUp Event */ protected String onkeyup = null; /** The weblounge request */ protected WebloungeRequest request = null; /** The weblounge response */ protected WebloungeResponse response = null; /** The stash */ protected Map<String, Object> stash = new HashMap<String, Object>(); /** The attributes that were added by this tag instance */ protected List<String> attributes = new ArrayList<String>(); /** * Resets the properties of this tag to default values. This method is called * between <strong>every</strong> request. * <p> * If you override this method make sure you call <code>super.reset()</code> */ protected void reset() { css = null; style = null; lang = null; dir = null; title = null; name = null; onclick = null; ondblclick = null; onmousedown = null; onmouseup = null; onmousemove = null; onmouseover = null; onmouseout = null; onkeydown = null; onkeypress = null; onkeyup = null; request = null; response = null; stash.clear(); attributes.clear(); } /** * Sets the standard <code>HTML</code> <code>class</code> attribute. * * @param c * the css class */ public void setClass(String c) { css = c; } /** * Sets the standard <code>HTML</code> <code>class</code> attribute. * * @param c * the css class */ public void setCss(String c) { css = c; } /** * Adds the class to the css class attribute. * * @param c * the class name */ protected void addCssClass(String c) { if (StringUtils.trimToNull(c) == null) return; if (css == null) css = c; else if (!css.startsWith(c + " ") && !css.endsWith(" " + c) && !css.contains(" " + c + " ")) css += " " + c; } /** * Sets the standard <code>HTML</code> <code>style</code> attribute. * * @param style * the html style */ public void setStyle(String style) { this.style = style; } /** * Sets the standard <code>HTML</code> <code>lang</code> attribute. * * @param lang * the language */ public void setLang(String lang) { this.lang = lang; } /** * Sets the standard <code>HTML</code> <code>dir</code> attribute. * * @param dir * the reading direction */ public void setDir(String dir) { this.dir = dir; } /** * Sets the standard <code>HTML</code> <code>title</code> attribute which is * used to display tooltips. * * @param title * the html title */ public void setTitle(String title) { this.title = title; } /** * Sets the standard <code>HTML</code> <code>name</code> attribute. * * @param name * the html name */ public void setName(String name) { this.name = name; } /** * Sets the standard <code>HTML</code> event <code>onclick</code> event * handler. * * @param handler * the event handler code */ public void setOnclick(String handler) { this.onclick = handler; } /** * Sets the standard <code>HTML</code> event <code>onclick</code> event * handler. * * @param handler * the event handler code */ public void setOnClick(String handler) { this.onclick = handler; } /** * Sets the standard <code>HTML</code> event <code>ondblclick</code> event * handler. * * @param handler * the event handler code */ public void setOndblclick(String handler) { this.ondblclick = handler; } /** * Sets the standard <code>HTML</code> event <code>ondblclick</code> event * handler. * * @param handler * the event handler code */ public void setOnDblClick(String handler) { this.ondblclick = handler; } /** * Sets the standard <code>HTML</code> event <code>onmousedown</code> event * handler. * * @param handler * the event handler code */ public void setOnmousedown(String handler) { this.onmousedown = handler; } /** * Sets the standard <code>HTML</code> event <code>onmousedown</code> event * handler. * * @param handler * the event handler code */ public void setOnMouseDown(String handler) { this.onmousedown = handler; } /** * Sets the standard <code>HTML</code> event <code>onmousemove</code> event * handler. * * @param handler * the event handler code */ public void setOnmousemove(String handler) { this.onmousemove = handler; } /** * Sets the standard <code>HTML</code> event <code>onmousemove</code> event * handler. * * @param handler * the event handler code */ public void setOnMouseMove(String handler) { this.onmousemove = handler; } /** * Sets the standard <code>HTML</code> event <code>onmouseout</code> event * handler. * * @param handler * the event handler code */ public void setOnmouseout(String handler) { this.onmouseout = handler; } /** * Sets the standard <code>HTML</code> event <code>onmouseout</code> event * handler. * * @param handler * the event handler code */ public void setOnMouseOut(String handler) { this.onmouseout = handler; } /** * Sets the standard <code>HTML</code> event <code>onmouseover</code> event * handler. * * @param handler * the event handler code */ public void setOnmouseover(String handler) { this.onmouseover = handler; } /** * Sets the standard <code>HTML</code> event <code>onmouseover</code> event * handler. * * @param handler * the event handler code */ public void setOnMouseOver(String handler) { this.onmouseover = handler; } /** * Sets the standard <code>HTML</code> event <code>onmouseup</code> event * handler. * * @param handler * the event handler code */ public void setOnmouseup(String handler) { this.onmouseup = handler; } /** * Sets the standard <code>HTML</code> event <code>onmouseup</code> event * handler. * * @param handler * the event handler code */ public void setOnMouseUp(String handler) { this.onmouseup = handler; } /** * Sets the standard <code>HTML</code> event <code>onkeydown</code> event * handler. * * @param handler * the event handler code */ public void setOnkeydown(String handler) { this.onkeydown = handler; } /** * Sets the standard <code>HTML</code> event <code>onkeydown</code> event * handler. * * @param handler * the event handler code */ public void setOnKeyDown(String handler) { this.onkeydown = handler; } /** * Sets the standard <code>HTML</code> event <code>onkeypress</code> event * handler. * * @param handler * the event handler code */ public void setOnkeypress(String handler) { this.onkeypress = handler; } /** * Sets the standard <code>HTML</code> event <code>onkeypress</code> event * handler. * * @param handler * the event handler code */ public void setOnKeyPress(String handler) { this.onkeypress = handler; } /** * Sets the standard <code>HTML</code> event <code>onkeyup</code> event * handler. * * @param handler * the event handler code */ public void setOnkeyup(String handler) { this.onkeyup = handler; } /** * Sets the standard <code>HTML</code> event <code>onkeyup</code> event * handler. * * @param handler * the event handler code */ public void setOnKeyUp(String handler) { this.onkeyup = handler; } /** * Returns the weblounge request. This method searches the probably wrapped * request hierarchy for the original weblounge request. * * @return the weblounge request */ public WebloungeRequest getRequest() { return unwrapRequest(pageContext.getRequest()); } /** * Returns the weblounge response. This method searches the probably wrapped * response hierarchy for the original weblounge response. * * @return the weblounge response */ public WebloungeResponse getResponse() { return unwrapResponse(pageContext.getResponse()); } /** * Returns the standard attributes ready to inserted in an HTML tag. * * @return the standard HTML attributes */ protected Map<String, String> getStandardAttributes() { Map<String, String> attributes = new HashMap<String, String>(); if (css != null) attributes.put("class", css); if (getId() != null) attributes.put("id", getId()); if (name != null) attributes.put("name", name); if (style != null) attributes.put("style", style); if (lang != null) attributes.put("lang", lang); if (dir != null) attributes.put("dir", dir); if (title != null) attributes.put("title", title); // Mouse events if (onclick != null) attributes.put("onclick", name); if (ondblclick != null) attributes.put("ondblclick", ondblclick); if (onmousedown != null) attributes.put("onmousedown", onmousedown); if (onmousemove != null) attributes.put("onmousemove", onmousemove); if (onmouseout != null) attributes.put("onmouseout", onmouseout); if (onmouseover != null) attributes.put("onmouseover", onmouseover); if (onmouseup != null) attributes.put("onmouseup", onmouseup); // Keyboard events if (onkeydown != null) attributes.put("onkeydown", onkeydown); if (onkeypress != null) attributes.put("onkeypress", onkeypress); if (onkeyup != null) attributes.put("onkeyup", onkeyup); return attributes; } /** * Overwritten to extract <code>WebloungeRequest</code> and * <code>WebloungeResponse</code>. * * @see javax.servlet.jsp.tagext.Tag#setPageContext(javax.servlet.jsp.PageContext) */ @Override public void setPageContext(PageContext ctxt) { super.setPageContext(ctxt); request = unwrapRequest(pageContext.getRequest()); response = unwrapResponse(pageContext.getResponse()); } /** * Stores any original value for the given attribute away for later reference. * * @param attribute * the attribute name */ protected void stashAttribute(String attribute) { stashAndSetAttribute(attribute, null); } /** * Sets the attribute in the page context and stores any original value away * for later reference. * * @param attribute * the attribute name * @param value * the value */ protected void stashAndSetAttribute(String attribute, Object value) { Object existingValue = pageContext.getAttribute(attribute); // If there is a value already, keep it for later reference if (existingValue != null) { String existingType = existingValue.getClass().getName(); logger.debug("Stashing context item '{}' of type {}", attribute, existingType); stash.put(attribute, existingValue); } // Set the attribute if (value != null) { pageContext.setAttribute(attribute, value); } attributes.add(attribute); } /** * Removes the given attribute from the page context and replaces it with a * potentially stashed value. * * @param attribute * the attribute name */ protected void removeAndUnsstashAttribute(String attribute) { Object value = stash.remove(attribute); if (value != null) { String existingType = value.getClass().getName(); logger.debug("Applying stashed page context item '{}' of type {}", attribute, existingType); pageContext.setAttribute(attribute, value); } else { pageContext.removeAttribute(attribute); } attributes.remove(attribute); } /** * Removes all attributes that have been set by the current tag instance from * the page context and replaces them with potentially stashed values. */ protected void removeAndUnstashAttributes() { for (String attribute : attributes) { Object value = stash.remove(attribute); if (value != null) { String existingType = value.getClass().getName(); logger.debug("Applying stashed page context item '{}' of type {}", attribute, existingType); pageContext.setAttribute(attribute, value); } else { pageContext.removeAttribute(attribute); } } attributes.clear(); // Make sure we are not missing out on any stash values for (Map.Entry<String, Object> stashEntry : stash.entrySet()) { String attribute = stashEntry.getKey(); Object value = stashEntry.getValue(); String existingType = value.getClass().getName(); logger.debug("Applying stashed page context item '{}' of type {}", attribute, existingType); pageContext.setAttribute(attribute, value); } stash.clear(); } /** * Returns the map of attributes as a string. If there are no attributes in * the map, an empty string is returned. * * @param attributes * the attributes as a string * @return the attributes ready to be added to a tag */ protected static String attributesToString(Map<String, String> attributes) { if (attributes == null || attributes.size() == 0) return ""; StringBuffer buf = new StringBuffer(); for (Map.Entry<String, String> attribute : attributes.entrySet()) { if (buf.length() > 0) buf.append(" "); buf.append(attribute.getKey()); buf.append("=\""); buf.append(attribute.getValue()); buf.append("\""); } return buf.toString(); } /** * Extract the wrapped <code>WebloungeResponse</code> from a <code> * ServletResponse</code>. * * @param response * the wrapping response * @return the wrapped <code>WebloungeResponse</code> or <code>null</code> if * no such response exists */ private static WebloungeResponse unwrapResponse(ServletResponse response) { while (response != null) { if (response instanceof WebloungeResponse) return (WebloungeResponse) response; if (!(response instanceof ServletResponseWrapper)) break; response = ((ServletResponseWrapper) response).getResponse(); } // Last resort if (response instanceof HttpServletResponse) return new WebloungeResponseImpl((HttpServletResponse) response); return null; } /** * Extract the wrapped <code>WebloungeRequest</code> from a <code> * ServletRequest</code> . * * @param request * the wrapping request * @return the wrapped <code>WebloungeRequest</code> or <code>null</code> if * no such response exists */ private static WebloungeRequest unwrapRequest(ServletRequest request) { while (request != null) { if (request instanceof WebloungeRequest) return (WebloungeRequest) request; if (!(request instanceof ServletRequestWrapper)) break; request = ((ServletRequestWrapper) request).getRequest(); } // Last resort if (request instanceof HttpServletRequest) { logger.warn("Found vanilla servlet request, defaulting to production environment"); // TOOD: Properly determine the environment return new WebloungeRequestImpl((HttpServletRequest) request, Environment.Production); } return null; } /** * {@inheritDoc} * * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag() */ @Override public int doStartTag() throws JspException { // Don't do work if not needed (which is the case during precompilation) if (RequestUtils.isPrecompileRequest(request)) return SKIP_BODY; return super.doStartTag(); } /** * {@inheritDoc} * * @see javax.servlet.jsp.tagext.TryCatchFinally#doCatch(java.lang.Throwable) */ public void doCatch(Throwable t) throws Throwable { // Don't log errors during tag execution while precompiling if (RequestUtils.isPrecompileRequest(request)) { return; } logger.warn("Error executing jsp tag {} on {}", getClass().getName(), request.getUrl()); logger.warn(t.getMessage(), t); } /** * {@inheritDoc} * * @see javax.servlet.jsp.tagext.TryCatchFinally#doFinally() */ public void doFinally() { // Make sure the state of the tag is reset between every use reset(); } }