Package org.apache.wicket

Source Code of org.apache.wicket.Localizer

/*
* 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.wicket;

import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;

import org.apache.wicket.model.IModel;
import org.apache.wicket.resource.loader.IStringResourceLoader;
import org.apache.wicket.settings.IResourceSettings;
import org.apache.wicket.util.concurrent.ConcurrentHashMap;
import org.apache.wicket.util.string.AppendingStringBuffer;
import org.apache.wicket.util.string.interpolator.PropertyVariableInterpolator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* A utility class that encapsulates all of the localization related functionality in a way that it
* can be accessed by all areas of the framework in a consistent way. A singleton instance of this
* class is available via the <code>Application</code> object.
* <p>
* You may register additional IStringResourceLoader to extend or replace Wickets default search
* strategy for the properties. E.g. string resource loaders which load the properties from a
* database. There should be no need to extend Localizer.
*
* @see org.apache.wicket.settings.Settings#getLocalizer()
* @see org.apache.wicket.resource.loader.IStringResourceLoader
* @see org.apache.wicket.settings.Settings#getStringResourceLoaders()
*
* @author Chris Turner
* @author Juergen Donnerstag
*/
public class Localizer
{
  private static final Logger logger = LoggerFactory.getLogger(Localizer.class);

  /** ConcurrentHashMap does not allow null values */
  private static final String NULL_VALUE = "<null-value>";

  /** Cache properties */
  private Map cache = newCache();

  /**
   * Create the utils instance class backed by the configuration information contained within the
   * supplied application object.
   */
  public Localizer()
  {
  }

  /**
   * Clear all cache entries
   */
  public final void clearCache()
  {
    if (cache != null)
    {
      cache = new ConcurrentHashMap();
    }
  }

  /**
   * @see #getString(String, Component, IModel, Locale, String, String)
   *
   * @param key
   *            The key to obtain the resource for
   * @param component
   *            The component to get the resource for
   * @return The string resource
   * @throws MissingResourceException
   *             If resource not found and configuration dictates that exception should be thrown
   */
  public String getString(final String key, final Component component)
    throws MissingResourceException
  {
    return getString(key, component, null, null);
  }

  /**
   * @see #getString(String, Component, IModel, Locale, String, String)
   *
   * @param key
   *            The key to obtain the resource for
   * @param component
   *            The component to get the resource for
   * @param model
   *            The model to use for property substitutions in the strings (optional)
   * @return The string resource
   * @throws MissingResourceException
   *             If resource not found and configuration dictates that exception should be thrown
   */
  public String getString(final String key, final Component component, final IModel model)
    throws MissingResourceException
  {
    return getString(key, component, model, null);
  }

  /**
   * @see #getString(String, Component, IModel, Locale, String, String)
   *
   * @param key
   *            The key to obtain the resource for
   * @param component
   *            The component to get the resource for
   * @param defaultValue
   *            The default value (optional)
   * @return The string resource
   * @throws MissingResourceException
   *             If resource not found and configuration dictates that exception should be thrown
   */
  public String getString(final String key, final Component component, final String defaultValue)
    throws MissingResourceException
  {
    return getString(key, component, null, defaultValue);
  }

  /**
   * This method is now deprecated.
   *
   * @param key
   * @param component
   * @param model
   * @param locale
   * @param style
   * @param defaultValue
   * @return String
   * @throws MissingResourceException
   *
   * @Deprecated please use {@link #getString(String, Component, IModel, String)}
   */
  public String getString(final String key, final Component component, final IModel model,
    final Locale locale, final String style, final String defaultValue)
    throws MissingResourceException
  {
    return getString(key, component, model, defaultValue);
  }

