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.PageContext; 042import javax.servlet.jsp.jstl.fmt.LocalizationContext; 043 044import org.apache.taglibs.standard.tag.common.fmt.BundleSupport; 045import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport; 046import org.apache.taglibs.standard.tag.el.fmt.BundleTag; 047 048/** 049 * Provides tag access to OpenCms resource bundles.<p> 050 * 051 * This replaces the <code><fmt:bundle basename=""></code> tag which is not capable of using OpenCms resource bundles.<p> 052 * 053 * You can use <code><fmt:message key=""></code> tags inside the <code><cms:bundle basename=""></code> tag as usual. 054 * 055 * @since 8.5.2 056 */ 057public class CmsJspTagBundle extends BundleTag { 058 059 /** Serial version UID required for safe serialisation. */ 060 private static final long serialVersionUID = 7592250223728101278L; 061 062 /** The basename attribute value. */ 063 private String m_basename; 064 065 /** The localization to use. */ 066 private LocalizationContext m_locCtxt; 067 068 /** 069 * Empty constructor.<p> 070 */ 071 public CmsJspTagBundle() { 072 073 super(); 074 m_basename = null; 075 m_locCtxt = null; 076 } 077 078 /** 079 * Returns the initialized localization context.<p> 080 * @param pc the current page context 081 * @param basename the bas name of the bundle 082 * 083 * @return the initialized localization context 084 */ 085 public static LocalizationContext getLocalizationContext(PageContext pc, String basename) { 086 087 LocalizationContext locCtxt = null; 088 ResourceBundle bundle = null; 089 090 if ((basename == null) || basename.equals("")) { 091 return new LocalizationContext(); 092 } 093 094 // Try preferred locales 095 Locale pref = getLocale(pc, javax.servlet.jsp.jstl.core.Config.FMT_LOCALE); 096 if (pref != null) { 097 // Preferred locale is application-based 098 bundle = findMatch(basename, pref); 099 if (bundle != null) { 100 locCtxt = new LocalizationContext(bundle, pref); 101 } 102 } 103 104 if (locCtxt == null) { 105 // No match found with preferred locales, try using fallback locale 106 locCtxt = BundleSupport.getLocalizationContext(pc, basename); 107 } else { 108 // set response locale 109 if (locCtxt.getLocale() != null) { 110 setResponseLocale(pc, locCtxt.getLocale()); 111 } 112 } 113 114 return locCtxt; 115 } 116 117 /** 118 * Returns the locale specified by the named scoped attribute or context 119 * configuration parameter. 120 * 121 * <p> The named scoped attribute is searched in the page, request, 122 * session (if valid), and application scope(s) (in this order). If no such 123 * attribute exists in any of the scopes, the locale is taken from the 124 * named context configuration parameter. 125 * 126 * @param pageContext the page in which to search for the named scoped 127 * attribute or context configuration parameter 128 * @param name the name of the scoped attribute or context configuration 129 * parameter 130 * 131 * @return the locale specified by the named scoped attribute or context 132 * configuration parameter, or <tt>null</tt> if no scoped attribute or 133 * configuration parameter with the given name exists 134 */ 135 static Locale getLocale(PageContext pageContext, String name) { 136 137 Locale loc = null; 138 139 Object obj = javax.servlet.jsp.jstl.core.Config.find(pageContext, name); 140 if (obj != null) { 141 if (obj instanceof Locale) { 142 loc = (Locale)obj; 143 } else { 144 loc = SetLocaleSupport.parseLocale((String)obj); 145 } 146 } 147 148 return loc; 149 } 150 151 /** 152 * Stores the given locale in the response object of the given page 153 * context, and stores the locale's associated charset in the 154 * javax.servlet.jsp.jstl.fmt.request.charset session attribute, which 155 * may be used by the <requestEncoding> action in a page invoked by a 156 * form included in the response to set the request charset to the same as 157 * the response charset (this makes it possible for the container to 158 * decode the form parameter values properly, since browsers typically 159 * encode form field values using the response's charset). 160 * 161 * @param pc the page context whose response object is assigned 162 * the given locale 163 * @param locale the response locale 164 */ 165 static void setResponseLocale(PageContext pc, Locale locale) { 166 167 // set response locale 168 ServletResponse response = pc.getResponse(); 169 response.setLocale(locale); 170 171 // get response character encoding and store it in session attribute 172 if (pc.getSession() != null) { 173 try { 174 pc.setAttribute( 175 "javax.servlet.jsp.jstl.fmt.request.charset", 176 response.getCharacterEncoding(), 177 PageContext.SESSION_SCOPE); 178 } catch (IllegalStateException ex) { 179 // invalidated session ignored 180 } 181 } 182 } 183 184 /** 185 * Gets the resource bundle with the given base name and preferred locale. 186 * 187 * @param basename the resource bundle base name 188 * @param pref the preferred locale 189 */ 190 private static ResourceBundle findMatch(String basename, Locale pref) { 191 192 ResourceBundle match = null; 193 try { 194 ResourceBundle bundle = CmsResourceBundleLoader.getBundle(basename, pref); 195 match = bundle; 196 } catch (MissingResourceException mre) { 197 // ignored 198 } 199 return match; 200 } 201 202 /** 203 * Internal action method.<p> 204 * 205 * @return EVAL_BODY_BUFFERED 206 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 207 */ 208 @Override 209 public int doStartTag() { 210 211 m_locCtxt = getLocalizationContext(pageContext, getBasename()); 212 return EVAL_BODY_BUFFERED; 213 } 214 215 /** 216 * Returns the basename attribute value.<p> 217 * 218 * @return the basename attribute value 219 */ 220 public String getBasename() { 221 222 return m_basename; 223 } 224 225 /** 226 * Returns the localization context to use.<p> 227 * 228 * @see org.apache.taglibs.standard.tag.common.fmt.BundleSupport#getLocalizationContext() 229 */ 230 @Override 231 public LocalizationContext getLocalizationContext() { 232 233 // TODO: Auto-generated method stub 234 return m_locCtxt; 235 } 236 237 /** 238 * Sets the basename attribute value.<p> 239 * 240 * @param bn the basename attribute value 241 * 242 * @see org.apache.taglibs.standard.tag.el.fmt.BundleTag#setBasename(java.lang.String) 243 */ 244 @Override 245 public void setBasename(String bn) { 246 247 m_basename = bn; 248 } 249 250}