com.day.cq.wcm.tags.SetContentBundleTag Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.wcm.tags;
import java.util.Arrays;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.jstl.core.Config;
import javax.servlet.jsp.jstl.fmt.LocalizationContext;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.scripting.jsp.util.TagUtil;
import com.day.cq.commons.LanguageUtil;
import com.day.cq.wcm.api.LanguageManager;
/**
* SetContentBundleTag
implements a custom tag, which sets a
* {@link LocalizationContext} backed with a {@link ContentResourceBundle}. This
* allows one to use property names as keys in a JSTL formatting action and use
* the value of the property as localized message.
*
*
* The provided resource bundle also uses the resource bundle provided by CQ as
* a fallback if the underlying Resource does not contain a certain key.
*
*
* The language/locale of the CQ resource bundle is determined depending on the
* "source" attribute, which can be either
*
*
* - static use "language" attribute,
* - request uses request.getLocale(),
* - page uses language of the current page or resource or
* - auto page if available, otherwise use locale from request.
*
*
* Defaults to "auto" or "static", if "language" is set. For "page" the
* "language" attribute will be used as fallback, if given. If the "language"
* attribute is not set, but expected, the server default locale will be used.
*/
public class SetContentBundleTag extends TagSupport {
private static final long serialVersionUID = -3437648502705143816L;
private enum Source {
STATIC,
PAGE,
REQUEST,
AUTO
}
private Source source = null;
private Locale language = null;
private String basename = null;
/**
* Sets a default {@link LocalizationContext} in {@link Config} with a page
* scope.
*
* @return {@link #EVAL_PAGE}.
*/
public int doEndTag() {
try {
SlingHttpServletRequest request = TagUtil.getRequest(pageContext);
Resource content = request.getResource();
final ResourceBundle requestBundle = getResourceBundle(request);
final ResourceBundle bundle;
final ValueMap values = content.adaptTo(ValueMap.class);
if ( values != null ) {
bundle = new ContentResourceBundle(values, requestBundle);
} else {
bundle = requestBundle;
}
Config.set(pageContext, Config.FMT_LOCALIZATION_CONTEXT,
new LocalizationContext(bundle, getLocale(request)),
PageContext.PAGE_SCOPE);
return EVAL_PAGE;
} finally {
// reset language
language = null;
}
}
public void setSource(String source) throws JspException {
try {
this.source = Source.valueOf(source.toUpperCase());
} catch (IllegalArgumentException e) {
throw new JspException("setContentBundle: 'source' must be one of " + Arrays.toString(Source.values()) + " (upper or lowercase)", e);
}
}
public String getSource() {
return this.source.toString();
}
/**
* @return the currently set language that should be used or null
* if the language should be derived from the path of the current resource.
*/
public String getLanguage() {
return language.getLanguage();
}
/**
* @param language the language that will be used when a resource bundle is
* obtained.
*/
public void setLanguage(String language) {
this.language = LanguageUtil.getLocale(language);
}
/**
* @return the currently set basename that should be used or null
.
*/
public String getBasename() {
return basename;
}
/**
* @param basename the basename that will be used when a resource bundle is
* obtained.
*/
public void setBasename(String basename) {
this.basename = basename;
}
//--------------------------------< internal >------------------------------
/**
* Returns the resource bundle from the given request
. The
* language for the locale is derived from the current request or
* set explicitly. See also {@link SetContentBundleTag}.
*
* @param request the current request.
* @return the resource bundle or null
if the language has not
* been set and the current resource path depth is less than 2.
*/
private ResourceBundle getResourceBundle(SlingHttpServletRequest request) {
return request.getResourceBundle(basename, getLocale(request));
}
private Locale getLocale(SlingHttpServletRequest request) {
Source source = this.source;
if (source == null) {
source = language != null ? Source.STATIC : Source.AUTO;
}
if (source == Source.STATIC) {
return language != null ? language : Locale.getDefault();
} else if (source == Source.PAGE) {
Locale locale = getPageLocale(request.getResource());
if (locale != null) {
return locale;
}
return language != null ? language : Locale.getDefault();
} else if (source == Source.REQUEST) {
return request.getLocale();
} else /* if (source == Source.AUTO) */ {
Locale locale = getPageLocale(request.getResource());
if (locale != null) {
return locale;
}
return request.getLocale();
}
}
private Locale getPageLocale(Resource resource) {
// retrieve language manager service
SlingBindings bindings = (SlingBindings) pageContext.getRequest().getAttribute(SlingBindings.class.getName());
SlingScriptHelper scriptHelper = bindings.getSling();
LanguageManager langMgr = scriptHelper.getService(LanguageManager.class);
if (langMgr == null) {
return null;
}
return langMgr.getLanguage(resource);
}
}