  /**
   * Get the localized string using all of the supplied parameters. This method is left public to
   * allow developers full control over string resource loading. However, it is recommended that
   * one of the other convenience methods in the class are used as they handle all of the work
   * related to obtaining the current user locale and style information.
   *
   * @param key
   *            The key to obtain the resource for
   * @param component
   *            The component to get the resource for (optional)
   * @param model
   *            The model to use for substitutions in the strings (optional)
   * @param defaultValue
   *            The default value (optional)
   * @return The string resource
   * @throws MissingResourceException
   *             If resource not found and configuration dictates that exception should be thrown
   */
  public String getString(final String key, final Component component, final IModel model,
    final String defaultValue) throws MissingResourceException
  {
    final IResourceSettings resourceSettings = Application.get().getResourceSettings();

    boolean addedToPage = false;
    if (component != null)
    {
      if ((component instanceof Page) || null != component.findParent(Page.class))
      {
        addedToPage = true;
      }

      if (!addedToPage)
      {
        logger.warn(
          "Tried to retrieve a localized string for a component that has not yet been added to the page. "
            + "This can sometimes lead to an invalid or no localized resource returned. "
            + "Make sure you are not calling Component#getString() inside your Component's constructor. "
            + "Offending component: {}", component);
      }
    }


    String cacheKey = null;
    String string = null;

    // If this component is not yet added to page we do not want to check
    // cache as we can generate an invalid cache key
    if ((cache != null) && addedToPage)
    {
      cacheKey = getCacheKey(key, component);
    }

    // Value not found are cached as well (value = null)
    if ((cacheKey != null) && cache.containsKey(cacheKey))
    {
      string = getFromCache(cacheKey);
    }
    else
    {
      // Iterate over all registered string resource loaders until the
      // property has been found

      Iterator iter = resourceSettings.getStringResourceLoaders().iterator();
      while (iter.hasNext())
      {
        IStringResourceLoader loader = (IStringResourceLoader)iter.next();
        string = loader.loadStringResource(component, key);
        if (string != null)
        {
          break;
        }
      }

      // Cache the result incl null if not found
      if (cacheKey != null)
      {
        putIntoCache(cacheKey, string);
      }
    }

    if ((string == null) && (defaultValue != null))
    {
      // Resource not found, so handle missing resources based on
      // application configuration and try the default value
      if (resourceSettings.getUseDefaultOnMissingResource())
      {
        string = defaultValue;
      }
    }

    // If a property value has been found, or a default value was given,
    // than replace the placeholder and we are done
    if (string != null)
    {
      return substitutePropertyExpressions(component, string, model);
    }

    if (resourceSettings.getThrowExceptionOnMissingResource())
    {
      AppendingStringBuffer message = new AppendingStringBuffer("Unable to find resource: " +
        key);
      if (component != null)
      {
        message.append(" for component: ");
        message.append(component.getPageRelativePath());
        message.append(" [class=").append(component.getClass().getName()).append("]");
      }
      throw new MissingResourceException(message.toString(), (component != null
        ? component.getClass().getName() : ""), key);
    }

    return "[Warning: String resource for '" + key + "' not found]";
  }

  /**
   * Put the value into the cache and associate it with the cache key
   *
   * @param cacheKey
   * @param string
   */
  protected void putIntoCache(final String cacheKey, final String string)
  {
    // ConcurrentHashMap does not allow null values
    if (string == null)
    {
      cache.put(cacheKey, NULL_VALUE);
    }
    else
    {
      cache.put(cacheKey, string);
    }
  }

  /**
   * Get the value associated with the key from the cache.
   *
   * @param cacheKey
   * @return The value of the key
   */
  protected String getFromCache(final String cacheKey)
  {
    final String value = (String)cache.get(cacheKey);

    // ConcurrentHashMap does not allow null values
    if (value == NULL_VALUE)
    {
      return null;
    }
    else
    {
      return value;
    }
  }

  /**
   * Gets the cache key
   *
   * @param key
   * @param component
   * @return The value of the key
   */
  protected String getCacheKey(final String key, final Component component)
  {
    String cacheKey = key;
    if (component != null)
    {
      AppendingStringBuffer buffer = new AppendingStringBuffer(key);

      Component cursor = component;
      while (cursor != null)
      {
        buffer.append("-").append(cursor.getClass().getName());
        buffer.append(":").append(cursor.getId());
        cursor = cursor.getParent();
      }

      buffer.append("-").append(component.getLocale());
      buffer.append("-").append(component.getStyle());
      // TODO 1.4 look if we want to properly separate getstyle/getvariation
      // for now getvariation() is rolled up into getstyle()
      // buffer.append("-").append(component.getVariation());
      cacheKey = buffer.toString();
    }
    return cacheKey;
  }

  /**
   * Helper method to handle property variable substitution in strings.
   *
   * @param component
   *            The component requesting a model value
   * @param string
   *            The string to substitute into
   * @param model
   *            The model
   * @return The resulting string
   */
  public String substitutePropertyExpressions(final Component component, final String string,
    final IModel model)
  {
    if ((string != null) && (model != null))
    {
      return PropertyVariableInterpolator.interpolate(string, model.getObject());
    }
    return string;
  }

  /**
   * By default the cache is enabled. Disabling the cache will disable it and clear the cache.
   *
   * @param value
   */
  public final void setEnableCache(boolean value)
  {
    if (value == false)
    {
      cache = null;
    }
    else if (cache == null)
    {
      cache = newCache();
    }
  }

  /**
   * Create a new cache
   *
   * @return cache
   */
  private Map newCache()
  {
    return new ConcurrentHashMap();
  }
}
TOP

Related Classes of org.apache.wicket.Localizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.