001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.util;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.net.URL;
022import java.util.Enumeration;
023import java.util.Locale;
024import java.util.Properties;
025import java.util.ResourceBundle;
026
027/**
028 * A specialization of a resource bundle.
029 *
030 * @since 2.0
031 */
032public class CombinedResources extends ResourceBundle {
033
034    // locale.getLanguage()
035    // locale.getCountry()
036    // locale.getVariant()
037
038    private final String resourceName;
039    private volatile boolean inited;
040    private final Properties properties = new Properties();
041
042    /**
043     * Constructs a new instance.
044     *
045     * @param resourceName A resource name.
046     */
047    public CombinedResources(final String resourceName) {
048        this.resourceName = resourceName;
049        init();
050    }
051
052    @Override
053    public Enumeration<String> getKeys() {
054        return new Enumeration<String>() {
055            @Override
056            public boolean hasMoreElements() {
057                return properties.keys().hasMoreElements();
058            }
059
060            @Override
061            public String nextElement() {
062                // We know that our properties will only ever contain Strings
063                return (String) properties.keys().nextElement();
064            }
065
066        };
067    }
068
069    /**
070     * Gets the resource name.
071     *
072     * @return the resource name.
073     */
074    public String getResourceName() {
075        return resourceName;
076    }
077
078    @Override
079    protected Object handleGetObject(final String key) {
080        return properties.get(key);
081    }
082
083    /**
084     * Initializes this instance.
085     */
086    protected void init() {
087        if (inited) {
088            return;
089        }
090        loadResources(getResourceName());
091        loadResources(Locale.getDefault());
092        loadResources(getLocale());
093        inited = true;
094    }
095
096    /**
097     * Loads resources.
098     *
099     * @param locale a Locale.
100     */
101    protected void loadResources(final Locale locale) {
102        if (locale == null) {
103            return;
104        }
105        final String[] parts = {locale.getLanguage(), locale.getCountry(), locale.getVariant()};
106        final StringBuilder sb = new StringBuilder();
107        for (int i = 0; i < 3; i++) {
108            sb.append(getResourceName());
109            for (int j = 0; j < i; j++) {
110                sb.append('_').append(parts[j]);
111            }
112            if (!parts[i].isEmpty()) {
113                sb.append('_').append(parts[i]);
114                loadResources(sb.toString());
115            }
116            sb.setLength(0);
117        }
118    }
119
120    /**
121     * Loads a resource.
122     *
123     * @param resourceName the resource to load.
124     */
125    protected void loadResources(String resourceName) {
126        ClassLoader loader = getClass().getClassLoader();
127        if (loader == null) {
128            loader = ClassLoader.getSystemClassLoader();
129        }
130        if (loader != null) {
131            resourceName = resourceName.replace('.', '/') + ".properties";
132            try {
133                final Enumeration<URL> resources = loader.getResources(resourceName);
134                while (resources.hasMoreElements()) {
135                    final URL resource = resources.nextElement();
136                    try (InputStream inputStream = resource.openConnection().getInputStream()) {
137                        properties.load(inputStream);
138                    } catch (final IOException ignored) {
139                        // Ignore
140                    }
141                }
142            } catch (final IOException ignored) {
143                // Ignore
144            }
145        }
146    }
147}