Hi all,

this my first post at tapestry dev list.

I have been working in serveral projects with tapestry (actually we have just finished the third one).

We have face and issue. One customer want an email to be send to every person in the BBDD. Each person has a different language, so the email has to be build for the locale of each one.

We have solve the issue using :
ResourceBundle strings = ResourceBundle.getBundle(
com.app.locale.mail,
                Locale.ENGLISH);
...

But it could be great if we can use getMessage from ComponentMessageSource with a specific locale, different than the one from the IEngine.
package org.apache.tapestry.services;
...
public interface ComponentMessagesSource
{
    public Messages getMessages(IComponent component);
    public Messages getMessages(IComponent component, Locale locale);
}

Is it a good idea?

The ComponentMessagesSource and ComponentMessagesSourceImpl are attached.

Regards

Pedro Ayala
package org.apache.tapestry.services;

import java.util.Locale;

import org.apache.hivemind.Messages;
import org.apache.tapestry.IComponent;

public interface ComponentMessagesSource
{
    public Messages getMessages(IComponent component);
    public Messages getMessages(IComponent component, Locale locale);
}
package org.apache.tapestry.services.impl;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.Messages;
import org.apache.hivemind.Resource;
import org.apache.hivemind.util.Defense;
import org.apache.hivemind.util.LocalizedNameGenerator;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.INamespace;
import org.apache.tapestry.event.ResetEventListener;
import org.apache.tapestry.services.ComponentMessagesSource;
import org.apache.tapestry.services.ComponentPropertySource;
import org.apache.tapestry.util.text.LocalizedProperties;

public class ComponentMessagesSourceImpl implements ComponentMessagesSource, ResetEventListener
{
    private Properties _emptyProperties = new Properties();

    private static final String SUFFIX = ".properties";

    /**
     * The name of the component/application/etc property that will be used to determine the
     * encoding to use when loading the messages
     */

    public static final String MESSAGES_ENCODING_PROPERTY_NAME = "org.apache.tapestry.messages-encoding";

    /**
     * Map of Maps. The outer map is keyed on component specification location ([EMAIL PROTECTED] Resource}.
     * This inner map is keyed on locale and the value is a [EMAIL PROTECTED] Properties}.
     */

    private Map _componentCache = new HashMap();

    private ComponentPropertySource _componentPropertySource;

    /**
     * Returns an instance of [EMAIL PROTECTED] Properties}containing the properly localized messages for the
     * component, in the [EMAIL PROTECTED] Locale}identified by the component's containing page.
     */

    protected synchronized Properties getLocalizedProperties(IComponent component, Locale locale)
    {
        Defense.notNull(component, "component");

        Resource specificationLocation = component.getSpecification().getSpecificationLocation();
        //Locale locale = component.getPage().getLocale();

        Map propertiesMap = findPropertiesMapForResource(specificationLocation);

        Properties result = (Properties) propertiesMap.get(locale);

        if (result == null)
        {

            // Not found, create it now.

            result = assembleComponentProperties(
                    component,
                    specificationLocation,
                    propertiesMap,
                    locale);

            propertiesMap.put(locale, result);
        }

        return result;
    }

    private Map findPropertiesMapForResource(Resource resource)
    {
        Map result = (Map) _componentCache.get(resource);

        if (result == null)
        {
            result = new HashMap();
            _componentCache.put(resource, result);
        }

        return result;
    }

    private Properties getNamespaceProperties(IComponent component, Locale locale)
    {
        INamespace namespace = component.getNamespace();

        Resource namespaceLocation = namespace.getSpecificationLocation();

        Map propertiesMap = findPropertiesMapForResource(namespaceLocation);

        Properties result = (Properties) propertiesMap.get(locale);

        if (result == null)
        {
            result = assembleNamespaceProperties(namespace, propertiesMap, locale);

            propertiesMap.put(locale, result);
        }

        return result;
    }

    private Properties assembleComponentProperties(IComponent component,
            Resource baseResourceLocation, Map propertiesMap, Locale locale)
    {
        List localizations = findLocalizationsForResource(baseResourceLocation, locale);

        Properties parent = null;
        Properties assembledProperties = null;
        
        Iterator i = localizations.iterator();

        while (i.hasNext())
        {
            ResourceLocalization rl = (ResourceLocalization) i.next();

            Locale l = rl.getLocale();

            // Retrieve namespace properties for current locale (and parent locales)
        	Properties namespaceProperties = getNamespaceProperties(component, l);
        	
        	// Use the namespace properties as default for assembled properties
            assembledProperties = new Properties(namespaceProperties);
            
            // Read localized properties for component
            Properties properties = readComponentProperties(component, l, rl.getResource(), null);

            // Override parent properties with current locale
            if (parent != null) {
            	if (properties != null)
            		parent.putAll(properties);
            }
            else
            	parent = properties;
            
            // Add to assembled properties
            if (parent != null)
            	assembledProperties.putAll(parent);
            
            // Save result in cache
            propertiesMap.put(l, assembledProperties);
        }

        return assembledProperties;
    }

