001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2018 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Affero General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jgrapes.webconsole.base; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.net.URL; 024import java.net.URLConnection; 025import java.util.List; 026import java.util.ListIterator; 027import java.util.Locale; 028import java.util.Properties; 029import java.util.ResourceBundle; 030import java.util.ResourceBundle.Control; 031 032/** 033 * A {@link Control} that implements a special lookup 034 * algorithm. See {@link #newBundle}. 035 */ 036public class ConsoleResourceBundleControl extends Control { 037 038 private final List<Class<?>> clses; 039 040 /** 041 * Instantiates a new web console resource bundle control. 042 * 043 * @param clses the classes to use 044 */ 045 public ConsoleResourceBundleControl(List<Class<?>> clses) { 046 super(); 047 this.clses = clses; 048 } 049 050 @Override 051 public List<String> getFormats(String baseName) { 052 if (baseName == null) { 053 throw new NullPointerException(); // NOPMD 054 } 055 return FORMAT_PROPERTIES; 056 } 057 058 /** 059 * Returns `null` (no fallback). 060 */ 061 @Override 062 public Locale getFallbackLocale(String baseName, Locale locale) { 063 return null; 064 } 065 066 /** 067 * Creates a new resource bundle using the classes passed to the 068 * constructor and the base name. For each class (in reverse order) 069 * an attempt is made to load a properties file relative to the 070 * class. If found, the entries are merged with any already existing 071 * entries. The class list usually consists of the web console class 072 * and its ancestor classes. Using this controller, derived classes 073 * can thus override resources from their base classes. 074 */ 075 @Override 076 @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", 077 "PMD.AvoidInstantiatingObjectsInLoops", "PMD.CognitiveComplexity" }) 078 public ResourceBundle newBundle(String baseName, Locale locale, 079 String format, ClassLoader loader, boolean reload) 080 throws IllegalAccessException, InstantiationException, IOException { 081 String bundleName = toBundleName(baseName, locale); 082 ResourceBundle bundle = null; 083 final String resourceName = toResourceName(bundleName, "properties"); 084 ListIterator<Class<?>> iter = clses.listIterator(clses.size()); 085 Properties props = new Properties(); 086 while (iter.hasPrevious()) { 087 Class<?> cls = iter.previous(); 088 @SuppressWarnings("PMD.CloseResource") 089 InputStream inStream = null; 090 if (reload) { 091 URL url = cls.getResource(resourceName); 092 if (url != null) { 093 URLConnection connection = url.openConnection(); 094 if (connection != null) { 095 // Disable caches to get fresh data for 096 // reloading. 097 connection.setUseCaches(false); 098 inStream = connection.getInputStream(); 099 } 100 } 101 } else { 102 inStream = cls.getResourceAsStream(resourceName); 103 } 104 if (inStream == null) { 105 continue; 106 } 107 props.load(inStream); 108 inStream.close(); 109 if (bundle == null) { 110 bundle = new ConsoleResourceBundle(props); 111 } 112 } 113 return bundle; 114 } 115}