blob: 999e5881eb089a7f6c7d99f2dc5a889e877c3fb5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.taglib.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import javax.el.ValueExpression;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspAttribute;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspTag;
import org.apache.myfaces.config.MyfacesConfig;
import org.apache.myfaces.util.lang.ClassUtils;
/**
* Loads a resource bundle and saves it as a variable in the request scope.
* <p>
* Unless otherwise specified, all attributes accept static values or EL expressions.
* </p>
* <p>
* TODO: We should find a way to save loaded bundles in the state, because otherwise on the next request the bundle map
* will not be present before the render phase and value bindings that reference to the bundle will always log annoying
* "Variable 'xxx' could not be resolved" error messages.
* </p>
*
* @author Manfred Geiler (latest modification by $Author$)
* @version $Revision$ $Date$
*/
@JSFJspTag(name = "f:loadBundle", bodyContent = "empty")
public class LoadBundleTag extends TagSupport
{
private static final long serialVersionUID = -8892145684062838928L;
private ValueExpression _basename;
private String _var;
/**
* The base name of the resource bundle.
*/
@JSFJspAttribute(className="javax.el.ValueExpression",
deferredValueType="java.lang.String")
public void setBasename(ValueExpression basename)
{
_basename = basename;
}
/**
* The name of the variable in request scope that the resources are saved to. This must be a static value.
*/
@JSFJspAttribute(required = true)
public void setVar(String var)
{
_var = var;
}
@Override
public int doStartTag() throws JspException
{
if (null == _var)
{
throw new NullPointerException("LoadBundle: 'var' must not be null");
}
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null)
{
throw new JspException("No faces context?!");
}
UIViewRoot viewRoot = facesContext.getViewRoot();
if (viewRoot == null)
{
throw new JspException("No view root! LoadBundle must be nested inside <f:view> action.");
}
Locale locale = viewRoot.getLocale();
if (locale == null)
{
locale = facesContext.getApplication().getDefaultLocale();
}
String basename = null;
if (_basename != null)
{
if (_basename.isLiteralText())
{
basename = _basename.getExpressionString();
}
else
{
basename = (String)_basename.getValue(facesContext.getELContext());
}
}
if (null == basename)
{
throw new NullPointerException("LoadBundle: 'basename' must not be null");
}
ResourceBundle.Control bundleControl =
MyfacesConfig.getCurrentInstance(facesContext).getResourceBundleControl();
ResourceBundle bundle;
try
{
if (bundleControl == null)
{
bundle = ResourceBundle.getBundle(basename, locale, ClassUtils.getContextClassLoader());
}
else
{
bundle = ResourceBundle.getBundle(basename, locale, ClassUtils.getContextClassLoader(),
bundleControl);
}
}
catch (MissingResourceException e)
{
try
{
if (bundleControl == null)
{
bundle = ResourceBundle.getBundle(basename, locale, this.getClass().getClassLoader());
}
else
{
bundle = ResourceBundle.getBundle(basename, locale, this.getClass().getClassLoader(),
bundleControl);
}
}
catch (MissingResourceException e1)
{
throw new JspException("Resource bundle '" + basename + "' could not be found.", e1);
}
}
facesContext.getExternalContext().getRequestMap().put(_var, new BundleMap(bundle));
return Tag.SKIP_BODY;
}
private static class BundleMap implements Map<String, String>
{
private ResourceBundle _bundle;
private List<String> _values;
public BundleMap(ResourceBundle bundle)
{
_bundle = bundle;
}
// Optimized methods
@Override
public String get(Object key)
{
try
{
return (String)_bundle.getObject(key.toString());
}
catch (Exception e)
{
return "???" + key + "???";
}
}
@Override
public boolean isEmpty()
{
return !_bundle.getKeys().hasMoreElements();
}
@Override
public boolean containsKey(Object key)
{
return _bundle.containsKey(key.toString());
}
// Unoptimized methods
@Override
public Collection<String> values()
{
if (_values == null)
{
_values = new ArrayList<>();
for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements();)
{
String v = _bundle.getString(enumer.nextElement());
_values.add(v);
}
}
return _values;
}
@Override
public int size()
{
return values().size();
}
@Override
public boolean containsValue(Object value)
{
return values().contains(value);
}
@Override
public Set<Map.Entry<String, String>> entrySet()
{
Set<Entry<String, String>> set = new HashSet<>();
for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements();)
{
final String k = enumer.nextElement();
set.add(new Map.Entry<String, String>()
{
@Override
public String getKey()
{
return k;
}
@Override
public String getValue()
{
return (String)_bundle.getObject(k);
}
@Override
public String setValue(String value)
{
throw new UnsupportedOperationException(this.getClass().getName()
+ " UnsupportedOperationException");
}
});
}
return set;
}
@Override
public Set<String> keySet()
{
Set<String> set = new HashSet<>();
for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements();)
{
set.add(enumer.nextElement());
}
return set;
}
// Unsupported methods
@Override
public String remove(Object key)
{
throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
}
@Override
public void putAll(Map<? extends String, ? extends String> t)
{
throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
}
@Override
public String put(String key, String value)
{
throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
}
@Override
public void clear()
{
throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
}
}
}