001/* 002 * File : $Source$ 003 * Date : $Date$ 004 * Version: $Revision$ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.jsp; 033 034import org.opencms.i18n.CmsResourceBundleLoader; 035 036import java.util.Locale; 037import java.util.MissingResourceException; 038import java.util.ResourceBundle; 039 040import javax.servlet.ServletResponse; 041import javax.servlet.jsp.JspException; 042import javax.servlet.jsp.PageContext; 043import javax.servlet.jsp.jstl.fmt.LocalizationContext; 044 045import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager; 046import org.apache.taglibs.standard.tag.common.fmt.BundleSupport; 047import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport; 048import org.apache.taglibs.standard.tag.el.fmt.BundleTag; 049 050/** 051 * Provides tag access to OpenCms resource bundles.<p> 052 * 053 * This replaces the <code><fmt:bundle basename=""></code> tag which is not capable of using OpenCms resource bundles.<p> 054 * 055 * You can use <code><fmt:message key=""></code> tags inside the <code><cms:bundle basename=""></code> tag as usual. 056 * 057 * @since 8.5.2 058 */ 059public class CmsJspTagBundle extends BundleTag { 060 061 /** Serial version UID required for safe serialization. */ 062 private static final long serialVersionUID = 7592250223728101278L; 063 064 /** The basename attribute value. */ 065 private String m_basename; 066 067 /** The localization to use. */ 068 private LocalizationContext m_locCtxt; 069 070 /** The prefix attribute value. */ 071 private String m_prefix; 072 073 /** 074 * Empty constructor.<p> 075 */ 076 public CmsJspTagBundle() { 077 078 super(); 079 init(); 080 } 081 082 /** 083 * Returns the initialized localization context.<p> 084 * @param pc the current page context 085 * @param basename the bas name of the bundle 086 * 087 * @return the initialized localization context 088 */ 089 public static LocalizationContext getLocalizationContext(PageContext pc, String basename) { 090 091 LocalizationContext locCtxt = null; 092 ResourceBundle bundle = null; 093 094 if ((basename == null) || basename.equals("")) { 095 return new LocalizationContext(); 096 } 097 098 // Try preferred locales 099 Locale pref = getLocale(pc, javax.servlet.jsp.jstl.core.Config.FMT_LOCALE); 100 if (pref != null) { 101 // Preferred locale is application-based 102 bundle = findMatch(basename, pref); 103 if (bundle != null) { 104 locCtxt = new LocalizationContext(bundle, pref); 105 } 106 } 107 108 if (locCtxt == null) { 109 // No match found with preferred locales, try using fallback locale 110 locCtxt = BundleSupport.getLocalizationContext(pc, basename); 111 } else { 112 // set response locale 113 if (locCtxt.getLocale() != null) { 114 setResponseLocale(pc, locCtxt.getLocale()); 115 } 116 } 117 118 return locCtxt; 119 } 120 121 /** 122 * Returns the locale specified by the named scoped attribute or context 123 * configuration parameter. 124 * 125 * <p> The named scoped attribute is searched in the page, request, 126 * session (if valid), and application scope(s) (in this order). If no such 127 * attribute exists in any of the scopes, the locale is taken from the 128 * named context configuration parameter. 129 * 130 * @param pageContext the page in which to search for the named scoped 131 * attribute or context configuration parameter 132 * @param name the name of the scoped attribute or context configuration 133 * parameter 134 * 135 * @return the locale specified by the named scoped attribute or context 136 * configuration parameter, or <tt>null</tt> if no scoped attribute or 137 * configuration parameter with the given name exists 138 */ 139 static Locale getLocale(PageContext pageContext, String name) { 140 141 Locale loc = null; 142 143 Object obj = javax.servlet.jsp.jstl.core.Config.find(pageContext, name); 144 if (obj != null) { 145 if (obj instanceof Locale) { 146 loc = (Locale)obj; 147 } else { 148 loc = SetLocaleSupport.parseLocale((String)obj); 149 } 150 } 151 152 return loc; 153 } 154 155 /** 156 * Stores the given locale in the response object of the given page 157 * context, and stores the locale's associated charset in the 158 * javax.servlet.jsp.jstl.fmt.request.charset session attribute, which 159 * may be used by the <requestEncoding> action in a page invoked by a 160 * form included in the response to set the request charset to the same as 161 * the response charset (this makes it possible for the container to 162 * decode the form parameter values properly, since browsers typically 163 * encode form field values using the response's charset). 164 * 165 * @param pc the page context whose response object is assigned 166 * the given locale 167 * @param locale the response locale 168 */ 169 static void setResponseLocale(PageContext pc, Locale locale) { 170 171 // set response locale 172 ServletResponse response = pc.getResponse(); 173 response.setLocale(locale); 174 175 // get response character encoding and store it in session attribute 176 if (pc.getSession() != null) { 177 try { 178 pc.setAttribute( 179 "javax.servlet.jsp.jstl.fmt.request.charset", 180 response.getCharacterEncoding(), 181 PageContext.SESSION_SCOPE); 182 } catch (IllegalStateException ex) { 183 // invalidated session ignored 184 } 185 } 186 } 187 188 /** 189 * Gets the resource bundle with the given base name and preferred locale. 190 * 191 * @param basename the resource bundle base name 192 * @param pref the preferred locale 193 * @return the resource bundle. 194 */ 195 private static ResourceBundle findMatch(String basename, Locale pref) { 196 197 ResourceBundle match = null; 198 try { 199 ResourceBundle bundle = CmsResourceBundleLoader.getBundle(basename, pref); 200 match = bundle; 201 } catch (MissingResourceException mre) { 202 // ignored 203 } 204 return match; 205 } 206 207 /** 208 * Internal action method.<p> 209 * 210 * @return EVAL_BODY_BUFFERED 211 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 212 */ 213 @Override 214 public int doStartTag() throws JspException { 215 216 evaluateExpressions(); 217 m_locCtxt = getLocalizationContext(pageContext, basename); 218 return EVAL_BODY_BUFFERED; 219 } 220 221 /** 222 * Returns the localization context to use.<p> 223 * 224 * @see org.apache.taglibs.standard.tag.common.fmt.BundleSupport#getLocalizationContext() 225 */ 226 @Override 227 public LocalizationContext getLocalizationContext() { 228 229 return m_locCtxt; 230 } 231 232 /** 233 * @see org.apache.taglibs.standard.tag.el.fmt.BundleTag#release() 234 */ 235 @Override 236 public void release() { 237 238 super.release(); 239 init(); 240 } 241 242 /** 243 * Sets the basename attribute value.<p> 244 * 245 * @param bn the basename attribute value 246 * 247 * @see org.apache.taglibs.standard.tag.el.fmt.BundleTag#setBasename(java.lang.String) 248 */ 249 @Override 250 public void setBasename(String bn) { 251 252 m_basename = bn; 253 } 254 255 /** 256 * Sets the prefix attribute value.<p> 257 * 258 * @param pf the prefix attribute value 259 * 260 * @see org.apache.taglibs.standard.tag.el.fmt.BundleTag#setPrefix(java.lang.String) 261 */ 262 @Override 263 public void setPrefix(String pf) { 264 265 m_prefix = pf; 266 } 267 268 /** 269 * Evaluates expressions as neccessary. 270 * 271 * This is a copy of the private method from the {@link BundleTag}. 272 * 273 * @throws JspException same as for the default {@link BundleTag}. 274 */ 275 private void evaluateExpressions() throws JspException { 276 277 // 'basename' attribute (mandatory) 278 basename = (String)ExpressionEvaluatorManager.evaluate("basename", m_basename, String.class, this, pageContext); 279 280 // 'prefix' attribute (optional) 281 if (m_prefix != null) { 282 prefix = (String)ExpressionEvaluatorManager.evaluate("prefix", m_prefix, String.class, this, pageContext); 283 } 284 } 285 286 /** 287 * Sets the initial state. 288 */ 289 private void init() { 290 291 m_basename = null; 292 m_locCtxt = null; 293 m_prefix = null; 294 } 295}