    private Properties assembleNamespaceProperties(INamespace namespace, Map propertiesMap,
            Locale locale)
    {
        List localizations = findLocalizationsForResource(
                namespace.getSpecificationLocation(),
                locale);

        // Build them back up in reverse order.

        Properties parent = _emptyProperties;

        Iterator i = localizations.iterator();

        while (i.hasNext())
        {
            ResourceLocalization rl = (ResourceLocalization) i.next();

            Locale l = rl.getLocale();

            Properties properties = (Properties) propertiesMap.get(l);

            if (properties == null)
            {
                properties = readNamespaceProperties(namespace, l, rl.getResource(), parent);

                propertiesMap.put(l, properties);
            }

            parent = properties;
        }

        return parent;

    }

    /**
     * Finds the localizations of the provided resource. Returns a List of
     * [EMAIL PROTECTED] ResourceLocalization}(each pairing a locale with a localized resource). The list is
     * ordered from most general (i.e., "foo.properties") to most specific (i.e.,
     * "foo_en_US_yokel.properties").
     */

    private List findLocalizationsForResource(Resource resource, Locale locale)
    {
        List result = new ArrayList();

        String baseName = extractBaseName(resource);

        LocalizedNameGenerator g = new LocalizedNameGenerator(baseName, locale, SUFFIX);

        while (g.more())
        {
            String localizedName = g.next();
            Locale l = g.getCurrentLocale();
            Resource localizedResource = resource.getRelativeResource(localizedName);

            result.add(new ResourceLocalization(l, localizedResource));
        }

        Collections.reverse(result);

        return result;
    }

    private String extractBaseName(Resource baseResourceLocation)
    {
        String fileName = baseResourceLocation.getName();
        int dotx = fileName.lastIndexOf('.');

        return fileName.substring(0, dotx);
    }

    private Properties readComponentProperties(IComponent component, Locale locale,
            Resource propertiesResource, Properties parent)
    {
        String encoding = getComponentMessagesEncoding(component, locale);

        return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
    }

    private Properties readNamespaceProperties(INamespace namespace, Locale locale,
            Resource propertiesResource, Properties parent)
    {
        String encoding = getNamespaceMessagesEncoding(namespace, locale);

        return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
    }

    private Properties readPropertiesResource(URL resourceURL, String encoding, Properties parent)
    {
        if (resourceURL == null)
            return parent;

        Properties result = new Properties(parent);

        LocalizedProperties wrapper = new LocalizedProperties(result);

        InputStream input = null;

        try
        {
            input = new BufferedInputStream(resourceURL.openStream());

            if (encoding == null)
                wrapper.load(input);
            else
                wrapper.load(input, encoding);

            input.close();
        }
        catch (IOException ex)
        {
            throw new ApplicationRuntimeException(ImplMessages.unableToLoadProperties(
                    resourceURL,
                    ex), ex);
        }
        finally
        {
            close(input);
        }

        return result;
    }

    private void close(InputStream is)
    {
        if (is != null)
            try
            {
                is.close();
            }
            catch (IOException ex)
            {
                // Ignore.
            }
    }

    /**
     * Clears the cache of read properties files.
     */

    public synchronized void resetEventDidOccur()
    {
        _componentCache.clear();
    }

    public Messages getMessages(IComponent component)
    {
    	return getMessages(component,component.getPage().getLocale());
    }
    
    public Messages getMessages(IComponent component, Locale locale)
    {
        return new ComponentMessages(locale, getLocalizedProperties(component, locale));
    }

    private String getComponentMessagesEncoding(IComponent component, Locale locale)
    {
        String encoding = _componentPropertySource.getLocalizedComponentProperty(
                component,
                locale,
                MESSAGES_ENCODING_PROPERTY_NAME);

        if (encoding == null)
            encoding = _componentPropertySource.getLocalizedComponentProperty(
                    component,
                    locale,
                    TemplateSourceImpl.TEMPLATE_ENCODING_PROPERTY_NAME);

        return encoding;
    }

    private String getNamespaceMessagesEncoding(INamespace namespace, Locale locale)
    {
        return _componentPropertySource.getLocalizedNamespaceProperty(
                namespace,
                locale,
                MESSAGES_ENCODING_PROPERTY_NAME);
    }

    public void setComponentPropertySource(ComponentPropertySource componentPropertySource)
    {
        _componentPropertySource = componentPropertySource;
    }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to