From be1dff28aa3e38dfb44270f48b3cfb53c3490c9f Mon Sep 17 00:00:00 2001 From: Tom Morris Date: Tue, 10 Mar 2026 22:02:56 -0400 Subject: [PATCH] Switch from ExtendedProperties to PropertiesConfiguration Although not officially deprecateed the docs contain strong encouragement to switch to the newer implementation as soon as it was available --- main/pom.xml | 15 +- .../edu/mit/simile/butterfly/Butterfly.java | 145 +++++++++--------- .../mit/simile/butterfly/ButterflyModule.java | 6 +- .../simile/butterfly/ButterflyModuleImpl.java | 16 +- .../butterfly/ButterflyScriptableObject.java | 4 +- 5 files changed, 92 insertions(+), 94 deletions(-) diff --git a/main/pom.xml b/main/pom.xml index 4e88805..dc11fa9 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -9,10 +9,8 @@ butterfly-container 1.2.7-SNAPSHOT - - org.openrefine.dependencies + butterfly - 1.2.7-SNAPSHOT SIMILE Butterfly Engine https://github.com/OpenRefine/simile-butterfly/ @@ -81,9 +79,14 @@ - commons-collections - commons-collections - 3.2.2 + org.apache.commons + commons-collections4 + 4.4 + + + org.apache.commons + commons-configuration2 + 2.10.1 commons-io diff --git a/main/src/edu/mit/simile/butterfly/Butterfly.java b/main/src/edu/mit/simile/butterfly/Butterfly.java index e6ff843..390b1c2 100644 --- a/main/src/edu/mit/simile/butterfly/Butterfly.java +++ b/main/src/edu/mit/simile/butterfly/Butterfly.java @@ -36,7 +36,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ExtendedProperties; +import org.apache.commons.configuration2.AbstractConfiguration; +import org.apache.commons.configuration2.CombinedConfiguration; +import org.apache.commons.configuration2.PropertiesConfiguration; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.commons.configuration2.tree.OverrideCombiner; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.mozilla.javascript.Context; @@ -156,7 +160,7 @@ public static boolean isGAE(ServletConfig config) { transient protected ServletContext _context; transient protected ButterflyMounter _mounter; - protected ExtendedProperties _properties; + protected PropertiesConfiguration _properties; protected File _contextDir; protected File _homeDir; protected File _webInfDir; @@ -188,27 +192,17 @@ public void init(ServletConfig config) throws ServletException { _contextDir = new File(_context.getRealPath("/")); _webInfDir = new File(_contextDir, "WEB-INF"); - _properties = new ExtendedProperties(); + _properties = new PropertiesConfiguration(); _mounter = new ButterflyMounter(); // Load the butterfly properties String props = System.getProperty("butterfly.properties"); File butterflyProperties = (props == null) ? new File(_webInfDir, "butterfly.properties") : new File(props); - BufferedInputStream is = null; - try { - is = new BufferedInputStream(new FileInputStream(butterflyProperties)); - _properties.load(is); - } catch (FileNotFoundException e) { + try (BufferedInputStream is = new BufferedInputStream(Files.newInputStream(butterflyProperties.toPath()))){ + _properties.read(new InputStreamReader(is, StandardCharsets.UTF_8)); + } catch (IOException|ConfigurationException e) { throw new ServletException("Could not find butterfly properties file",e); - } catch (IOException e) { - throw new ServletException("Could not read butterfly properties file",e); - } finally { - try { - is.close(); - } catch (Exception e) { - // ignore - } } // Process eventual properties includes @@ -216,27 +210,20 @@ public void init(ServletConfig config) throws ServletException { if (includes != null) { for (String prop : includes.split(",")) { File prop_file = (prop.startsWith("/")) ? new File(prop) : new File(_webInfDir, prop); - try { - is = new BufferedInputStream(new FileInputStream(prop_file)); - ExtendedProperties p = new ExtendedProperties(); - p.load(is); - _properties.combine(p); - } catch (Exception e) { - // ignore - } finally { - try { - is.close(); - } catch (Exception e) { - // ignore - } + try (BufferedInputStream is = new BufferedInputStream(Files.newInputStream(prop_file.toPath()))){ + PropertiesConfiguration p = new PropertiesConfiguration(); + p.read(new InputStreamReader(is, StandardCharsets.UTF_8)); + _properties.append(p); + } catch (ConfigurationException | IOException e) { + _logger.warn("Error loading included properties file: " + prop_file, e); } } } // Overload with properties set from the command line // using the -Dkey=value parameters to the JVM Properties systemProperties = System.getProperties(); - for (Iterator i = systemProperties.keySet().iterator(); i.hasNext(); ) { - String key = (String) i.next(); + for (Object o : systemProperties.keySet()) { + String key = (String) o; String value = systemProperties.getProperty(key); _properties.setProperty(key, value); } @@ -326,8 +313,7 @@ public void configure() { } _logger.info("Butterfly home: {}", _homeDir); - Iterator i = _properties.getKeys(ZONE); - while (i.hasNext()) { + for(Iterator i = _properties.getKeys(ZONE); i.hasNext(); ) { String zone = i.next(); String path = _properties.getString(zone); zone = zone.substring(ZONE.length() + 1); @@ -373,7 +359,7 @@ public void configure() { _logger.info("> load modules"); // load modules from the properties found in the butterfly.properties - List paths = _properties.getList(MODULES_PATH); + List paths = _properties.getList(String.class, MODULES_PATH); for (String path : paths) { findModulesIn(absolutize(_homeDir, path.trim())); } @@ -394,16 +380,15 @@ public void configure() { _logger.info("< create modules"); _logger.info("> load module wirings"); - ExtendedProperties wirings = new ExtendedProperties(); - try { - // Load the wiring properties - File moduleWirings = absolutize(_homeDir, _properties.getString("butterfly.modules.wirings","WEB-INF/modules.properties")); - _logger.info("Loaded module wirings from: {}", moduleWirings); - _classLoader.watch(moduleWirings); // reload if the module wirings change - FileInputStream fis = new FileInputStream(moduleWirings); - wirings.load(fis); - fis.close(); - } catch (Exception e) { + PropertiesConfiguration wirings = new PropertiesConfiguration(); + + // Load the wiring properties + File moduleWirings = absolutize(_homeDir, _properties.getString("butterfly.modules.wirings","WEB-INF/modules.properties")); + _logger.info("Loaded module wirings from: {}", moduleWirings); + _classLoader.watch(moduleWirings); // reload if the module wirings change + try (FileInputStream fis = new FileInputStream(moduleWirings)) { + wirings.read(new InputStreamReader(fis, StandardCharsets.UTF_8)); + } catch (IOException | ConfigurationException e) { _configurationException = new Exception("Failed to load module wirings", e); } _logger.info("< load module wirings"); @@ -526,7 +511,7 @@ public void service(HttpServletRequest request, HttpServletResponse response) th protected Map _modulesByName = new HashMap(); protected Map> _modulesByInterface = new HashMap>(); - protected Map _moduleProperties = new HashMap(); + protected Map _moduleProperties = new HashMap(); protected Map _created = new HashMap(); final static private String routingCookie = "host"; @@ -573,13 +558,13 @@ protected void findModulesIn(File f) { try { String name = f.getName(); - ExtendedProperties p = new ExtendedProperties(); + PropertiesConfiguration p = new PropertiesConfiguration(); File propFile = new File(modFile,"module.properties"); if (propFile.exists()) { - _classLoader.watch(propFile); // reload if the the module properties change - BufferedInputStream stream = new BufferedInputStream(new FileInputStream(propFile)); - p.load(stream); - stream.close(); + _classLoader.watch(propFile); // reload if the module properties change + try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(propFile.toPath()))) { + p.read(new InputStreamReader(stream, StandardCharsets.UTF_8)); + } } p.addProperty(PATH_PROP, f.getAbsolutePath()); @@ -624,7 +609,7 @@ protected ButterflyModule createModule(String name) { return _modulesByName.get(name); } - ExtendedProperties p = _moduleProperties.get(name); + AbstractConfiguration p = _moduleProperties.get(name); File path = new File(p.getString(PATH_PROP)); _logger.debug("Module path: {}", path); @@ -685,8 +670,7 @@ protected ButterflyModule createModule(String name) { return m; } - @SuppressWarnings("unchecked") - protected void wireModules(ExtendedProperties wirings) { + protected void wireModules(PropertiesConfiguration wirings) { _logger.trace("> wireModules()"); _logger.info("mounting modules"); @@ -714,21 +698,32 @@ protected void wireModules(ExtendedProperties wirings) { for (String name : _moduleProperties.keySet()) { _logger.trace("> Expanding properties for module: {}", name); ButterflyModule m = _modulesByName.get(name); - ExtendedProperties p = _moduleProperties.get(name); ButterflyModule extended = m.getExtendedModule(); + // Highest priority properties need to be added first, so we need to collect them all first + List propertiesList = new ArrayList<>(); + propertiesList.add(_moduleProperties.get(name)); while (extended != null) { _logger.trace("> Merging properties from extended module: {}", name); - ExtendedProperties temp = p; - p = _moduleProperties.get(extended.getName()); - p.combine(temp); + AbstractConfiguration p = _moduleProperties.get(extended.getName()); + propertiesList.add(p); _logger.trace("< Merging properties from extended module: {} -> {}", name, p); extended = extended.getExtendedModule(); } + AbstractConfiguration p; + if (propertiesList.size() == 1) { + p = propertiesList.get(0); + } else { + p = new CombinedConfiguration(new OverrideCombiner()); + // Add files in reverse order to maintain priority + for (int i = propertiesList.size() - 1; i >= 0; i--) { + ((CombinedConfiguration) p).addConfiguration(propertiesList.get(i)); + } + } - _moduleProperties.put(name,p); + _moduleProperties.put(name, p); - List implementations = p.getList(implementsProperty); + List implementations = p.getList(String.class, implementsProperty); if (implementations != null) { for (String i : implementations) { Map map = _modulesByInterface.get(i); @@ -745,11 +740,11 @@ protected void wireModules(ExtendedProperties wirings) { for (String name : _moduleProperties.keySet()) { _logger.trace("> Inject dependencies in module: {}", name); - ExtendedProperties p = _moduleProperties.get(name); + AbstractConfiguration p = _moduleProperties.get(name); ButterflyModule m = _modulesByName.get(name); - for (Object o : p.keySet()) { - String s = (String) o; + for (Iterator keys = p.getKeys(); keys.hasNext(); ) { + String s = keys.next(); if (s.equals(dependencyPrefix)) { for (Object oo : p.getList(s)) { String dep = (String) oo; @@ -800,12 +795,12 @@ protected void wireModules(ExtendedProperties wirings) { _logger.trace("< wireModules()"); } - @SuppressWarnings("unchecked") + protected void configureModules() { _logger.trace("> configureModules()"); for (String name : _moduleProperties.keySet()) { _logger.trace("> Configuring module: {}", name); - ExtendedProperties p = _moduleProperties.get(name); + AbstractConfiguration p = _moduleProperties.get(name); ButterflyModule m = _modulesByName.get(name); // make the system properties accessible to the modules @@ -818,16 +813,16 @@ protected void configureModules() { Properties properties = new Properties(); File velocityProperties = new File(_webInfDir, "velocity.properties"); _classLoader.watch(velocityProperties); // reload if the velocity properties change - FileInputStream fis = new FileInputStream(velocityProperties); - properties.load(fis); - fis.close(); + try (FileInputStream fis = new FileInputStream(velocityProperties)) { + properties.load(fis); + } // set properties for resource loading - properties.setProperty("resource.loader", "butterfly"); - properties.setProperty("butterfly.resource.loader.class", ButterflyResourceLoader.class.getName()); - properties.setProperty("butterfly.resource.loader.cache", "true"); - properties.setProperty("butterfly.resource.loader.modificationCheckInterval", "1"); - properties.setProperty("butterfly.resource.loader.description", "Butterfly Resource Loader"); + properties.setProperty("resource.loaders", "butterfly"); + properties.setProperty("resource.loader.butterfly.class", ButterflyResourceLoader.class.getName()); + properties.setProperty("resource.loader.butterfly.cache", "true"); + properties.setProperty("resource.loader.butterfly.modification_check_interval", "1"); + properties.setProperty("resource.loader.butterfly.description", "Butterfly Resource Loader"); // set properties for macros properties.setProperty("velocimacro.library.path", p.getString("templating.macros", "")); @@ -854,8 +849,8 @@ protected void configureModules() { _logger.trace("< enabling templating"); } - List scriptables = p.getList("scriptables"); - if (scriptables.size() > 0) { + List scriptables = p.getList(String.class, "scriptables"); + if (scriptables != null && !scriptables.isEmpty()) { Context context = Context.enter(); BufferedReader initializerReader = null; @@ -887,7 +882,7 @@ protected void configureModules() { Context.exit(); } - List controllers = p.getList("controller", CONTROLLER); + List controllers = p.getList(String.class, "controller", CONTROLLER); Set controllerURLs = new HashSet(controllers.size()); for (String controller : controllers) { URL controllerURL = m.getResource("MOD-INF/" + controller); diff --git a/main/src/edu/mit/simile/butterfly/ButterflyModule.java b/main/src/edu/mit/simile/butterfly/ButterflyModule.java index 68b8869..fc8a64b 100644 --- a/main/src/edu/mit/simile/butterfly/ButterflyModule.java +++ b/main/src/edu/mit/simile/butterfly/ButterflyModule.java @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ExtendedProperties; +import org.apache.commons.configuration2.FileBasedConfiguration; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.mozilla.javascript.Context; @@ -65,7 +65,7 @@ public interface ButterflyModule { public void setTemplateEngine(VelocityEngine velocity); - public void setProperties(ExtendedProperties properties); + public void setProperties(FileBasedConfiguration properties); public void setTimer(Timer timer); @@ -77,7 +77,7 @@ public interface ButterflyModule { public String getName(); - public ExtendedProperties getProperties(); + public FileBasedConfiguration getProperties(); public File getPath(); diff --git a/main/src/edu/mit/simile/butterfly/ButterflyModuleImpl.java b/main/src/edu/mit/simile/butterfly/ButterflyModuleImpl.java index b6cc49a..7645c7a 100644 --- a/main/src/edu/mit/simile/butterfly/ButterflyModuleImpl.java +++ b/main/src/edu/mit/simile/butterfly/ButterflyModuleImpl.java @@ -32,10 +32,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ExtendedProperties; -import org.apache.commons.collections.OrderedMap; -import org.apache.commons.collections.OrderedMapIterator; -import org.apache.commons.collections.map.ListOrderedMap; +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.map.ListOrderedMap; +import org.apache.commons.configuration2.FileBasedConfiguration; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.velocity.VelocityContext; @@ -76,7 +76,7 @@ public class ButterflyModuleImpl implements ButterflyModule { protected Set _extendedBy = new LinkedHashSet(); protected Set _implementations = new LinkedHashSet(); protected Map _dependencies = new HashMap(); - protected ExtendedProperties _properties; + protected FileBasedConfiguration _properties; protected Map _modules; protected VelocityEngine _templateEngine; protected OrderedMap _scripts = new ListOrderedMap(); @@ -170,7 +170,7 @@ public void setTemplateEngine(VelocityEngine templateEngine) { this._templateEngine = templateEngine; } - public void setProperties(ExtendedProperties properties) { + public void setProperties(FileBasedConfiguration properties) { _logger.trace("{} gets loaded with properties", this); this._properties = properties; } @@ -206,7 +206,7 @@ public File getPath() { return this._path; } - public ExtendedProperties getProperties() { + public FileBasedConfiguration getProperties() { return this._properties; } @@ -585,7 +585,7 @@ public void initScope(Context context, Scriptable scope) { m.initScope(context, scope); } - OrderedMapIterator i = _scripts.orderedMapIterator(); + OrderedMapIterator i = _scripts.mapIterator(); while (i.hasNext()) { URL url = (URL) i.next(); _logger.debug("Executing script: {}", url); diff --git a/main/src/edu/mit/simile/butterfly/ButterflyScriptableObject.java b/main/src/edu/mit/simile/butterfly/ButterflyScriptableObject.java index 9249e4c..72c3103 100644 --- a/main/src/edu/mit/simile/butterfly/ButterflyScriptableObject.java +++ b/main/src/edu/mit/simile/butterfly/ButterflyScriptableObject.java @@ -1,6 +1,6 @@ package edu.mit.simile.butterfly; -import org.apache.commons.collections.ExtendedProperties; +import org.apache.commons.configuration2.FileBasedConfiguration; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; @@ -16,7 +16,7 @@ public abstract class ButterflyScriptableObject extends ScriptableObject { private static final long serialVersionUID = 6392807122149170350L; protected ButterflyModule _module; - protected ExtendedProperties _properties; + protected FileBasedConfiguration _properties; public void init(ButterflyModule module) { _module = module;