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}