org.hippoecm.frontend.ClassFromKeyStringResourceLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.hippoecm.frontend.ClassFromKeyStringResourceLoader.java

Source

/*
 *  Copyright 2010-2013 Hippo B.V. (http://www.onehippo.com)
 * 
 *  Licensed 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.hippoecm.frontend;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.wicket.Component;
import org.apache.wicket.core.util.resource.UrlResourceStream;
import org.apache.wicket.core.util.resource.locator.ResourceNameIterator;
import org.apache.wicket.resource.loader.ComponentStringResourceLoader;
import org.apache.wicket.util.resource.IResourceStream;
import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
import org.apache.wicket.util.string.Strings;
import org.apache.wicket.util.value.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An IStringResourceLoader that does not need a class to resolve the corresponding properties.
 * <p>
 * The keys can be in the format "realKey[,prop1=value1[,prop2=value2[...]]]".
 * In this case, the prop-value pairs are used as additional criteria in the
 * search for a translation.
 * <p>
 * The "class" criterium is used to find the resource from the class path.  When the key
 * "exception" has a criterium "type", that is used when the "class" was not available or
 * did not yield a result.
 */
public class ClassFromKeyStringResourceLoader extends ComponentStringResourceLoader {

    static final Logger log = LoggerFactory.getLogger(ClassFromKeyStringResourceLoader.class);

    private final Map<String, java.util.Properties> cache = new ConcurrentHashMap<String, java.util.Properties>();

    private IResourceStream getResourceStream(final String path) {
        // use context classloader when no specific classloader is set
        // (package resources for instance)
        URL url = Thread.currentThread().getContextClassLoader().getResource(path);
        if (url != null) {
            return new UrlResourceStream(url);
        }

        // use Wicket classloader when no specific classloader is set
        url = getClass().getClassLoader().getResource(path);
        if (url != null) {
            return new UrlResourceStream(url);
        }
        return null;
    }

    private Properties getProperties(String path) {
        if (!cache.containsKey(path)) {
            java.util.Properties properties = new java.util.Properties();
            IResourceStream resourceStream = getResourceStream(path);
            if (resourceStream != null) {
                try {
                    InputStream in = new BufferedInputStream(resourceStream.getInputStream());
                    properties.load(in);
                } catch (IOException e) {
                    log.error("Error reading " + path, e);
                } catch (ResourceStreamNotFoundException e) {
                    log.error("Could not find resource at " + path, e);
                }
            }
            cache.put(path, properties);
        }
        return cache.get(path);
    }

    private String getStringForClass(String realKey, Locale locale, String style, String clazz) {
        // Create the base path
        String path = clazz.replace('.', '/');

        // Iterator over all the combinations
        ResourceNameIterator iter = new ResourceNameIterator(path, style, null, locale,
                Arrays.asList("properties", "xml"), false);
        while (iter.hasNext()) {
            String newPath = iter.next();
            Properties properties = getProperties(newPath);
            String value = properties.getProperty(realKey);
            if (value != null) {
                return value;
            }
        }
        return null;
    }

    @Override
    public String loadStringResource(final Component component, final String key, final Locale locale,
            final String style, final String variation) {
        if (key.indexOf(',') > 0) {
            List<String> criteria = new LinkedList<String>();
            for (String subKey : key.split(",")) {
                criteria.add(subKey);
            }

            String realKey = key.substring(0, key.indexOf(','));
            ValueMap map = new ValueMap(key.substring(key.indexOf(',') + 1));
            if (map.containsKey("class")) {
                // remove class key from map and criteria
                String clazz = (String) map.remove("class");
                Iterator<String> iter = criteria.iterator();
                while (iter.hasNext()) {
                    if (iter.next().startsWith("class=")) {
                        iter.remove();
                        break;
                    }
                }

                // iterate while no value is found, dropping the last 
                String value = getStringForClass(Strings.join(",", criteria.toArray(new String[criteria.size()])),
                        locale, style, clazz);
                if (value != null) {
                    return value;
                }
            }
            if ("exception".equals(realKey) && map.containsKey("type")) {
                // remove class key from map and criteria
                String clazz = (String) map.remove("type");
                Iterator<String> iter = criteria.iterator();
                while (iter.hasNext()) {
                    if (iter.next().startsWith("type=")) {
                        iter.remove();
                        break;
                    }
                }

                // Load the properties associated with the path
                String value = getStringForClass(Strings.join(",", criteria.toArray(new String[criteria.size()])),
                        locale, style, clazz);
                if (value != null) {
                    return value;
                }
            }
        }
        return null;
    }

}