001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2021, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-385, Indriya nor the names of their contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.units.indriya.internal.format.l10n; 031 032import java.io.IOException; 033import java.io.InputStream; 034import java.util.Enumeration; 035import java.util.HashMap; 036import java.util.Map; 037import java.util.Objects; 038import java.util.PropertyResourceBundle; 039import java.util.ResourceBundle; 040import java.util.Set; 041import java.util.Vector; 042 043/** 044 * Extends <code>ResourceBundle</code> with 2 new capabilities. The first is to store the path where the properties file used to create the 045 * <code>InputStream</code> is located and the second is to allow additional <code>ResourceBundle</code> properties to be merged into an instance. 046 * <br> 047 * <br> 048 * To allow a <code>SystemOfUnits</code> to locate and merge extension module properties files. 049 * <br> 050 * 051 * @author Werner Keil 052 * @version 1.2 053 */ 054public class MultiPropertyResourceBundle extends ResourceBundle { 055// also see https://github.com/vitorzachi/tcc-multitenancy/blob/master/tccMultitenancy/src/net/sf/trugger/util/MultiResourceBundle.java but that code might be older 056 057 /** 058 * The location of the properties file that was used to instantiate the <code>MultiPropertyResourceBundle</code> instance. This field is set by the 059 * constructor. 060 */ 061 private String resourcePath = null; 062 063 /** 064 * @return The location of the properties file that was used to instantiate the <code>MultiPropertyResourceBundle</code> instance. 065 */ 066 public String getResourcePath() { 067 return resourcePath; 068 } 069 070 /** 071 * A {@link Map} containing all the properties that have been merged from multiple {@link ResourceBundle} instances. 072 */ 073 private final Map<String, Object> resources = new HashMap<>(); 074 075 /** 076 * A {@link StringBuilder} instance containing all the paths of the {@link ResourceBundle} instances that have been merged into this instance. This 077 * value is intended to be use to help generate a key for caching JSON formatted resource output in the {@link AbstractWebScript} class. 078 */ 079 private final StringBuilder mergedBundlePaths = new StringBuilder(); 080 081 /** 082 * @return Returns the {@link StringBuilder} instance containing the paths of all the {@link ResourceBundle} instances that have been merged into 083 * this instance. 084 */ 085 public StringBuilder getMergedBundlePaths() { 086 return mergedBundlePaths; 087 } 088 089 /** 090 * Instantiates a new <code>MultiPropertyResourceBundle</code>. 091 * 092 * @param stream 093 * The <code>InputStream</code> passed on to the super class constructor. 094 * @param resourcePath 095 * The location of the properties file used to create the <code>InputStream</code> 096 * @throws IOException 097 */ 098 public MultiPropertyResourceBundle(InputStream stream, String resourcePath) throws IOException { 099 final ResourceBundle resourceBundle = new PropertyResourceBundle(stream); 100 this.resourcePath = resourcePath; 101 merge(resourceBundle, resourcePath); 102 } 103 104 /** 105 * Constructor for instantiating from an existing {@link ResourceBundle}. This calls the <code>merge</code> method to copy the properties from the 106 * bundle into the <code>resources</code> map. 107 * 108 * @param baseBundle 109 * @param resourcePath 110 */ 111 public MultiPropertyResourceBundle(ResourceBundle baseBundle, String resourcePath) { 112 super(); 113 this.resourcePath = resourcePath; 114 merge(baseBundle, resourcePath); 115 } 116 117 /** 118 * Merges the properties of a <code>ResourceBundle</code> into the current <code>MultiPropertyResourceBundle</code> instance. This will override any 119 * values mapped to duplicate keys in the current merged properties. 120 * 121 * @param resourceBundle 122 * The <code>ResourceBundle</code> to merge the properties of. 123 * @param aResourcePath 124 */ 125 public void merge(ResourceBundle resourceBundle, String aResourcePath) { 126 if (resourceBundle != null) { 127 Enumeration<String> keys = resourceBundle.getKeys(); 128 while (keys.hasMoreElements()) { 129 String key = keys.nextElement(); 130 this.resources.put(key, resourceBundle.getObject(key)); 131 } 132 } 133 134 // Update the paths merged in this bundle 135 mergedBundlePaths.append(aResourcePath); 136 mergedBundlePaths.append(":"); 137 } 138 139 /** 140 * Overrides the super class implementation to return an object located in the merged bundles 141 * 142 * @return An <code>Object</code> from the merged bundles 143 */ 144 @Override 145 public Object handleGetObject(String key) { 146 Objects.requireNonNull(key); 147 return this.resources.get(key); 148 } 149 150 /** 151 * Overrides the super class implementation to return an enumeration of keys from all the merged bundles 152 * 153 * @return An <code>Enumeration</code> of the keys across all the merged bundles. 154 */ 155 @Override 156 public Enumeration<String> getKeys() { 157 Vector<String> keys = new Vector<>(this.resources.keySet()); 158 return keys.elements(); 159 } 160 161 /** 162 * Overrides the super class implementation to return the <code>Set</code> of keys from all merged bundles 163 * 164 * @return A <code>Set</code> of keys obtained from all merged bundles 165 */ 166 @Override 167 protected Set<String> handleKeySet() { 168 return this.resources.keySet(); 169 } 170 171 /** 172 * Overrides the super class implementation to check the existence of a key across all merged bundles 173 * 174 * @return <code>true</code> if the key is present and <code>false</code> otherwise. 175 */ 176 @Override 177 public boolean containsKey(String key) { 178 return this.resources.containsKey(key); 179 } 180 181 /** 182 * Overrides the super class implementation to return the <code>Set</code> of keys from all merged bundles 183 * 184 * @return A <code>Set</code> of keys obtained from all merged bundles 185 */ 186 @Override 187 public Set<String> keySet() { 188 return this.resources.keySet(); 189 } 190}