From cf688c653a3394c56c94eca43749d09ce91f2d05 Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 15:12:00 -0500 Subject: [PATCH 1/8] Updating to Java 21. --- olcut-config-edn/pom.xml | 9 +------- olcut-config-protobuf/pom.xml | 11 ++------- olcut-core/pom.xml | 6 ++--- olcut-core/src/main/java/module-info.java | 7 +++++- olcut-extras/pom.xml | 4 ++-- pom.xml | 27 +++++++++++------------ 6 files changed, 27 insertions(+), 37 deletions(-) diff --git a/olcut-config-edn/pom.xml b/olcut-config-edn/pom.xml index 19f9a524..d72ae18f 100644 --- a/olcut-config-edn/pom.xml +++ b/olcut-config-edn/pom.xml @@ -87,14 +87,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 - - - - com.oracle.labs.mlrg.olcut.config.edn - - - + 3.4.2 diff --git a/olcut-config-protobuf/pom.xml b/olcut-config-protobuf/pom.xml index e3f06465..a3080ed5 100644 --- a/olcut-config-protobuf/pom.xml +++ b/olcut-config-protobuf/pom.xml @@ -87,19 +87,12 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 - - - - com.oracle.labs.mlrg.olcut.config.protobuf - - - + 3.4.2 org.apache.maven.plugins maven-assembly-plugin - 3.4.2 + 3.7.1 jar-with-dependencies diff --git a/olcut-core/pom.xml b/olcut-core/pom.xml index 14574aeb..533c5ed9 100644 --- a/olcut-core/pom.xml +++ b/olcut-core/pom.xml @@ -78,7 +78,7 @@ org.codehaus.mojo templating-maven-plugin - 1.0.0 + 3.0.0 filtering-java-templates @@ -91,7 +91,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 @@ -103,7 +103,7 @@ org.apache.maven.plugins maven-assembly-plugin - 3.4.2 + 3.7.1 jar-with-dependencies diff --git a/olcut-core/src/main/java/module-info.java b/olcut-core/src/main/java/module-info.java index 6500e38f..937b07f4 100644 --- a/olcut-core/src/main/java/module-info.java +++ b/olcut-core/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -26,6 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/** + * Core OLCUT module containing the command shell, configuration, options, provenance systems and core utilities. + *

+ * Code which uses the configuration system should open its module to {@code com.oracle.labs.mlrg.olcut.core}. + */ module com.oracle.labs.mlrg.olcut.core { requires java.base; requires java.logging; diff --git a/olcut-extras/pom.xml b/olcut-extras/pom.xml index 48673845..1fff7e27 100644 --- a/olcut-extras/pom.xml +++ b/olcut-extras/pom.xml @@ -44,7 +44,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 @@ -56,7 +56,7 @@ org.apache.maven.plugins maven-assembly-plugin - 3.4.2 + 3.7.1 diff --git a/pom.xml b/pom.xml index f9665f00..0fe7a16c 100644 --- a/pom.xml +++ b/pom.xml @@ -37,9 +37,9 @@ 6.0.0-SNAPSHOT UTF-8 - 17 - 17 - 17 + 21 + 21 + 21 0.7.1 2.18.0 2.18.0 @@ -173,11 +173,11 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M8 + 3.5.2 maven-deploy-plugin - 3.0.0 + 3.1.3 @@ -185,7 +185,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.2.1 + 3.5.0 enforce-maven @@ -205,7 +205,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.11.2 public false @@ -216,10 +216,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.13.0 - 17 - 17 + 21 + 21 -Xlint:unchecked @@ -233,7 +233,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.1.0 + 1.6.0 true resolveCiFriendliesOnly @@ -258,13 +258,12 @@ org.apache.maven.plugins maven-deploy-plugin - 3.0.0 + 3.1.3 - org.apache.maven.plugins maven-site-plugin - 3.9.1 + 3.21.0 From 000a1f428815925aee5ed21bb373d63da562ed71 Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 17:33:07 -0500 Subject: [PATCH 2/8] Removing deprecated features. - Removed Jini related component attributes. - Removed Java Security Manager related calls. - Removed Random config field. - Removed use of AccessibleObject.isAccessible. --- README.md | 2 +- .../olcut/config/edn/ClassnameMapper.java | 4 +- .../olcut/config/edn/EdnConfigFactory.java | 4 +- .../olcut/config/edn/EdnConfigWriter.java | 10 +- .../labs/mlrg/olcut/config/edn/EdnLoader.java | 83 ++-- .../olcut/config/json/JsonConfigFactory.java | 4 +- .../olcut/config/json/JsonConfigWriter.java | 18 +- .../mlrg/olcut/config/json/JsonLoader.java | 103 ++--- .../config/protobuf/ProtoConfigWriter.java | 14 +- .../olcut/config/protobuf/ProtoLoader.java | 66 ++-- .../protobuf/ProtoTxtConfigFactory.java | 1 - .../src/main/resources/olcut_proto.proto | 8 +- .../config_tests/ArgumentParsingTest.java | 8 - .../config_tests/ConfigurationDataTest.java | 4 - .../ConfigurationManagerTest.java | 6 - .../config_tests/TypedProcessorsTest.java | 1 - .../provenance_tests/ProvenanceUtilTest.java | 1 - .../test/config_tests/singletonConfig.xml | 3 - .../mlrg/olcut/config/ArgumentException.java | 9 +- .../mlrg/olcut/config/ComponentListener.java | 6 +- .../oracle/labs/mlrg/olcut/config/Config.java | 2 +- .../labs/mlrg/olcut/config/ConfigManager.java | 4 +- .../mlrg/olcut/config/ConfigurableName.java | 2 +- .../mlrg/olcut/config/ConfigurationData.java | 160 ++------ .../olcut/config/ConfigurationManager.java | 353 +++++++++--------- .../olcut/config/DescribeConfigurable.java | 22 +- .../labs/mlrg/olcut/config/FieldType.java | 8 +- .../InternalConfigurationException.java | 6 +- .../oracle/labs/mlrg/olcut/config/Option.java | 25 +- .../labs/mlrg/olcut/config/Options.java | 222 +++++------ .../mlrg/olcut/config/PropertyException.java | 2 +- .../labs/mlrg/olcut/config/PropertySheet.java | 233 ++++++------ .../mlrg/olcut/config/SerializedObject.java | 68 ++-- .../mlrg/olcut/config/UsageException.java | 10 +- .../mlrg/olcut/config/io/ConfigLoader.java | 4 +- .../config/io/ConfigLoaderException.java | 15 +- .../config/io/ConfigWriterException.java | 6 +- .../olcut/config/io/FileFormatFactory.java | 22 +- .../labs/mlrg/olcut/config/io/URLLoader.java | 8 +- .../config/property/GlobalProperties.java | 6 +- .../labs/mlrg/olcut/config/xml/SAXLoader.java | 68 +--- .../olcut/config/xml/XMLConfigWriter.java | 16 - .../mlrg/olcut/provenance/ProvenanceUtil.java | 5 +- .../SkeletalConfiguredObjectProvenance.java | 20 +- .../oracle/labs/mlrg/olcut/util/IOUtil.java | 12 +- .../mlrg/olcut/util/LabsLogFormatter.java | 28 +- .../olcut/util/SimpleLabsLogFormatter.java | 27 +- .../labs/mlrg/olcut/util/StopWatch.java | 4 + .../mlrg/olcut/config/BooleanOptionTest.java | 4 +- .../labs/mlrg/olcut/config/OptionsTest.java | 14 +- 50 files changed, 742 insertions(+), 989 deletions(-) diff --git a/README.md b/README.md index 3cc8672a..279e50b3 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,6 @@ Please consult the [security guide](./SECURITY.md) for our responsible security ## License -Copyright (c) 2017, 2023 Oracle and/or its affiliates. +Copyright (c) 2017, 2025 Oracle and/or its affiliates. Released under the BSD 2-Clause License diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/ClassnameMapper.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/ClassnameMapper.java index dda543d9..21c17635 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/ClassnameMapper.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/ClassnameMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -38,7 +38,7 @@ public class ClassnameMapper { - private Map prefixes; + private final Map prefixes; public ClassnameMapper(Map prefixes) { this.prefixes = prefixes; diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigFactory.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigFactory.java index 90fe6737..752e5227 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigFactory.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -43,6 +43,8 @@ public class EdnConfigFactory implements FileFormatFactory { + public EdnConfigFactory() {} + @Override public String getExtension() { return "edn"; diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java index 9588fed5..dfd3e324 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -55,10 +55,10 @@ public class EdnConfigWriter implements ConfigWriter { - private Printer printer; - private List struct; - private ClassnameMapper cnMapper; - private static final Set COMPONENT_MODIFIERS = new HashSet<>(Arrays.asList(ConfigLoader.IMPORT, ConfigLoader.EXPORT, ConfigLoader.ENTRIES, ConfigLoader.LEASETIME, ConfigLoader.SERIALIZED)); + private final Printer printer; + private final List struct; + private final ClassnameMapper cnMapper; + private static final Set COMPONENT_MODIFIERS = new HashSet<>(List.of(ConfigLoader.SERIALIZED)); public EdnConfigWriter(OutputStream os) { this.printer = new OlcutEdnPrinter(new OutputStreamWriter(os, StandardCharsets.UTF_8)); diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java index 3670aca4..7199d8b5 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -55,8 +55,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -68,7 +66,7 @@ public class EdnLoader implements ConfigLoader { private static final Logger logger = Logger.getLogger(EdnLoader.class.getName()); - private ClassnameMapper cnMapper; + private final ClassnameMapper cnMapper; private static List rest(List l) { return l.subList(1, l.size()); @@ -151,7 +149,6 @@ private static long checkLong(Object o) throws ConfigLoaderException { } } - private final URLLoader parent; private final Map rpdMap; private final Map existingRPD; @@ -171,25 +168,20 @@ public EdnLoader(URLLoader parent, Map rpdMap, Map) - () -> { - if (url.getProtocol().equals("file")) { - workingDir = new File(url.getFile()).getParent(); - } else if (IOUtil.isDisallowedProtocol(url)) { - throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); - } else { - workingDir = ""; - } - try { - innerLoad(url.openStream()); - } catch (EdnException e) { - throw new ConfigLoaderException(e, "Edn failed to parse url: " + url.toString()); - } catch (IOException e) { - throw new ConfigLoaderException(e, "Failed to load url: " + url.toString()); - } - return null; - } - ); + if (url.getProtocol().equals("file")) { + workingDir = new File(url.getFile()).getParent(); + } else if (IOUtil.isDisallowedProtocol(url)) { + throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); + } else { + workingDir = ""; + } + try { + innerLoad(url.openStream()); + } catch (EdnException e) { + throw new ConfigLoaderException(e, "Edn failed to parse url: " + url.toString()); + } catch (IOException e) { + throw new ConfigLoaderException(e, "Failed to load url: " + url.toString()); + } } @Override @@ -212,13 +204,11 @@ private void innerLoad(InputStream stream) throws EdnException { private void parseEdn(Parseable in) { Parser p = Parsers.newParser(Parsers.defaultConfiguration()); Object parseValue = p.nextValue(in); - if (parseValue instanceof List) { - List config = (List) parseValue; - if(checkSymbol(config.get(0)).equals(ConfigLoader.CONFIG)) { + if (parseValue instanceof List config) { + if(checkSymbol(config.getFirst()).equals(ConfigLoader.CONFIG)) { for(Object configObj : rest(config)) { - if(configObj instanceof List) { - List configListItem = (List) configObj; - switch (checkSymbol(configListItem.get(0))) { + if(configObj instanceof List configListItem) { + switch (checkSymbol(configListItem.getFirst())) { case FILE: parseFile(rest(configListItem)); break; @@ -296,7 +286,7 @@ private void parseFile(List fileListItem) { private void parseComponents(List componentsListItem) { int i = 1; boolean hasMap = false; - if(componentsListItem.get(0) instanceof Map) { + if(componentsListItem.getFirst() instanceof Map) { i++; hasMap = true; } @@ -314,15 +304,14 @@ private void parseComponents(List componentsListItem) { } for(; i) { - List l = (List) o; + if(o instanceof List l) { int lStart = 1; List formed = new ArrayList<>(); - formed.add(l.get(0)); // name element + formed.add(l.getFirst()); // name element formed.add(componentsListItem.get(hasMap ? 1 : 0)); // type element Map m = new HashMap<>(); if(hasMap) { - m.putAll((Map) componentsListItem.get(0)); + m.putAll((Map) componentsListItem.getFirst()); } if(l.size() > 1 && l.get(1) instanceof Map) { m.putAll((Map) l.get(1)); @@ -348,11 +337,7 @@ private void parseComponent(List componentListItem) { int propsStart = 2; ConfigurationData rpd = new ConfigurationData(name, type); - boolean importable = false; - boolean exportable = false; String override = null; - long leaseTime = ConfigurationData.DEFAULT_LEASE_TIME; - String entriesName = null; String serializedForm = null; if(componentListItem.get(2) instanceof Map) { @@ -362,22 +347,6 @@ private void parseComponent(List componentListItem) { if(modMap.containsKey(ConfigLoader.INHERIT)) { override = checkSymbolOrString(modMap.get(ConfigLoader.INHERIT)); } - if(modMap.containsKey(ConfigLoader.IMPORT)) { - importable = checkBoolean(modMap.get(ConfigLoader.IMPORT)); - } - if(modMap.containsKey(ConfigLoader.EXPORT)) { - exportable = checkBoolean(modMap.get(ConfigLoader.EXPORT)); - } - if(modMap.containsKey(ConfigLoader.LEASETIME)) { - if(!exportable) { - throw new ConfigLoaderException("lease timeout " + leaseTime + - " specified for component that does not have export set, at " + modMap.toString()); - } - leaseTime = checkLong(modMap.get(ConfigLoader.LEASETIME)); - } - if(modMap.containsKey(ConfigLoader.ENTRIES)) { - entriesName = modMap.get(ConfigLoader.ENTRIES).toString(); - } if(modMap.containsKey(ConfigLoader.SERIALIZED)) { serializedForm = modMap.get(ConfigLoader.SERIALIZED).toString(); } @@ -398,13 +367,13 @@ private void parseComponent(List componentListItem) { logger.log(Level.FINE, String.format("Overriding component %s with component %s, new type is %s overridden type was %s", spd.getName(), name , type, spd.getClassName())); } - rpd = new ConfigurationData(name, type, spd.getProperties(), serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(name, type, spd.getProperties(), serializedForm); } else { if (rpdMap.get(name) != null) { throw new ConfigLoaderException("duplicate definition for " + name); } - rpd = new ConfigurationData(name, type, serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(name, type, serializedForm); } propsStart = 3; } diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigFactory.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigFactory.java index 36d20f8e..8ec96a63 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigFactory.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigFactory.java @@ -46,9 +46,9 @@ import java.util.Map; /** - * + * Configuration factory for reading and writing json format configuration files. */ -public class JsonConfigFactory implements FileFormatFactory { +public final class JsonConfigFactory implements FileFormatFactory { private final JsonFactory factory = new JsonFactory(); diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java index 34456bda..55199d9d 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -43,12 +43,16 @@ import java.util.Map.Entry; /** - * + * A {@link ConfigWriter} for json format config files. */ -public class JsonConfigWriter implements ConfigWriter { +public final class JsonConfigWriter implements ConfigWriter { private final JsonGenerator writer; + /** + * Constructs a JsonConfigWriter from the supplied JsonGenerator. + * @param writer The json generator. + */ public JsonConfigWriter(JsonGenerator writer) { this.writer = writer; } @@ -122,14 +126,6 @@ public void writeComponent(Map attributes, Map writer.writeStartObject(); writer.writeStringField(ConfigLoader.NAME, attributes.get(ConfigLoader.NAME)); writer.writeStringField(ConfigLoader.TYPE, attributes.get(ConfigLoader.TYPE)); - writer.writeStringField(ConfigLoader.EXPORT, attributes.get(ConfigLoader.EXPORT)); - writer.writeStringField(ConfigLoader.IMPORT, attributes.get(ConfigLoader.IMPORT)); - if (attributes.containsKey(ConfigLoader.ENTRIES)) { - writer.writeStringField(ConfigLoader.ENTRIES, attributes.get(ConfigLoader.ENTRIES)); - } - if (attributes.containsKey(ConfigLoader.LEASETIME)) { - writer.writeStringField(ConfigLoader.LEASETIME, attributes.get(ConfigLoader.LEASETIME)); - } if (attributes.containsKey(ConfigLoader.SERIALIZED)) { writer.writeStringField(ConfigLoader.SERIALIZED, attributes.get(ConfigLoader.SERIALIZED)); } diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java index 0ecc3da1..374d9f61 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -52,8 +52,6 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -63,9 +61,9 @@ import java.util.logging.Logger; /** - * + * A {@link ConfigLoader} for configuration data stored in json format. */ -public class JsonLoader implements ConfigLoader { +public final class JsonLoader implements ConfigLoader { private static final Logger logger = Logger.getLogger(JsonLoader.class.getName()); @@ -83,6 +81,15 @@ public class JsonLoader implements ConfigLoader { private String workingDir; + /** + * Constructs a configuration loader for JSON formatted data. + * @param factory The JsonFactory to use. + * @param parent The parent URL loader for chaining. + * @param rpdMap The current property map. + * @param existingRPD Any existing property maps. + * @param serializedObjects The existing serialized objects. + * @param globalProperties The existing global properties. + */ public JsonLoader(JsonFactory factory, URLLoader parent, Map rpdMap, Map existingRPD, Map serializedObjects, GlobalProperties globalProperties) { this.factory = factory; @@ -97,26 +104,21 @@ public JsonLoader(JsonFactory factory, URLLoader parent, Map) - () -> { - if (url.getProtocol().equals("file")) { - workingDir = new File(url.getFile()).getParent(); - } else if (IOUtil.isDisallowedProtocol(url)) { - throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); - } else { - workingDir = ""; - } - try (JsonParser parser = factory.createParser(url)) { - parser.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); - parseJson(parser); - } catch (IOException e) { - String msg = "Error while parsing " + url.toString() + ": " + e.getMessage(); - throw new ConfigLoaderException(e, msg); - } - return null; - } - ); + public void load(URL url) throws ConfigLoaderException { + if (url.getProtocol().equals("file")) { + workingDir = new File(url.getFile()).getParent(); + } else if (IOUtil.isDisallowedProtocol(url)) { + throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); + } else { + workingDir = ""; + } + try (JsonParser parser = factory.createParser(url)) { + parser.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); + parseJson(parser); + } catch (IOException e) { + String msg = "Error while parsing " + url.toString() + ": " + e.getMessage(); + throw new ConfigLoaderException(e, msg); + } } /** @@ -133,19 +135,7 @@ public void load(InputStream stream) throws ConfigLoaderException { } } - public Map getPropertyMap() { - return rpdMap; - } - - public Map getSerializedObjects() { - return serializedObjects; - } - - public GlobalProperties getGlobalProperties() { - return globalProperties; - } - - protected void parseJson(JsonParser parser) { + private void parseJson(JsonParser parser) { ObjectMapper mapper = new ObjectMapper(); try { parser.nextToken(); // now currentToken == START_OBJECT @@ -194,7 +184,7 @@ protected void parseJson(JsonParser parser) { } } - protected void parseComponent(ObjectNode node) { + private void parseComponent(ObjectNode node) { boolean overriding = false; JsonNode curComponentNode = node.get(ConfigLoader.NAME); JsonNode curTypeNode = node.get(ConfigLoader.TYPE); @@ -209,30 +199,6 @@ protected void parseComponent(ObjectNode node) { String curType = curTypeNode != null ? curTypeNode.textValue() : null; String override = overrideNode != null ? overrideNode.textValue() : null; - JsonNode export = node.get(ConfigLoader.EXPORT); - boolean exportable = export != null && Boolean.parseBoolean(export.textValue()); - JsonNode impNode = node.get(ConfigLoader.IMPORT); - boolean importable = impNode != null && Boolean.parseBoolean(impNode.textValue()); - JsonNode lt = node.get(ConfigLoader.LEASETIME); - if (export == null && lt != null) { - throw new ConfigLoaderException("lease timeout " + lt + - " specified for component that does not have export set, at node " + node.toString()); - } - long leaseTime = ConfigurationData.DEFAULT_LEASE_TIME; - if (lt != null) { - try { - leaseTime = Long.parseLong(lt.textValue()); - if (leaseTime < 0) { - throw new ConfigLoaderException("lease timeout " - + lt + " must be greater than 0, for component " + curComponent); - } - } catch (NumberFormatException nfe) { - throw new ConfigLoaderException("lease timeout " - + lt + " must be a long, for component " + curComponent); - } - } - JsonNode entriesNameNode = node.get(ConfigLoader.ENTRIES); - String entriesName = entriesNameNode != null ? entriesNameNode.textValue() : null; JsonNode serializedFormNode = node.get(ConfigLoader.SERIALIZED); String serializedForm = serializedFormNode != null ? serializedFormNode.textValue() : null; @@ -261,14 +227,14 @@ protected void parseComponent(ObjectNode node) { if (curType == null) { curType = spd.getClassName(); } - rpd = new ConfigurationData(curComponent, curType, spd.getProperties(), serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(curComponent, curType, spd.getProperties(), serializedForm); overriding = true; } else { if (rpdMap.get(curComponent) != null) { throw new ConfigLoaderException("duplicate definition for " + curComponent); } - rpd = new ConfigurationData(curComponent, curType, serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(curComponent, curType, serializedForm); } ObjectNode properties = (ObjectNode) node.get(ConfigLoader.PROPERTIES); @@ -278,11 +244,10 @@ protected void parseComponent(ObjectNode node) { while (fieldsItr.hasNext()) { Entry e = fieldsItr.next(); String propName = e.getKey(); - if (e.getValue() instanceof ArrayNode) { + if (e.getValue() instanceof ArrayNode listNode) { // Must be list ArrayList listOutput = new ArrayList<>(); ArrayList> classListOutput = new ArrayList<>(); - ArrayNode listNode = (ArrayNode) e.getValue(); for (JsonNode element : listNode) { if (element.size() > 1) { throw new ConfigLoaderException("Too many elements in a propertylist item, found " + element); @@ -349,7 +314,7 @@ protected void parseComponent(ObjectNode node) { rpdMap.put(rpd.getName(),rpd); } - protected void parseFile(ObjectNode node) { + private void parseFile(ObjectNode node) { JsonNode name = node.get(ConfigLoader.NAME); JsonNode value = node.get(ConfigLoader.VALUE); if (name == null || value == null) { @@ -372,7 +337,7 @@ protected void parseFile(ObjectNode node) { } } - protected void parseSerializedObject(ObjectNode node) { + private void parseSerializedObject(ObjectNode node) { JsonNode name = node.get(ConfigLoader.NAME); JsonNode type = node.get(ConfigLoader.TYPE); JsonNode location = node.get(ConfigLoader.LOCATION); diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java index ba8a6e25..b2c8ee89 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -106,18 +106,6 @@ public void writeComponent(Map attributes, Map ComponentProto.Builder componentBuilder = ComponentProto.newBuilder(); componentBuilder.setName(attributes.get(ConfigLoader.NAME)); componentBuilder.setType(attributes.get(ConfigLoader.TYPE)); - if (attributes.get(ConfigLoader.EXPORT).equalsIgnoreCase("true")) { - componentBuilder.setExportable(true); - } - if (attributes.get(ConfigLoader.IMPORT).equalsIgnoreCase("true")) { - componentBuilder.setImportable(true); - } - if (attributes.containsKey(ConfigLoader.ENTRIES)) { - componentBuilder.setEntries(attributes.get(ConfigLoader.ENTRIES)); - } - if (attributes.containsKey(ConfigLoader.LEASETIME)) { - componentBuilder.setLeaseTime(Long.parseLong(attributes.get(ConfigLoader.LEASETIME))); - } if (attributes.containsKey(ConfigLoader.SERIALIZED)) { componentBuilder.setSerialized(attributes.get(ConfigLoader.SERIALIZED)); } diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java index 27a02351..b892ca10 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -56,8 +56,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -66,7 +64,7 @@ import java.util.logging.Logger; /** - * A loader for configuration data stored in protobuf format. + * A {@link ConfigLoader} for configuration data stored in protobuf format. */ public final class ProtoLoader implements ConfigLoader { @@ -107,31 +105,26 @@ public ProtoLoader(URLLoader parent, Map rpdMap, @Override public void load(URL url) throws ConfigLoaderException { - AccessController.doPrivileged((PrivilegedAction) - () -> { - String workingDir = ""; - if (url.getProtocol().equals("file")) { - workingDir = new File(url.getFile()).getParent(); - } else if (IOUtil.isDisallowedProtocol(url)) { - throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); - } - try (InputStream is = url.openStream()) { - ConfigProto proto; - if (parseTextFormat) { - ConfigProto.Builder protoBuilder = ConfigProto.newBuilder(); - BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); - TextFormat.getParser().merge(reader,protoBuilder); - proto = protoBuilder.build(); - } else { - proto = ConfigProto.parseFrom(is); - } - parseConfigProto(workingDir,proto); - } catch (IOException e) { - throw new ConfigLoaderException(e, e.getMessage()); - } - return null; - } - ); + String workingDir = ""; + if (url.getProtocol().equals("file")) { + workingDir = new File(url.getFile()).getParent(); + } else if (IOUtil.isDisallowedProtocol(url)) { + throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); + } + try (InputStream is = url.openStream()) { + ConfigProto proto; + if (parseTextFormat) { + ConfigProto.Builder protoBuilder = ConfigProto.newBuilder(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + TextFormat.getParser().merge(reader, protoBuilder); + proto = protoBuilder.build(); + } else { + proto = ConfigProto.parseFrom(is); + } + parseConfigProto(workingDir, proto); + } catch (IOException e) { + throw new ConfigLoaderException(e, e.getMessage()); + } } @Override @@ -223,17 +216,6 @@ private void parseComponentProto(ComponentProto component) { + "'name' and either 'type' or 'inherit' attributes, found " + component); } - boolean exportable = component.getExportable(); - boolean importable = component.getImportable(); - if (!exportable && component.hasLeaseTime()) { - throw new ConfigLoaderException("lease timeout " + component.getLeaseTime() + - " specified for component '" + name + "' that does not have export set"); - } else if (component.hasLeaseTime() && component.getLeaseTime() < 0) { - throw new ConfigLoaderException("lease timeout " - + component.getLeaseTime() + " must be greater than 0, for component " + name); - } - long leaseTime = component.hasLeaseTime() ? component.getLeaseTime() : ConfigurationData.DEFAULT_LEASE_TIME; - String entriesName = component.hasEntries() ? component.getEntries() : null; String serializedForm = component.hasSerialized() ? component.getSerialized() : null; ConfigurationData rpd; @@ -261,13 +243,13 @@ private void parseComponentProto(ComponentProto component) { if (type.isEmpty()) { type = spd.getClassName(); } - rpd = new ConfigurationData(name, type, spd.getProperties(), serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(name, type, spd.getProperties(), serializedForm); } else { if (rpdMap.get(name) != null) { throw new ConfigLoaderException("duplicate definition for " + name); } - rpd = new ConfigurationData(name, type, serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(name, type, serializedForm); } // Read out simple properties diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoTxtConfigFactory.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoTxtConfigFactory.java index 52b38aeb..4f522fbc 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoTxtConfigFactory.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoTxtConfigFactory.java @@ -38,7 +38,6 @@ import com.oracle.labs.mlrg.olcut.config.io.URLLoader; import com.oracle.labs.mlrg.olcut.config.property.GlobalProperties; -import java.io.IOException; import java.io.OutputStream; import java.util.Map; diff --git a/olcut-config-protobuf/src/main/resources/olcut_proto.proto b/olcut-config-protobuf/src/main/resources/olcut_proto.proto index 7cda1e9c..7fb1d4b9 100644 --- a/olcut-config-protobuf/src/main/resources/olcut_proto.proto +++ b/olcut-config-protobuf/src/main/resources/olcut_proto.proto @@ -55,11 +55,11 @@ message ComponentProto { repeated PropertyListProto list_property = 4; repeated PropertyMapProto map_property = 5; optional string override = 6; - optional bool exportable = 7; - optional bool importable = 8; - optional int64 leaseTime = 9; + optional bool exportable = 7; // Ignored in OLCUT 6+ + optional bool importable = 8; // Ignored in OLCUT 6+ + optional int64 leaseTime = 9; // Ignored in OLCUT 6+ optional string serialized = 10; - optional string entries = 11; + optional string entries = 11; // Ignored in OLCUT 6+ } /* diff --git a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ArgumentParsingTest.java b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ArgumentParsingTest.java index 7d167b0c..90ec530a 100644 --- a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ArgumentParsingTest.java +++ b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ArgumentParsingTest.java @@ -50,7 +50,6 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.List; -import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -355,8 +354,6 @@ public static class AllOfTheOptions implements Options { private File psi; @Option(charName = 'x', longName = "omega", usage = "") private Path omega; - @Option(charName = 'y', longName = "\uD83D\uDE01", usage = "") - private Random a; @Option(charName = 'z', longName = "\uD83D\uDE00", usage = "") private Foo b; @@ -389,7 +386,6 @@ public String toString() { ",\n chi=" + chi + ",\n psi=" + psi + ",\n omega=" + omega + - ",\n a=" + a + ",\n b=" + b + "}\n"; } @@ -423,7 +419,6 @@ public static AllOfTheOptions generate() { o.chi = new AtomicLong(1234567890L); o.psi = new File("file.txt"); o.omega = Paths.get("path.txt"); - o.a = new Random(1); o.b = Foo.BAZ; return o; @@ -480,8 +475,6 @@ public String[] generateArguments() { a.add(psi.getName() + ""); a.add("-x"); a.add(omega.getFileName() + ""); - a.add("-y"); - a.add(this.a.nextInt() + ""); a.add("-z"); a.add(b.toString() + ""); @@ -625,7 +618,6 @@ public int hashCode() { result = 31 * result + (chi != null ? chi.hashCode() : 0); result = 31 * result + (psi != null ? psi.hashCode() : 0); result = 31 * result + (omega != null ? omega.hashCode() : 0); - result = 31 * result + (a != null ? a.hashCode() : 0); result = 31 * result + (b != null ? b.hashCode() : 0); return result; } diff --git a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java index 1d930540..303e9aa3 100644 --- a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java +++ b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java @@ -51,7 +51,6 @@ public void structuralEqualsAllConfig() { final String aName = "all-config"; ConfigurationManager cm = new ConfigurationManager(createModuleResourceString(this.getClass(), "allConfig.xml")); AllFieldsConfigurable ac = (AllFieldsConfigurable) cm.lookup(aName); - cm.close(); cm = new ConfigurationManager(); cm.importConfigurable(ac); List a = cm.getComponentNames().stream() @@ -60,7 +59,6 @@ public void structuralEqualsAllConfig() { .map(Optional::get) .collect(Collectors.toList()); - cm.close(); cm = new ConfigurationManager(); final String bName = cm.importConfigurable(ac); List b = cm.getComponentNames().stream() @@ -76,7 +74,6 @@ public void structuralEqualsAllConfig() { ac.stringField = "Something different from before"; - cm.close(); cm = new ConfigurationManager(); String b2Name = cm.importConfigurable(ac); @@ -95,7 +92,6 @@ public void structuralEqualsProvenanceRoundtrip() { ConfigurationManager cm = new ConfigurationManager(createModuleResourceString(this.getClass(), "allConfig.xml")); AllFieldsConfigurable ac = (AllFieldsConfigurable) cm.lookup("all-config"); - cm.close(); cm = new ConfigurationManager(); String aName = cm.importConfigurable(ac); diff --git a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationManagerTest.java b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationManagerTest.java index 1cc0c2bc..e4bd4a82 100644 --- a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationManagerTest.java +++ b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationManagerTest.java @@ -89,12 +89,6 @@ public void testSingletonMultipleInterfaces() { Assertions.assertNull(m, "Looked up interface without allowAssignable but didn't get null"); } - @Test - public void testSingletonNoImport() { - assertNull(singletonCM.lookupSingleton(Barbary.class, false), "Should ignore imports"); - assertNull(singletonCM.lookupSingleton(Barbary.class, true), "Should ignore imports"); - } - @Test public void testMultipleLoading() { List files = new ArrayList<>(); diff --git a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/TypedProcessorsTest.java b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/TypedProcessorsTest.java index 504cac23..a30e279a 100644 --- a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/TypedProcessorsTest.java +++ b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/TypedProcessorsTest.java @@ -51,6 +51,5 @@ public void testStringType() throws Exception { assertEquals("McOmeletFace", values.get(0)); assertEquals("telemO-1170105035", values.get(1)); - cm.close(); } } \ No newline at end of file diff --git a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/provenance_tests/ProvenanceUtilTest.java b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/provenance_tests/ProvenanceUtilTest.java index 459b08ed..cf0e3622 100644 --- a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/provenance_tests/ProvenanceUtilTest.java +++ b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/provenance_tests/ProvenanceUtilTest.java @@ -94,7 +94,6 @@ public void testSerialize() throws Exception { ConfigurationManager cm = new ConfigurationManager(createModuleResourceString(this.getClass(), "/com/oracle/labs/mlrg/olcut/test/config_tests/allConfig.xml")); AllFieldsConfigurable afc = (AllFieldsConfigurable) cm.lookup("all-config"); - cm.close(); MyProvenancableClass mpc = new MyProvenancableClass(afc); IOUtil.serialize(mpc, tempFile.getPath()); mpc = IOUtil.deserialize(tempFile.getPath(), MyProvenancableClass.class).get(); diff --git a/olcut-core-test/src/test/resources/com/oracle/labs/mlrg/olcut/test/config_tests/singletonConfig.xml b/olcut-core-test/src/test/resources/com/oracle/labs/mlrg/olcut/test/config_tests/singletonConfig.xml index a4a92514..7eab6a41 100644 --- a/olcut-core-test/src/test/resources/com/oracle/labs/mlrg/olcut/test/config_tests/singletonConfig.xml +++ b/olcut-core-test/src/test/resources/com/oracle/labs/mlrg/olcut/test/config_tests/singletonConfig.xml @@ -18,7 +18,4 @@ - - - \ No newline at end of file diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ArgumentException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ArgumentException.java index 8e55e5c6..5aa7e423 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ArgumentException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ArgumentException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -56,7 +56,6 @@ public ArgumentException(String argumentName, String otherArgumentName, String m this(null, argumentName, otherArgumentName, msg); } - /** * Creates a new argument exception. * @@ -94,12 +93,6 @@ public ArgumentException(Throwable cause, String argumentName, String otherArgum this.msg = msg; } - /** @return Returns the msg. */ - @Deprecated - public String getMsg() { - return msg; - } - @Override public String getMessage() { StringBuilder sb = new StringBuilder(); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ComponentListener.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ComponentListener.java index 8cc14bc3..5804fef6 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ComponentListener.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ComponentListener.java @@ -30,15 +30,13 @@ /** * An interface that can be used for changes to components that have been - * looked up in a configuration manager, especially for those components that - * have been looked up in a component registry. + * looked up in a configuration manager. * * @see ConfigurationManager#lookup(String,ComponentListener) * @see ConfigurationManager#lookupAll(Class, ComponentListener) */ public interface ComponentListener { - - + /** * Indicates that a component has been added to the configuration. This * method will only be called when a component of a type that the listener diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Config.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Config.java index 2622dbe0..107faca2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Config.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Config.java @@ -38,7 +38,7 @@ * An annotation that can be added directly to variables that should be * configurable. We don't require a default value, as we can assign that * default during construction by declaring the annotated field with a value. - * + *

* Config should not be applied to a static field. */ @Documented diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigManager.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigManager.java index 88fdd714..2182de63 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigManager.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigManager.java @@ -36,9 +36,9 @@ /** * An annotation that denotes where the ConfigurationManager should be stored. - * + *

* Use this sparingly. - * + *

* ConfigManager should not be applied to a static field. */ @Documented diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurableName.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurableName.java index f3b95289..53a5fba3 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurableName.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurableName.java @@ -36,7 +36,7 @@ /** * An annotation that denotes where the String value of the component's name should be stored. - * + *

* ConfigurableName should not be applied to a static field. */ @Documented diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java index 2db6cd86..c9249811 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java @@ -66,8 +66,6 @@ public final class ConfigurationData implements Serializable { private static final long serialVersionUID = 1L; - public static final long DEFAULT_LEASE_TIME = -1; - private final String name; private final String className; @@ -80,25 +78,6 @@ public final class ConfigurationData implements Serializable { */ private final String serializedForm; - /** - * Whether this component is exportable to a service registrar. - */ - private final boolean exportable; - - private final boolean importable; - - /** - * The time to lease this object. - */ - private final long leaseTime; - - /** - * The (possibly null) name of a component that has a list - * of configuration entries to use when registering this component with - * a service registrar. - */ - private final String entriesName; - /** * Creates an empty ConfigurationData. * @param name the name of the item @@ -116,7 +95,7 @@ public ConfigurationData(String name, String className) { * @param properties The properties to apply to that object. */ public ConfigurationData(String name, String className, Map properties) { - this(name,className,properties,null,null,false,false,DEFAULT_LEASE_TIME); + this(name,className,properties,null); } /** @@ -124,13 +103,9 @@ public ConfigurationData(String name, String className, Map pr * @param name The name of the configured object. * @param className The class name of the configured object. * @param serializedForm A path to load the serialised form of this object (or null). - * @param entriesName The entries to restrict Jini loading (or null). - * @param exportable Is this object exportable via a Jini registry. - * @param importable Should this object be imported via a Jini registry. - * @param leaseTime How long before the Jini registrar needs to have the object renewed. */ - public ConfigurationData(String name, String className, String serializedForm, String entriesName, boolean exportable, boolean importable, long leaseTime) { - this(name,className, Collections.emptyMap(),serializedForm,entriesName,exportable,importable,leaseTime); + public ConfigurationData(String name, String className, String serializedForm) { + this(name,className,Collections.emptyMap(),serializedForm); } /** @@ -140,20 +115,12 @@ public ConfigurationData(String name, String className, String serializedForm, S * @param className The class name of the configured object. * @param properties The properties to apply to that object. * @param serializedForm A path to load the serialised form of this object (or null). - * @param entriesName The entries to restrict Jini loading (or null). - * @param exportable Is this object exportable via a Jini registry. - * @param importable Should this object be imported via a Jini registry. - * @param leaseTime How long before the Jini registrar needs to have the object renewed. */ - public ConfigurationData(String name, String className, Map properties, String serializedForm, String entriesName, boolean exportable, boolean importable, long leaseTime) { + public ConfigurationData(String name, String className, Map properties, String serializedForm) { this.name = name; this.className = className; this.properties = new HashMap<>(properties); this.serializedForm = serializedForm; - this.entriesName = entriesName; - this.exportable = exportable; - this.importable = importable; - this.leaseTime = leaseTime; } /** @@ -184,42 +151,6 @@ public String getSerializedForm() { return serializedForm; } - /** - * Should this configuration import a remote object via Jini. - * @return Should the configuration import a remote object. - */ - @Deprecated - public boolean isImportable() { - return importable; - } - - /** - * Returns the Jini lease time. Defaults to -1, Leases.ANY. - * @return The Jini lease time. - */ - @Deprecated - public long getLeaseTime() { - return leaseTime; - } - - /** - * Should this configuration export it's object via Jini. - * @return Should the configuration export a remote object. - */ - @Deprecated - public boolean isExportable() { - return exportable; - } - - /** - * Returns the entries which control Jini lookup. - * @return The Jini control entries. - */ - @Deprecated - public String getEntriesName() { - return entriesName; - } - /** @return Returns an unmodifiable view on the properties. */ public Map getProperties() { return Collections.unmodifiableMap(properties); @@ -256,27 +187,22 @@ public boolean contains(String propName) { * @return A copy of this object. */ public ConfigurationData copy() { - return new ConfigurationData(name,className,properties,serializedForm,entriesName,exportable,importable,leaseTime); + return new ConfigurationData(name,className,properties,serializedForm); } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ConfigurationData)) return false; - ConfigurationData that = (ConfigurationData) o; - return exportable == that.exportable && - importable == that.importable && - leaseTime == that.leaseTime && - name.equals(that.name) && + if (!(o instanceof ConfigurationData that)) return false; + return name.equals(that.name) && className.equals(that.className) && properties.equals(that.properties) && - Objects.equals(serializedForm, that.serializedForm) && - Objects.equals(entriesName, that.entriesName); + Objects.equals(serializedForm, that.serializedForm); } @Override public int hashCode() { - return Objects.hash(name, className, properties, serializedForm, exportable, importable, leaseTime, entriesName); + return Objects.hash(name, className, properties, serializedForm); } @Override @@ -286,10 +212,6 @@ public String toString() { ", className='" + className + '\'' + ", properties=" + properties + ", serializedForm='" + serializedForm + '\'' + - ", exportable=" + exportable + - ", importable=" + importable + - ", leaseTime=" + leaseTime + - ", entriesName='" + entriesName + '\'' + ')'; } @@ -323,24 +245,24 @@ public StructuralConfigurationData(Map contextMap, Co for(Map.Entry propertyEntry: referencedCD.properties.entrySet()) { String propName = propertyEntry.getKey(); Property prop = propertyEntry.getValue(); - if(prop instanceof SimpleProperty) { - this.simpleProperties.put(propName, new DerefedProperty(contextMap, (SimpleProperty) prop, propName, "")); - } else if (prop instanceof ListProperty) { - ListProperty listProperty = (ListProperty) prop; - this.listProperties.put(propName, - IntStream.range(0, listProperty.getSimpleList().size()) - .mapToObj(i -> - new DerefedProperty(contextMap, listProperty.getSimpleList().get(i), propName, ", index: " + i)) - .collect(Collectors.toList())); - this.listClassProperties.put(propName, listProperty.getClassList()); - } else if (prop instanceof MapProperty) { - MapProperty mapProperty = (MapProperty) prop; - this.mapProperties.put(propName, mapProperty.getMap().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - e -> new DerefedProperty(contextMap, e.getValue(), - propName, ", PropValue key: " + e.getKey())))); - } else { - logger.fine(String.format("Unknown Property of key: %s with type: %s", propertyEntry.getKey(), prop.getClass())); + switch (prop) { + case SimpleProperty simpleProperty -> + this.simpleProperties.put(propName, new DerefedProperty(contextMap, simpleProperty, propName, "")); + case ListProperty listProperty -> { + this.listProperties.put(propName, + IntStream.range(0, listProperty.getSimpleList().size()) + .mapToObj(i -> + new DerefedProperty(contextMap, listProperty.getSimpleList().get(i), propName, ", index: " + i)) + .collect(Collectors.toList())); + this.listClassProperties.put(propName, listProperty.getClassList()); + } + case MapProperty mapProperty -> + this.mapProperties.put(propName, mapProperty.getMap().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, + e -> new DerefedProperty(contextMap, e.getValue(), + propName, ", PropValue key: " + e.getKey())))); + case null, default -> + logger.fine(String.format("Unknown Property of key: %s with type: %s", propertyEntry.getKey(), prop.getClass())); } } } @@ -374,8 +296,7 @@ public int hashCode() { @Override public boolean equals(Object o) { - if (o instanceof StructuralConfigurationData) { - StructuralConfigurationData that = (StructuralConfigurationData) o; + if (o instanceof StructuralConfigurationData that) { if (this.className.equals(that.className)) { boolean simpleMatch = checkPresenceAllMatch(this.simpleProperties, that.simpleProperties, DerefedProperty::equals); @@ -530,8 +451,7 @@ public int hashCode() { */ @Override public boolean equals(Object o) { - if (o instanceof DerefedProperty) { - DerefedProperty that = (DerefedProperty) o; + if (o instanceof DerefedProperty that) { if(this.isDerefed && that.isDerefed) { return this.innerConf.equals(that.innerConf); } else if(!this.isDerefed && !that.isDerefed) { @@ -596,28 +516,20 @@ private static boolean innerStructuralEquals(Map a, M * Checks whether two ConfigurationData objects are 'structurally equal'. Two objects are structurally * equal when their classNames are the same and when all of their properties are equal or, if those * properties refer to another ConfigurationData by name, if all of their properties are structurally - * equal recursively. It does not compare {@link ConfigurationData#serializedForm}, {@link ConfigurationData#importable}, - * {@link ConfigurationData#exportable}, {@link ConfigurationData#leaseTime}, or {@link ConfigurationData#entriesName}. - * The SerializedForm is not relevant to the equality comparison we are making here, and the remaining fields are - * all deprecated. - * + * equal recursively. It does not compare {@link ConfigurationData#serializedForm} as the serialized form is not + * relevant to the equality comparison we are making here. *

- * * N.B. Because the serialized configuration format internally represents things as strings with no type information * but equality semantics often differ between strings and the types the represent, the method attempts to intuit * represented types by attempting to parse the string as that type and treating it as that type if it successfully * parses. This means that, eg. ID values that are typed as strings but are fully numerical will be converted to * doubles and be compared for equality that way. For more details on the processing see {@link DerefedProperty#equals(Object)}. - * *

- * * {@code aName} should be the name of an element of {@code a} that is to be compared to {@code bName} * in {@code b}. {@code a} and {@code b} should each contain all the ConfigurationData objects * needed to instantiate the objects named by {@code aName} and {@code bName} respectively. Objects not * instantiated by traversing children of {@code aName} and {@code bName} are ignored. - * *

- * * At log-level {@link java.util.logging.Level#FINE} this reports the first configuration object where the two * instances differ, together with the property values that differ between those instances. Any time this method * returns {@code false}, it should also log at least one message. @@ -646,7 +558,7 @@ public void save(ConfigWriter configWriter) throws ConfigWriterException { } /** - * Writes out the configuration data, redacting (i.e.\ ignoring) fields if necessary. + * Writes out the configuration data, redacting (i.e.,\ ignoring) fields if necessary. * @param configWriter The writer to use. * @param redactedFields The fields to redact. * @throws ConfigWriterException If the writer throws an exception. @@ -656,17 +568,9 @@ public void save(ConfigWriter configWriter, Set redactedFields) { attributes.put(ConfigLoader.NAME,name); attributes.put(ConfigLoader.TYPE,className); - attributes.put(ConfigLoader.IMPORT,""+isImportable()); - attributes.put(ConfigLoader.EXPORT,""+isExportable()); - if (getLeaseTime() > 0) { - attributes.put(ConfigLoader.LEASETIME, "" + getLeaseTime()); - } if (getSerializedForm() != null) { attributes.put(ConfigLoader.SERIALIZED,getSerializedForm()); } - if (getEntriesName() != null) { - attributes.put(ConfigLoader.ENTRIES,getEntriesName()); - } Map writtenProperties = new HashMap<>(); for (Map.Entry p : properties.entrySet()) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java index 254d3dda..50f595b2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -45,7 +45,6 @@ import com.oracle.labs.mlrg.olcut.util.Pair; import javax.management.MBeanServer; -import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -57,10 +56,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -83,7 +78,6 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static com.oracle.labs.mlrg.olcut.config.PropertySheet.StoredFieldType; @@ -94,7 +88,7 @@ * @see Configurable * @see PropertySheet */ -public class ConfigurationManager implements Closeable { +public final class ConfigurationManager { private static final Logger logger = Logger.getLogger(ConfigurationManager.class.getName()); /** @@ -103,6 +97,9 @@ public class ConfigurationManager implements Closeable { public static final char MODULE_SEPARATOR_CHAR = '|'; private static final Pattern WHITESPACE = Pattern.compile("\\s"); + /** + * Default option for configuration file loading. + */ public static final Option configFileOption = new Option() { @Override public String longName() { return "config-file"; } @@ -114,6 +111,9 @@ public class ConfigurationManager implements Closeable { public Class annotationType() { return Option.class; } }; + /** + * Option to provide as an error location when loading from a default configuration file. + */ public static final Function defaultConfigOptionFunction = (String path) -> new Option() { @Override public char charName() { return '\0'; } @@ -125,6 +125,9 @@ public class ConfigurationManager implements Closeable { public Class annotationType() { return Option.class; } }; + /** + * Option for specifying file format factories. + */ public static final Option fileFormatOption = new Option() { @Override public String longName() { return "config-file-formats"; } @@ -136,6 +139,9 @@ public class ConfigurationManager implements Closeable { public Class annotationType() { return Option.class; } }; + /** + * Option for requesting the usage for a CLI application. Equivalent to {@link #helpOption}. + */ public static final Option usageOption = new Option() { @Override public String longName() { return "usage"; } @@ -147,6 +153,9 @@ public class ConfigurationManager implements Closeable { public Class annotationType() { return Option.class; } }; + /** + * Option for requesting the help for a CLI application. Equivalent to {@link #usageOption}. + */ public static final Option helpOption = new Option() { @Override public String longName() { return "help"; } @@ -158,30 +167,56 @@ public class ConfigurationManager implements Closeable { public Class annotationType() { return Option.class; } }; + /** + * Delimiter for arguments. + */ public static final char ARG_DELIMITER = ','; + /** + * Escape character in UNIX. + */ public static final char UNIX_ESCAPE_CHAR = '\\'; + /** + * Escape character in Windows. + */ public static final char WIN_ESCAPE_CHAR = '^'; - @Deprecated - public static final char ESCAPE_CHAR = UNIX_ESCAPE_CHAR; - + /** + * Is this JVM running on Windows? + */ public static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().startsWith("windows"); + /** + * Escape character for the current JVM. + */ public static final char CUR_ESCAPE_CHAR = IS_WINDOWS ? WIN_ESCAPE_CHAR : UNIX_ESCAPE_CHAR; + /** + * Character prefix for overriding a property in a configuration file. + */ public static final char CONFIGURABLE_CHAR = '@'; + /** + * Start sequence for a character argument. + */ public static final String SHORT_ARG = "-"; + /** + * Start sequence for a long argument. + */ public static final String LONG_ARG = "--"; + /** + * Start sequence for a configuration override argument. + */ public static final String CONFIGURABLE_OVERRIDE = LONG_ARG + CONFIGURABLE_CHAR; + /** + * Default empty options instance. + */ // **WARNING** - do not convert this into a Lambda, it doesn't work due to reflection issues. public static final Options EMPTY_OPTIONS = new Options(){ }; - //public static final Options EMPTY_OPTIONS = () -> ""; /** * Used to support new config file formats at runtime. @@ -287,12 +322,14 @@ public ConfigurationManager(String[] arguments, String defaultConfigPath) throws /** * Creates a new configuration manager. - * + *

* This constructor performs a sequence of operations: - * - It validates the supplied options struct to make sure it does not have duplicate option names. - * - Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}. - * - Parses any configuration overrides and applies them to the configuration manager. - * - Parses out options for the supplied struct and writes them into the struct. + *

    + *
  • It validates the supplied options struct to make sure it does not have duplicate option names.
  • + *
  • Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}.
  • + *
  • Parses any configuration overrides and applies them to the configuration manager.
  • + *
  • Parses out options for the supplied struct and writes them into the struct.
  • + *
* @param arguments An array of command line arguments. * @param options An object to write the parsed argument values into. * @throws UsageException Thrown when the user requested the usage string. @@ -306,12 +343,14 @@ public ConfigurationManager(String[] arguments, Options options) throws UsageExc /** * Creates a new configuration manager. - * + *

* This constructor performs a sequence of operations: - * - It validates the supplied options struct to make sure it does not have duplicate option names. - * - Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}. - * - Parses any configuration overrides and applies them to the configuration manager. - * - Parses out options for the supplied struct and writes them into the struct. + *

    + *
  • It validates the supplied options struct to make sure it does not have duplicate option names.
  • + *
  • Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}.
  • + *
  • Parses any configuration overrides and applies them to the configuration manager.
  • + *
  • Parses out options for the supplied struct and writes them into the struct.
  • + *
* @param arguments An array of command line arguments. * @param options An object to write the parsed argument values into. * @param useConfigFiles If true, add the config file option. If false ignore the config file option, @@ -327,12 +366,14 @@ public ConfigurationManager(String[] arguments, Options options, boolean useConf /** * Creates a new configuration manager. - * + *

* This constructor performs a sequence of operations: - * - It validates the supplied options struct to make sure it does not have duplicate option names. - * - Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}. - * - Parses any configuration overrides and applies them to the configuration manager. - * - Parses out options for the supplied struct and writes them into the struct. + *

    + *
  • It validates the supplied options struct to make sure it does not have duplicate option names.
  • + *
  • Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}.
  • + *
  • Parses any configuration overrides and applies them to the configuration manager.
  • + *
  • Parses out options for the supplied struct and writes them into the struct.
  • + *
* @param arguments An array of command line arguments. * @param options An object to write the parsed argument values into. * @param defaultConfigPath The default config path. Set to empty or null to disable. @@ -349,13 +390,15 @@ public ConfigurationManager(String[] arguments, Options options, String defaultC /** * Creates a new configuration manager. - * + *

* This constructor performs a sequence of operations: - * - It validates the supplied options struct to make sure it does not have duplicate option names. - * - Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}. - * - Loads in the supplied ConfigurationData objects, overwriting things in the files if necessary. - * - Parses any configuration overrides and applies them to the configuration manager. - * - Parses out options for the supplied struct and writes them into the struct. + *

    + *
  • It validates the supplied options struct to make sure it does not have duplicate option names.
  • + *
  • Loads any configuration file specified by the {@link ConfigurationManager#configFileOption}.
  • + *
  • Loads in the supplied ConfigurationData objects, overwriting things in the files if necessary.
  • + *
  • Parses any configuration overrides and applies them to the configuration manager.
  • + *
  • Parses out options for the supplied struct and writes them into the struct.
  • + *
* @param arguments An array of command line arguments. * @param configData A list of {@link ConfigurationData} objects. * @param options An object to write the parsed argument values into. @@ -442,33 +485,15 @@ public ConfigurationManager(String[] arguments, List configDa // *Must* be last as it can cause Configurable instantiation. // Throws an exception if there are unknown named arguments at this stage. try { - unnamedArguments = AccessController.doPrivileged((PrivilegedExceptionAction) () -> parseOptionArguments(argumentsList, options)); - } catch (PrivilegedActionException e) { - Exception inner = e.getException(); - if (inner instanceof IllegalAccessException) { - throw new ArgumentException(e, "Failed to write argument into Options"); - } else if ((inner instanceof InstantiationException) || (inner instanceof NoSuchMethodException) || (inner instanceof InvocationTargetException)) { + unnamedArguments = parseOptionArguments(argumentsList, options); + } catch (IllegalAccessException e) { + throw new ArgumentException(e, "Failed to write argument into Options"); + } catch (InstantiationException | NoSuchMethodException | InvocationTargetException e) { throw new ArgumentException(e, "Failed to instantiate a field of Options."); - } else { - throw new ArgumentException(inner, "Unexpected exception thrown when reading arguments - " + inner.getMessage()); - } } catch (PropertyException e) { throw new ArgumentException(e, e.getMessage() + "\n\n" + usage); - } - } - - private ConfigurationManager(Map newrpm, GlobalProperties newgp, Map> newSymbolTable, Map newSerializedObjects, GlobalProperties newOrigGlobal) { - this.configurationDataMap = newrpm; - this.configurationNameMap = new IdentityHashMap<>(); - this.globalProperties = newgp; - this.symbolTable = newSymbolTable; - this.serializedObjects = newSerializedObjects; - this.origGlobal = newOrigGlobal; - GlobalProperty sC = globalProperties.get("showCreations"); - if(sC != null) { - this.showCreations = Boolean.parseBoolean(sC.getValue()); - } else { - this.showCreations = false; + } catch (Exception e) { + throw new ArgumentException(e, "Unexpected exception thrown when reading arguments - " + e.getMessage()); } } @@ -498,8 +523,13 @@ public static void addFileFormatFactory(FileFormatFactory f) { formatFactoryMap.put(f.getExtension(),f); } - public static FileFormatFactory getFileFormatFactory(String extension) { - return formatFactoryMap.get(extension); + /** + * Gets the file format factory for the supplied extension, or {@link Optional#empty()} if it's unknown. + * @param extension The extension to check. + * @return The file format factory if known. + */ + public static Optional getFileFormatFactory(String extension) { + return Optional.ofNullable(formatFactoryMap.get(extension)); } /** @@ -608,7 +638,7 @@ public static String validateOptions(Options options, String defaultConfigPath, // Now check the generic type of the list. List> list = PropertySheet.getGenericClass(f); if (list.size() == 1) { - Class genericClazz = list.get(0); + Class genericClazz = list.getFirst(); FieldType genericFieldType = FieldType.getFieldType(genericClazz); if (FieldType.configurableTypes.contains(genericFieldType)) { throw new ArgumentException(longName,"Argument has a Configurable type, which requires using a config file."); @@ -652,7 +682,7 @@ public static String validateOptions(Options options, String defaultConfigPath, /** * Checks to see if the input after lowercasing is equal to "false" or "true". - * + *

* It's stricter than Boolean.parseBoolean. * @param input The input to test * @return True if it's a boolean value, false otherwise. @@ -663,56 +693,52 @@ private static boolean parseableAsBoolean(String input) { } private static URL findURL(String input, String argumentName) { - return AccessController.doPrivileged((PrivilegedAction) - () -> { - int modIndex = input.indexOf(MODULE_SEPARATOR_CHAR); - if (modIndex > 0) { - try { - String witnessClassName = input.substring(0, modIndex); - String classPathName = input.substring(modIndex + 1); - Class witnessClass = Class.forName(witnessClassName); - URL url = witnessClass.getResource(classPathName); - if (url != null) { - return url; - } // else fall through to regular loading - } catch (ClassNotFoundException e) { - // fall through to regular loading - logger.warning("Failed to load class '" + input.substring(0, modIndex) + "'"); - } - } - URL url = ConfigurationManager.class.getResource(input); - if (url == null) { - File file = new File(input); - if (file.exists()) { - try { - url = file.toURI().toURL(); - } catch (MalformedURLException e) { - throw new ArgumentException(e, argumentName, "Can't load config file: " + input); - } - } else { - try { - url = (new URI(input)).toURL(); - } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) { - throw new ArgumentException(argumentName, "Can't find config file: " + input); - } - } - } - if (IOUtil.isDisallowedProtocol(url)) { - throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); - } + int modIndex = input.indexOf(MODULE_SEPARATOR_CHAR); + if (modIndex > 0) { + try { + String witnessClassName = input.substring(0, modIndex); + String classPathName = input.substring(modIndex + 1); + Class witnessClass = Class.forName(witnessClassName); + URL url = witnessClass.getResource(classPathName); + if (url != null) { return url; + } // else fall through to regular loading + } catch (ClassNotFoundException e) { + // fall through to regular loading + logger.warning("Failed to load class '" + input.substring(0, modIndex) + "'"); + } + } + URL url = ConfigurationManager.class.getResource(input); + if (url == null) { + File file = new File(input); + if (file.exists()) { + try { + url = file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new ArgumentException(e, argumentName, "Can't load config file: " + input); + } + } else { + try { + url = (new URI(input)).toURL(); + } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) { + throw new ArgumentException(argumentName, "Can't find config file: " + input); } - ); + } + } + if (IOUtil.isDisallowedProtocol(url)) { + throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); + } + return url; } /** * Parses out arguments which override fields in configured objects. - * + *

* Expects arguments of the form --@componentname.propertyname. - * + *

* Throws {@link ArgumentException} if the component name does not match a known component, * or if the property name is not valid for that class. - * + *

* Removes the parsed arguments from the input, and overwrites values in the rpd for each component. * * @param arguments The command line arguments. @@ -737,7 +763,7 @@ private void parseConfigurableArguments(List arguments) throws ArgumentE String param = argsItr.next(); List list = parseStringList(param); if (list.size() == 1) { - rpd.add(split[1], new SimpleProperty(list.get(0))); + rpd.add(split[1], new SimpleProperty(list.getFirst())); } else { rpd.add(split[1], ListProperty.createFromStringList(list)); } @@ -770,7 +796,7 @@ private void parseConfigurableArguments(List arguments) throws ArgumentE /** * Parses out the arguments into the supplied {@link Options}. - * + *

* Removes the parsed arguments from the input. * * @param arguments The command line arguments. @@ -801,14 +827,13 @@ private String[] parseOptionArguments(List arguments, Options options) t } fields = Options.getOptions(o.getClass()); for (Field f : fields) { - boolean accessible = f.isAccessible(); f.setAccessible(true); if (f.get(o) != null) { logger.fine("Warning: overwriting Options field."); } f.set(o,f.getType().getDeclaredConstructor().newInstance()); objectQueue.add((Options)f.get(o)); - f.setAccessible(accessible); + f.setAccessible(false); } } @@ -827,7 +852,6 @@ private String[] parseOptionArguments(List arguments, Options options) t arguments.remove(i); consumed = true; if (i < arguments.size()) { - boolean accessible = f.isAccessible(); f.setAccessible(true); String param = arguments.get(i); List list = parseStringList(param); @@ -838,18 +862,18 @@ private String[] parseOptionArguments(List arguments, Options options) t if (genericList.size() == 1) { f.set(arg.getB(), PropertySheet.parseListField(this, curArg, f.getName(), f.getType(), genericList.get(0), ft, ListProperty.createFromStringList(list))); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new ArgumentException(curArg,"Unknown generic type in argument"); } } else if (list.size() == 1) { f.set(arg.getB(), PropertySheet.parseSimpleField(this,curArg,f.getName(),f.getType(),ft,list.get(0))); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new ArgumentException(curArg,"Parsed a list where a single argument was expected. Type = " + f.getType() + ", parsed output = " + list.toString()); } // Consume parameter. arguments.remove(i); - f.setAccessible(accessible); + f.setAccessible(false); } else { throw new ArgumentException(curArg,"No parameter for argument"); } @@ -867,16 +891,15 @@ private String[] parseOptionArguments(List arguments, Options options) t Pair arg = charNameMap.get(args[j]); if (arg != null) { Field f = arg.getA(); - boolean accessible = f.isAccessible(); f.setAccessible(true); FieldType ft = FieldType.getFieldType(f); if (FieldType.isBoolean(ft)) { f.set(arg.getB(),true); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new ArgumentException(curArg + " on element " + args[j], "Non boolean argument found where boolean expected"); } - f.setAccessible(accessible); + f.setAccessible(false); } else { throw new ArgumentException(curArg + " on element " + args[j], "Unknown argument"); } @@ -885,7 +908,6 @@ private String[] parseOptionArguments(List arguments, Options options) t Pair arg = charNameMap.get(args[args.length-1]); if (arg != null) { Field f = arg.getA(); - boolean accessible = f.isAccessible(); f.setAccessible(true); FieldType ft = FieldType.getFieldType(f); if (FieldType.isBoolean(ft)) { @@ -917,23 +939,23 @@ private String[] parseOptionArguments(List arguments, Options options) t if (genericList.size() == 1) { f.set(arg.getB(), PropertySheet.parseListField(this, curArg, f.getName(), f.getType(), genericList.get(0), ft, ListProperty.createFromStringList(list))); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new ArgumentException(curArg,"Unknown generic type in argument"); } } else if (list.size() == 1) { f.set(arg.getB(), PropertySheet.parseSimpleField(this,curArg,f.getName(),f.getType(),ft,list.get(0))); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new ArgumentException(curArg,"Parsed a list where a single argument was expected. Type = " + f.getType() + ", parsed output = " + list.toString()); } // Consume parameter. arguments.remove(i); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new ArgumentException(curArg,"No parameter for argument"); } } - f.setAccessible(accessible); + f.setAccessible(false); } } else { throw new ArgumentException(curArg, "Empty argument found."); @@ -949,7 +971,7 @@ private String[] parseOptionArguments(List arguments, Options options) t /** * Parses out the config file argument. - * + *

* Removes the parsed arguments from the input. * @param arguments The command line arguments. * @return A list of URLs pointing to olcut config files. @@ -1169,7 +1191,7 @@ public void addProperties(URL url) throws ConfigLoaderException { /** * Overrides a simple property in a specific configurable in this configuration manager. - * + *

* Throws {@link PropertyException} if the configurable/property doesn't exist, has already been instantiated, or doesn't match the field type. * @param componentName The name of the component. * @param propertyName The name of the property/field. @@ -1199,12 +1221,6 @@ public void overrideConfigurableProperty(String componentName, String propertyNa } } - /** - * Shuts down the configuration manager, which is a no-op on the standard version. - */ - @Override - public synchronized void close() { } - /** * Get a copy of any unnamed arguments that weren't parsed into an {@link Options} * instance, or used to override a {@link Configurable} field. @@ -1216,7 +1232,7 @@ public String[] getUnnamedArguments() { /** * Gets the configuration data associated with a given instance. - * + *

* Allows the modification of configuration for future objects. * @param instanceName the name of the instance whose properties we want * @return the associated configuration data, or {@link Optional#empty} if there is no data @@ -1224,16 +1240,12 @@ public String[] getUnnamedArguments() { */ public Optional getConfigurationData(String instanceName) { ConfigurationData data = configurationDataMap.get(instanceName); - if (data == null) { - return Optional.empty(); - } else { - return Optional.of(data); - } + return Optional.ofNullable(data); } /** * Does this ConfigurationManager know about an instance called instanceName. - * + *

* Does not trigger class instantiation or configuration. * @param instanceName The name to check. * @return True if it contains a {@link Configurable} called instanceName. @@ -1265,7 +1277,7 @@ public Optional getConfiguredName(Configurable conf) { * @return the property sheet for the object. */ @SuppressWarnings("unchecked") // Warning suppressed as it's behind an isAssignableFrom check. - protected PropertySheet getPropertySheet(String instanceName) { + private PropertySheet getPropertySheet(String instanceName) { if(!symbolTable.containsKey(instanceName)) { // if it is not in the symbol table, so construct // it based upon our raw property data @@ -1291,7 +1303,7 @@ protected PropertySheet getPropertySheet(String instance /** * Gets all instances that are of the given type. - * + *

* Only returns the names of the instantiated objects. * * @param type the desired type of instance @@ -1431,8 +1443,7 @@ private Configurable innerLookup(String instanceName, ComponentListener cl, bool configurationNameMap.put(ret, instanceName); } - if (ret instanceof Startable) { - Startable stret = (Startable) ret; + if (ret instanceof Startable stret) { Thread t = new Thread(stret); t.setName(instanceName + "_thread"); stret.setThread(t); @@ -1472,7 +1483,7 @@ public T lookup(Class c, ComponentListener cl) { return null; } Collections.shuffle(comps); - return comps.get(0); + return comps.getFirst(); } /** @@ -1495,8 +1506,7 @@ public Map lookupAllMap(Class c) { if(!c.isInterface()) { String className = c.getName(); for (Map.Entry e : configurationDataMap.entrySet()) { - if (e.getValue().getClassName().equals(className) && - !e.getValue().isImportable()) { + if (e.getValue().getClassName().equals(className)) { ret.put(e.getKey(),(T)lookup(e.getKey())); } } @@ -1506,8 +1516,8 @@ public Map lookupAllMap(Class c) { // implementing classes and return them. for (Map.Entry e : configurationDataMap.entrySet()) { try { - Class clazz = Class.forName(e.getValue().getClassName()); - if (!e.getValue().isImportable() && c.isAssignableFrom(clazz) && !clazz.isInterface()) { + Class clazz = Class.forName(e.getValue().getClassName()); + if (c.isAssignableFrom(clazz) && !clazz.isInterface()) { ret.put(e.getKey(),(T)innerLookup(e.getKey(),null,true)); } } catch (ClassNotFoundException ex) { @@ -1531,13 +1541,11 @@ public List lookupAll(Class c) { // // If the class isn't an interface, then lookup each of the names - // in the raw property data with the given class - // name, ignoring those things marked as importable. + // in the raw property data with the given class name. if(!c.isInterface()) { String className = c.getName(); for (Map.Entry e : configurationDataMap.entrySet()) { - if (e.getValue().getClassName().equals(className) && - !e.getValue().isImportable()) { + if (e.getValue().getClassName().equals(className)) { ret.add((T)lookup(e.getKey())); } } @@ -1547,8 +1555,8 @@ public List lookupAll(Class c) { // implementing classes and return them. for (Map.Entry e : configurationDataMap.entrySet()) { try { - Class clazz = Class.forName(e.getValue().getClassName()); - if (!e.getValue().isImportable() && c.isAssignableFrom(clazz) && !clazz.isInterface()) { + Class clazz = Class.forName(e.getValue().getClassName()); + if (c.isAssignableFrom(clazz) && !clazz.isInterface()) { ret.add((T)innerLookup(e.getKey(),null,true)); } } catch (ClassNotFoundException ex) { @@ -1595,9 +1603,8 @@ public T lookupSingleton(Class c, boolean allowAssig ConfigurationData rpd = e.getValue(); try { Class pclass = Class.forName(rpd.getClassName()); - if (!rpd.isImportable() && - ((allowAssignable && c.isAssignableFrom(pclass)) || - (!allowAssignable && rpd.getClassName().equals(c.getName())))) { + if ((allowAssignable && c.isAssignableFrom(pclass)) || + (!allowAssignable && rpd.getClassName().equals(c.getName()))) { instanceNames.add(e.getKey()); } } catch(ClassNotFoundException ex) { @@ -1616,7 +1623,7 @@ public T lookupSingleton(Class c, boolean allowAssig throw new PropertyException("", "Multiple instances of " + c.getName() + " found in configuration: " + names); } - String matchedName = instanceNames.get(0); + String matchedName = instanceNames.getFirst(); ConfigurationData cd = configurationDataMap.get(matchedName); try { Class matchedClass = Class.forName(cd.getClassName()); @@ -1645,7 +1652,7 @@ public List listAll(Class c) { for(Map.Entry e : configurationDataMap.entrySet()) { ConfigurationData rpd = e.getValue(); try { - Class pclass = Class.forName(rpd.getClassName()); + Class pclass = Class.forName(rpd.getClassName()); if (c.isAssignableFrom(pclass)) { ret.add(e.getKey()); } @@ -1701,10 +1708,19 @@ public boolean removeConfigurable(String name) { } } + /** + * Adds all the configurations and global properties from the supplied CM to this CM. + * @param subCM The CM containing configurations to copy. + */ public void addSubConfiguration(ConfigurationManager subCM) { addSubConfiguration(subCM, false); } + /** + * Adds all the configurations and global properties from the supplied CM to this CM. + * @param subCM The CM containing configurations to copy. + * @param overwrite Should elements of this CM be overwritten if they have the same name? + */ public void addSubConfiguration(ConfigurationManager subCM, boolean overwrite) { Collection compNames = getComponentNames(); @@ -1725,8 +1741,7 @@ public void addSubConfiguration(ConfigurationManager subCM, boolean overwrite) { globalProperties.putAll(subCM.globalProperties); for(Map.Entry> e : subCM.symbolTable.entrySet()) { - PropertySheet newPS = e.getValue().copy(); - newPS.setCM(this); + PropertySheet newPS = e.getValue().copy(this); symbolTable.put(e.getKey(),newPS); } @@ -1753,7 +1768,7 @@ public void addConfiguration(ConfigurationData newData) { /** * Adds all the configurations in the list to this ConfigurationManager. - * + *

* Does not trigger class loading or validation of the ConfigurationData objects. * @param newData The configurations to ingest. */ @@ -1819,7 +1834,7 @@ public void setGlobalProperty(String propertyName, String value) { } } - protected String getStrippedComponentName(String propertyName) { + private String getStrippedComponentName(String propertyName) { assert propertyName != null; while(propertyName.startsWith("$")) { @@ -1838,12 +1853,10 @@ protected String getStrippedComponentName(String propertyName) { */ @Override public boolean equals(Object obj) { - if(!(obj instanceof ConfigurationManager)) { + if(!(obj instanceof ConfigurationManager cm)) { return false; } - ConfigurationManager cm = (ConfigurationManager) obj; - Collection setA = new HashSet<>(getComponentNames()); Collection setB = new HashSet<>(cm.getComponentNames()); if(!setA.equals(setB)) { @@ -1871,7 +1884,7 @@ public int hashCode() { /** * Saves the current configuration to the given file. - * + *

* Only writes out instantiated components, and redacts their fields if required. * * @param file Place to save the configuration. @@ -1939,7 +1952,7 @@ public void save(OutputStream writer, String extension, boolean writeAll) throws * will be written. * @throws ConfigWriterException If an error occurs while writing the configuration. */ - protected void write(ConfigWriter writer, boolean writeAll) throws ConfigWriterException { + private void write(ConfigWriter writer, boolean writeAll) throws ConfigWriterException { writer.writeStartDocument(); // // Write out the global properties. @@ -1985,7 +1998,7 @@ protected void write(ConfigWriter writer, boolean writeAll) throws ConfigWriterE writer.close(); } - protected PropertySheet createPropertySheet(T configurable, ConfigurationManager cm, ConfigurationData rpd) { + private PropertySheet createPropertySheet(T configurable, ConfigurationManager cm, ConfigurationData rpd) { return new PropertySheet<>(configurable,cm,rpd); } @@ -2005,23 +2018,22 @@ public String importConfigurable(Configurable configurable) throws PropertyExcep try { Set fields = PropertySheet.getAllFields(configurable.getClass()); for (Field field : fields) { - boolean accessible = field.isAccessible(); field.setAccessible(true); ConfigurableName nameAnnotation = field.getAnnotation(ConfigurableName.class); if (nameAnnotation != null) { configName = (String) field.get(configurable); // // break out of loop at the first instance of ConfigurableName. - field.setAccessible(accessible); + field.setAccessible(false); break; } - field.setAccessible(accessible); + field.setAccessible(false); } } catch (IllegalAccessException ex) { - throw new PropertyException(ex, configName, "Failed to read the ConfigurableName field"); + throw new PropertyException(ex, configName, "Failed to read the @ConfigurableName field"); } - if (configName.equals("")) { + if (configName.isEmpty()) { throw new PropertyException("", "Failed to extract name from @ConfigurableName field"); } else { return importConfigurable(configurable, configName); @@ -2034,7 +2046,7 @@ public String importConfigurable(Configurable configurable) throws PropertyExcep * this configuration manager. This is useful in situations where you have * a configurable component but you don't have the property sheet that * generated it (e.g., if it was sent over the network). - * + *

* It's best effort, if your object graph is loopy, it will flatten it * into a tree by cloning elements. * @@ -2064,7 +2076,6 @@ public String importConfigurable(Configurable configurable, try { Set fields = PropertySheet.getAllFields(confClass); for (Field field : fields) { - boolean accessible = field.isAccessible(); field.setAccessible(true); Config configAnnotation = field.getAnnotation(Config.class); if (configAnnotation != null) { @@ -2171,7 +2182,7 @@ public String importConfigurable(Configurable configurable, }); } } - field.setAccessible(accessible); + field.setAccessible(false); } ConfigurationData rpd = new ConfigurationData(name, confClass.getName(), m); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/DescribeConfigurable.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/DescribeConfigurable.java index 3536ac66..79c8d86a 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/DescribeConfigurable.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/DescribeConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -42,12 +42,14 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -222,8 +224,6 @@ private static String generateDefaultValue(FieldInfo fi) { return "/path/to/a/file"; case URL: return "file:///path/to/a/file"; - case RANDOM: - return "42"; case ENUM: try { return Class.forName(fi.className).getEnumConstants()[0].toString(); @@ -249,10 +249,9 @@ public static SortedMap generateFieldInfo(Class constructor = configurableClass.getDeclaredConstructor(); - boolean isAccessible = constructor.isAccessible(); constructor.setAccessible(true); instance = constructor.newInstance(); - constructor.setAccessible(isAccessible); + constructor.setAccessible(false); } catch (NoSuchMethodException ex) { throw new IllegalStateException("No-args constructor not found for class " + configurableClass, ex); } catch (InvocationTargetException | IllegalAccessException | InstantiationException ex) { @@ -263,7 +262,6 @@ public static SortedMap generateFieldInfo(Class generateFieldInfo(Class> genericList = PropertySheet.getGenericClass(f); if (genericList.size() == 1) { - Class listType = genericList.get(0); + Class listType = genericList.getFirst(); FieldInfo fi; if (listType.isEnum()) { Object[] constants = listType.getEnumConstants(); @@ -325,7 +323,7 @@ public static SortedMap generateFieldInfo(Class> generateDescription(Map map) * @param map The field infos for that class. */ public static void writeExampleConfig(OutputStream stream, String fileFormat, Class configurableClass, Map map) { - FileFormatFactory factory = ConfigurationManager.getFileFormatFactory(fileFormat); - if (factory == null) { + Optional factory = ConfigurationManager.getFileFormatFactory(fileFormat); + if (factory.isEmpty()) { throw new IllegalArgumentException("No format factory found for extension '" + fileFormat + "'"); } - ConfigWriter configWriter = factory.getWriter(stream); + ConfigWriter configWriter = factory.get().getWriter(stream); // Generate attributes Map attributes = new HashMap<>(); @@ -544,7 +542,7 @@ public static void main(String[] args) throws UnsupportedEncodingException { writeExampleConfig(writer, o.extension, configurableClass, map); - System.out.println("Example :\n" + writer.toString("UTF-8")); + System.out.println("Example :\n" + writer.toString(StandardCharsets.UTF_8)); } } else { logger.warning("The supplied class did not implement Configurable, class = " + clazz.getCanonicalName()); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/FieldType.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/FieldType.java index 7211da3d..18f9cc75 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/FieldType.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/FieldType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -89,9 +89,7 @@ public enum FieldType { DATE_TIME(OffsetDateTime.class), DATE(LocalDate.class), TIME(OffsetTime.class), - ENUM(Enum.class), - @Deprecated - RANDOM(Random.class); + ENUM(Enum.class); private static final Class configurableClass = Configurable.class; private static final Class configurableArrayClass = Configurable[].class; @@ -110,7 +108,7 @@ public enum FieldType { public final static EnumSet simpleTypes = EnumSet.of(BOOLEAN, BYTE, CHAR, SHORT, INTEGER, LONG, FLOAT, DOUBLE, STRING, CONFIGURABLE, ATOMIC_INTEGER, - ATOMIC_LONG, FILE, PATH, URL, RANDOM, DATE_TIME, DATE, TIME, ENUM); + ATOMIC_LONG, FILE, PATH, URL, DATE_TIME, DATE, TIME, ENUM); public final static EnumSet mapTypes = EnumSet.of(MAP); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/InternalConfigurationException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/InternalConfigurationException.java index cf75da6c..754e1d3b 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/InternalConfigurationException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/InternalConfigurationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -29,20 +29,16 @@ package com.oracle.labs.mlrg.olcut.config; /** - *

* Indicates that a problem occurred while setting one or more properties for this component. This includes errors as * improper type for component(-lists) properties, out-of-range-problems for double-, int- and ranged string-properties, * instantiation errors and undefined mandatory properties. - *

*

* This exception is instantiable only by the configuration management classes itself. In order to indicate problems * within Configurable.newProperties which are not coped by types or ranges (eg file-not-found, complex configuration * logic problems, etc.) PropertyException (which superclasses this class) can be used. - *

*

* The intention of the class is to make a clear distinction between core configuration errors and high level user * specific problems. - *

*/ public class InternalConfigurationException extends PropertyException { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Option.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Option.java index fee57fce..e2f7ae28 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Option.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Option.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -36,10 +36,10 @@ /** * An annotation that can be added directly to variables that are command line arguments. - * + *

* Defaults to the value set during construction. Supports all the types supported * by the {@link Config} annotation. - * + *

* Option should not be applied to a static field. */ @Documented @@ -47,13 +47,32 @@ @Target(ElementType.FIELD) public @interface Option { + /** + * Character option, allowed to be any single UTF-8 glyph. + * @return The character for this option. + */ char charName() default EMPTY_CHAR; + /** + * Long name of the option. Allowed to be any sequence of non-whitespace characters. + * @return The long name. + */ String longName(); + /** + * Usage field for the option, displayed in the help message. + * @return The option's usage text. + */ String usage(); + /** + * Empty character. + */ public static final char EMPTY_CHAR = '\0'; + + /** + * Space character. + */ public static final char SPACE_CHAR = ' '; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java index 67c9d8ac..c5e77dff 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -36,8 +36,6 @@ import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -72,7 +70,7 @@ public interface Options { /** * Gets a possibly multi line description of this Options subclass. - * + *

* Default implementation returns the empty string. * @return A description string. */ @@ -135,7 +133,7 @@ public static List> getUsage(Class options) { ArrayList> list = new ArrayList<>(); ArrayList> optionsList = new ArrayList<>(); Set fields = getOptionFields(options); - if (fields.size() == 0) { + if (fields.isEmpty()) { return list; } else { list.add(new ArrayList<>(Collections.singletonList(options.getSimpleName()))); @@ -214,8 +212,7 @@ public static String generateTypeDescription(Field f) { return "enum - " + getEnumConstantString(enumClazz); } else if (clazz == EnumSet.class) { Type type = f.getGenericType(); - if (type instanceof ParameterizedType) { - ParameterizedType typeName = (ParameterizedType) type; + if (type instanceof ParameterizedType typeName) { // Should only have a single type parameter Type enumType = typeName.getActualTypeArguments()[0]; try { @@ -283,19 +280,16 @@ public static ArrayList getOptionUsage(Option option, Field f, Options o } output.add(option.longName()); output.add(type); - Object extractedField = AccessController.doPrivileged((PrivilegedAction) - () -> { - try { - boolean accessible = f.isAccessible(); - f.setAccessible(true); - Object fieldVal = f.get(obj); - f.setAccessible(accessible); - return fieldVal; - } catch (IllegalAccessException e) { - Logger.getLogger(Options.class.getName()).fine("Failed to read default value from field " + option.longName()); - return null; - } - }); + Object extractedField; + try { + f.setAccessible(true); + Object fieldVal = f.get(obj); + f.setAccessible(false); + extractedField = fieldVal; + } catch (IllegalAccessException e) { + Logger.getLogger(Options.class.getName()).fine("Failed to read default value from field " + option.longName()); + extractedField = null; + } String defaultVal = extractedField == null ? "" : extractedField.toString(); output.add(defaultVal); output.add(option.usage()); @@ -311,33 +305,29 @@ public static ArrayList getOptionUsage(Option option, Field f, Options o * @return all of the fields annotated with {@link Option}. */ public static Set getOptionFields(Class options) { - return AccessController.doPrivileged((PrivilegedAction>) - () -> { - Set ret = new HashSet<>(); - Queue> cq = new ArrayDeque<>(); - cq.add(options); - while (!cq.isEmpty()) { - Class curr = cq.remove(); - for (Field f : curr.getDeclaredFields()) { - if (f.getAnnotation(Option.class) != null) { - ret.add(f); - } - } - for (Field f : curr.getFields()) { - if (f.getAnnotation(Option.class) != null) { - ret.add(f); - } - } - Class sc = curr.getSuperclass(); - if (sc != null) { - cq.add(sc); - } - cq.addAll(Arrays.asList(curr.getInterfaces())); - } - ret.removeIf(f -> Modifier.isStatic(f.getModifiers())); - return ret; + Set ret = new HashSet<>(); + Queue> cq = new ArrayDeque<>(); + cq.add(options); + while (!cq.isEmpty()) { + Class curr = cq.remove(); + for (Field f : curr.getDeclaredFields()) { + if (f.getAnnotation(Option.class) != null) { + ret.add(f); + } + } + for (Field f : curr.getFields()) { + if (f.getAnnotation(Option.class) != null) { + ret.add(f); } - ); + } + Class sc = curr.getSuperclass(); + if (sc != null) { + cq.add(sc); + } + cq.addAll(Arrays.asList(curr.getInterfaces())); + } + ret.removeIf(f -> Modifier.isStatic(f.getModifiers())); + return ret; } /** @@ -349,33 +339,29 @@ public static Set getOptionFields(Class options) { * @return all of the fields which subclass {@link Options}. */ public static Set getOptions(Class options) { - return AccessController.doPrivileged((PrivilegedAction>) - () -> { - Set ret = new HashSet<>(); - Queue> cq = new ArrayDeque<>(); - cq.add(options); - while (!cq.isEmpty()) { - Class curr = cq.remove(); - for (Field f : curr.getDeclaredFields()) { - if (Options.class.isAssignableFrom(f.getType())) { - ret.add(f); - } - } - for (Field f : curr.getFields()) { - if (Options.class.isAssignableFrom(f.getType())) { - ret.add(f); - } - } - Class sc = curr.getSuperclass(); - if (sc != null) { - cq.add(sc); - } - cq.addAll(Arrays.asList(curr.getInterfaces())); - } - ret.removeIf(f -> Modifier.isStatic(f.getModifiers())); - return ret; + Set ret = new HashSet<>(); + Queue> cq = new ArrayDeque<>(); + cq.add(options); + while (!cq.isEmpty()) { + Class curr = cq.remove(); + for (Field f : curr.getDeclaredFields()) { + if (Options.class.isAssignableFrom(f.getType())) { + ret.add(f); + } + } + for (Field f : curr.getFields()) { + if (Options.class.isAssignableFrom(f.getType())) { + ret.add(f); } - ); + } + Class sc = curr.getSuperclass(); + if (sc != null) { + cq.add(sc); + } + cq.addAll(Arrays.asList(curr.getInterfaces())); + } + ret.removeIf(f -> Modifier.isStatic(f.getModifiers())); + return ret; } /** @@ -387,55 +373,51 @@ public static Set getOptions(Class options) { */ @SuppressWarnings("unchecked") public static Set> getAllOptions(Class options) { - return AccessController.doPrivileged((PrivilegedAction>>) - () -> { - // The Pair is (classname,fieldname) - Map,Pair> ret = new LinkedHashMap<>(); - Map,Class> tempSet = new HashMap<>(); - ret.put(options,new Pair<>("root","root")); - Queue> cq = new ArrayDeque<>(); - cq.add(options); - while (!cq.isEmpty()) { - Class curr = cq.remove(); - String currName = curr.getName(); - for (Field f : curr.getDeclaredFields()) { - if (Options.class.isAssignableFrom(f.getType()) && !Modifier.isStatic(f.getModifiers())) { - Class nextOptions = (Class) f.getType(); - // Add to the processing queue, via a map to make sure we don't double count fields. - tempSet.put(new Pair<>(currName,f.getName()),nextOptions); - } - } - for (Field f : curr.getFields()) { - if (Options.class.isAssignableFrom(f.getType()) && !Modifier.isStatic(f.getModifiers())) { - Class nextOptions = (Class) f.getType(); - // Add to the processing queue, via a map to make sure we don't double count fields. - tempSet.put(new Pair<>(currName,f.getName()),nextOptions); - } - } - Class sc = curr.getSuperclass(); - if (sc != null) { - cq.add(sc); - } - cq.addAll(Arrays.asList(curr.getInterfaces())); - - // Append the processing queue to the returned set, validating that each one is unique. - for (Map.Entry,Class> e : tempSet.entrySet()) { - if (ret.containsKey(e.getValue())) { - Pair otherOccurrence = ret.get(e.getValue()); - String firstOccurrence = otherOccurrence.getA()+"."+otherOccurrence.getB(); - String thisOccurrence = e.getKey().getA() + "." + e.getKey().getB(); - throw new ArgumentException(firstOccurrence,thisOccurrence,"There are two instances of " + e.getValue().getName() + " in this Options tree."); - } else { - ret.put(e.getValue(),e.getKey()); - cq.add(e.getValue()); - } - } + // The Pair is (classname,fieldname) + Map, Pair> ret = new LinkedHashMap<>(); + Map, Class> tempSet = new HashMap<>(); + ret.put(options, new Pair<>("root", "root")); + Queue> cq = new ArrayDeque<>(); + cq.add(options); + while (!cq.isEmpty()) { + Class curr = cq.remove(); + String currName = curr.getName(); + for (Field f : curr.getDeclaredFields()) { + if (Options.class.isAssignableFrom(f.getType()) && !Modifier.isStatic(f.getModifiers())) { + Class nextOptions = (Class) f.getType(); + // Add to the processing queue, via a map to make sure we don't double count fields. + tempSet.put(new Pair<>(currName, f.getName()), nextOptions); + } + } + for (Field f : curr.getFields()) { + if (Options.class.isAssignableFrom(f.getType()) && !Modifier.isStatic(f.getModifiers())) { + Class nextOptions = (Class) f.getType(); + // Add to the processing queue, via a map to make sure we don't double count fields. + tempSet.put(new Pair<>(currName, f.getName()), nextOptions); + } + } + Class sc = curr.getSuperclass(); + if (sc != null) { + cq.add(sc); + } + cq.addAll(Arrays.asList(curr.getInterfaces())); - // Flush the temporary set. - tempSet.clear(); - } - return new LinkedHashSet<>(ret.keySet()); + // Append the processing queue to the returned set, validating that each one is unique. + for (Map.Entry, Class> e : tempSet.entrySet()) { + if (ret.containsKey(e.getValue())) { + Pair otherOccurrence = ret.get(e.getValue()); + String firstOccurrence = otherOccurrence.getA() + "." + otherOccurrence.getB(); + String thisOccurrence = e.getKey().getA() + "." + e.getKey().getB(); + throw new ArgumentException(firstOccurrence, thisOccurrence, "There are two instances of " + e.getValue().getName() + " in this Options tree."); + } else { + ret.put(e.getValue(), e.getKey()); + cq.add(e.getValue()); } - ); + } + + // Flush the temporary set. + tempSet.clear(); + } + return new LinkedHashSet<>(ret.keySet()); } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertyException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertyException.java index 3d4bda23..e6f3b326 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertyException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertyException.java @@ -2,7 +2,7 @@ * Copyright 1999-2004 Carnegie Mellon University. * Portions Copyright 2004 Sun Microsystems, Inc. * Portions Copyright 2004 Mitsubishi Electric Research Laboratories. - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java index 2ebed679..d02c0d56 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -43,10 +43,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Paths; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.OffsetTime; @@ -62,7 +58,6 @@ import java.util.Map; import java.util.Objects; import java.util.Queue; -import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -161,27 +156,40 @@ protected PropertySheet(Class confClass, propValues.putAll(rpd.getProperties()); } + /** + * Copy constructor. Does not copy the instantiated object, and disconnects it from that object. + * @param other The property sheet to copy. + */ protected PropertySheet(PropertySheet other) { + this(other, other.cm); + } + + /** + * Copy constructor. Does not copy the instantiated object, and disconnects it from that object. + * @param other The property sheet to copy. + * @param newCM The new configuration manager. + */ + protected PropertySheet(PropertySheet other, ConfigurationManager newCM) { this.ownerClass = other.ownerClass; - this.cm = other.cm; + this.cm = newCM; this.instanceName = other.instanceName; this.data = other.data; this.propValues.putAll(other.propValues); this.redacted.addAll(other.redacted); } - public boolean isExportable() { - return data.isExportable(); - } - - public boolean isImportable() { - return data.isImportable(); - } - + /** + * Returns an unmodifiable view on the property names. + * @return The property names. + */ public Set getPropertyNames() { return Collections.unmodifiableSet(propValues.keySet()); } + /** + * Returns an unmodifiable view on the field names which should be redacted. + * @return The redacted field names. + */ public Set getRedactedFieldNames() { return Collections.unmodifiableSet(redacted); } @@ -213,18 +221,14 @@ private String flattenString(String name, String value) { return cm.getImmutableGlobalProperties().replaceGlobalProperties(getInstanceName(), name, value); } + /** + * The name of this configured object in the configuration file. + * @return The name. + */ public String getInstanceName() { return instanceName; } - public long getLeaseTime() { - return data.getLeaseTime(); - } - - public String getEntriesName() { - return data.getEntriesName(); - } - /** * Is this property sheet instantiated? * @return true if the owner of this property sheet is already instantiated. @@ -233,6 +237,10 @@ public synchronized boolean isInstantiated() { return owner != null; } + /** + * The class object for this property sheet's type. + * @return The class. + */ public Class getOwnerClass() { return ownerClass; } @@ -286,24 +294,20 @@ public synchronized T getOwner(ComponentListener cl, boolean reuseComponent) // Should we load a serialized form? if (data.getSerializedForm() != null) { String actualLocation = flattenString("", data.getSerializedForm()); - T obj = AccessController.doPrivileged((PrivilegedAction) () -> { - InputStream serStream = IOUtil.getInputStreamForLocation(actualLocation); - if (serStream != null) { - try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(serStream, 1024 * 1024))) { - Object deser = ois.readObject(); - return ownerClass.cast(deser); - } catch (IOException ex) { - throw new PropertyException(ex, instanceName, null, - "Error reading serialized form from " + actualLocation); - } catch (ClassNotFoundException ex) { - throw new PropertyException(ex, instanceName, null, - "Serialized class not found at " + actualLocation); - } - } else { - return null; - } - } - ); + T obj = null; + InputStream serStream = IOUtil.getInputStreamForLocation(actualLocation); + if (serStream != null) { + try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(serStream, 1024 * 1024))) { + Object deser = ois.readObject(); + obj = ownerClass.cast(deser); + } catch (IOException ex) { + throw new PropertyException(ex, instanceName, null, + "Error reading serialized form from " + actualLocation); + } catch (ClassNotFoundException ex) { + throw new PropertyException(ex, instanceName, null, + "Serialized class not found at " + actualLocation); + } + } if (obj != null) { owner = obj; return obj; @@ -323,25 +327,21 @@ public synchronized T getOwner(ComponentListener cl, boolean reuseComponent) logger.info(String.format("Creating %s type %s", instanceName, ownerClass.getName())); } - owner = AccessController.doPrivileged((PrivilegedExceptionAction) () -> { - T newObj; - try { - Constructor constructor = ownerClass.getDeclaredConstructor(); - boolean isAccessible = constructor.isAccessible(); - constructor.setAccessible(true); - newObj = constructor.newInstance(); - constructor.setAccessible(isAccessible); - } catch (NoSuchMethodException ex) { - throw new PropertyException(ex, instanceName, null, - "No-args constructor not found for class " + ownerClass); - } catch (InvocationTargetException ex) { - throw new InternalConfigurationException(ex, instanceName, null, - "Can't instantiate class " + ownerClass); - } - setConfiguredFields(newObj, this); - return newObj; - } - ); + T newObj; + try { + Constructor constructor = ownerClass.getDeclaredConstructor(); + constructor.setAccessible(true); + newObj = constructor.newInstance(); + constructor.setAccessible(false); + } catch (NoSuchMethodException ex) { + throw new PropertyException(ex, instanceName, null, + "No-args constructor not found for class " + ownerClass); + } catch (InvocationTargetException ex) { + throw new InternalConfigurationException(ex, instanceName, null, + "Can't instantiate class " + ownerClass); + } + setConfiguredFields(newObj, this); + owner = newObj; try { owner.postConfig(); } catch (IOException e) { @@ -367,17 +367,14 @@ public synchronized T getOwner(ComponentListener cl, boolean reuseComponent) } } } - } catch (PrivilegedActionException e) { - Exception inner = e.getException(); - if (inner instanceof IllegalAccessException) { - throw new InternalConfigurationException(inner, getInstanceName(), null, "Can't access class " - + ownerClass); - } else if (inner instanceof InstantiationException) { - throw new InternalConfigurationException(inner, getInstanceName(), null, "Can't instantiate class " - + ownerClass); - } else { - throw new InternalConfigurationException(inner, getInstanceName(), null, "Unexpected exception thrown by " + ownerClass); - } + } catch (IllegalAccessException e) { + throw new InternalConfigurationException(e, getInstanceName(), null, "Can't access class " + ownerClass); + } catch (InstantiationException e) { + throw new InternalConfigurationException(e, getInstanceName(), null, "Can't instantiate class " + ownerClass); + } catch (PropertyException e) { + throw e; + } catch (Exception e) { + throw new InternalConfigurationException(e, getInstanceName(), null, "Unexpected exception thrown by " + ownerClass); } return owner; @@ -396,7 +393,6 @@ private static void setConfiguredFields(T o, PropertySh Class curClass = o.getClass(); Set fields = getAllFields(curClass); for (Field f : fields) { - boolean accessible = f.isAccessible(); f.setAccessible(true); Config configAnnotation = f.getAnnotation(Config.class); ConfigurableName nameAnnotation = f.getAnnotation(ConfigurableName.class); @@ -432,7 +428,7 @@ private static void setConfiguredFields(T o, PropertySh ListProperty vals = (ListProperty) ps.propValues.get(f.getName()); f.set(o, parseListField(ps.getConfigurationManager(), ps.getInstanceName(), f.getName(), f.getType(), genericList.get(0), ft, vals)); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new PropertyException(ps.getInstanceName(), f.getName(), "Failed to extract generic type arguments from field. Found: " + genericList.toString()); } } else if (FieldType.simpleTypes.contains(ft)) { @@ -453,29 +449,29 @@ private static void setConfiguredFields(T o, PropertySh MapProperty mapVals = (MapProperty) ps.propValues.get(f.getName()); f.set(o, parseMapField(ps.getConfigurationManager(), ps.getInstanceName(), f.getName(), genericList.get(1), mapVals)); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new PropertyException(ps.getInstanceName(), f.getName(), "Failed to extract generic type arguments from field. Found: " + genericList.toString()); } } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new PropertyException(ps.getInstanceName(), f.getName(), "Unknown field type " + ft.toString()); } } else if (nameAnnotation != null) { if (String.class.isAssignableFrom(f.getType())) { f.set(o, ps.getInstanceName()); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new PropertyException(ps.getInstanceName(), f.getName(), "Assigning ConfigurableName to non-String type " + f.getType().getName()); } } else if (cmAnnotation != null) { if (ConfigurationManager.class.isAssignableFrom(f.getType())) { f.set(o, ps.getConfigurationManager()); } else { - f.setAccessible(accessible); + f.setAccessible(false); throw new PropertyException(ps.getInstanceName(), f.getName(), "Assigning ConfigManager to non-ConfigurationManager type " + f.getType().getName()); } } - f.setAccessible(accessible); + f.setAccessible(false); } } @@ -630,7 +626,7 @@ static Object parseArrayField(ConfigurationManager cm, String instanceName, Stri break; } classVals.removeAll(removeList); - if (classVals.size() > 0) { + if (!classVals.isEmpty()) { throw new PropertyException(instanceName,fieldName,"Found class values in a primitive array"); } return output; @@ -714,7 +710,7 @@ static Object parseListField(ConfigurationManager cm, String instanceName, Strin break; } classVals.removeAll(removeList); - if (classVals.size() > 0) { + if (!classVals.isEmpty()) { throw new PropertyException(instanceName,fieldName,"Found class values in a primitive array"); } return output; @@ -808,13 +804,6 @@ static Object parseSimpleField(ConfigurationManager cm, String instanceName, Str } catch (MalformedURLException ex) { throw new PropertyException(ex, instanceName, fieldName, String.format("%s is not a valid URL", val)); } - case RANDOM: - logger.warning("@Config on Random fields is deprecated for removal in a future version."); - try { - return new Random(Integer.parseInt(val)); - } catch (NumberFormatException ex) { - throw new PropertyException(ex, instanceName, fieldName, String.format("The seed %s is not an integer", val)); - } case ENUM: try { return Enum.valueOf((Class) fieldClass, val); @@ -834,7 +823,7 @@ static Object parseSimpleField(ConfigurationManager cm, String instanceName, Str /** * Extracts the classes representing the generic type parameters for the supplied field. - * + *

* It ignores types which aren't classes. If you've got those, you're on your own. * * @param f The field to inspect. @@ -845,8 +834,7 @@ public static List> getGenericClass(Field f) { Type genericType = f.getGenericType(); - if (genericType instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) genericType; + if (genericType instanceof ParameterizedType pt) { for (Type t : pt.getActualTypeArguments()) { //update the type to the raw type if appropriate if(t instanceof ParameterizedType) { @@ -863,6 +851,9 @@ public static List> getGenericClass(Field f) { return list; } + /** + * Removes the reference to the constructed object. + */ public synchronized void clearOwner() { owner = null; } @@ -877,7 +868,7 @@ public Class getConfigurableClass() { /** * Sets the raw property to the given name. - * + *

* If the owner is instantiated it *does not* change the field in the owner. * * @param key the simple property name @@ -903,9 +894,9 @@ public Property getProperty(String name) { } /** - * Gets the owning property manager + * Gets the owning configuration manager * - * @return the property manager + * @return the configuration manager */ public ConfigurationManager getConfigurationManager() { return cm; @@ -928,21 +919,16 @@ public Set getRegisteredProperties() { return Collections.unmodifiableSet(registeredProperties.keySet()); } - public synchronized void setCM(ConfigurationManager cm) { - this.cm = cm; - } - /** * Returns true if two property sheet define the same object in terms of * configuration. The owner (and the parent configuration manager) are not * expected to be the same. */ public boolean equals(Object obj) { - if (obj == null || !(obj instanceof PropertySheet)) { + if (!(obj instanceof PropertySheet ps)) { return false; } - PropertySheet ps = (PropertySheet) obj; return propValues.equals(ps.propValues); } @@ -951,37 +937,46 @@ public int hashCode() { return Objects.hash(propValues); } + /** + * Copies this property sheet (disconnecting it from the constructed object). + * @return A copy of this property sheet. + */ public PropertySheet copy() { return new PropertySheet<>(this); } + /** + * Copies this property sheet to a new configuration manager. + * @param newCM The new configuration manager. + * @return A copy of this property sheet. + */ + public PropertySheet copy(ConfigurationManager newCM) { + return new PropertySheet<>(this, newCM); + } + /** * Gets all of the fields associated with a class by walking up the class * tree. Handles super classes, as well as interfaces. * - * @param configurable the class who's fields we wish to walk. + * @param configurable the class whose fields we wish to walk. * @return all of the fields, so they can be checked for annotations. */ public static Set getAllFields(Class configurable) { - return AccessController.doPrivileged((PrivilegedAction>) - () -> { - Set ret = new HashSet<>(); - Queue> cq = new ArrayDeque<>(); - cq.add(configurable); - while (!cq.isEmpty()) { - Class curr = cq.remove(); - ret.addAll(Arrays.asList(curr.getDeclaredFields())); - ret.addAll(Arrays.asList(curr.getFields())); - Class sc = curr.getSuperclass(); - if (sc != null) { - cq.add(sc); - } - cq.addAll(Arrays.asList(curr.getInterfaces())); - } - ret.removeIf(f -> Modifier.isStatic(f.getModifiers())); - return ret; - } - ); + Set ret = new HashSet<>(); + Queue> cq = new ArrayDeque<>(); + cq.add(configurable); + while (!cq.isEmpty()) { + Class curr = cq.remove(); + ret.addAll(Arrays.asList(curr.getDeclaredFields())); + ret.addAll(Arrays.asList(curr.getFields())); + Class sc = curr.getSuperclass(); + if (sc != null) { + cq.add(sc); + } + cq.addAll(Arrays.asList(curr.getInterfaces())); + } + ret.removeIf(f -> Modifier.isStatic(f.getModifiers())); + return ret; } /** diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/SerializedObject.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/SerializedObject.java index 54352bb9..00b98449 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/SerializedObject.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/SerializedObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -34,8 +34,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; /** * A class to hold the information for a serialized Object that is defined in a @@ -53,24 +51,46 @@ public final class SerializedObject { private T object; + /** + * The configuration for a serialized object. + * @param name The name of the object in the config file. + * @param location The location of the serialized file. + * @param className The class name of the object. + */ public SerializedObject(String name, String location, String className) { this.name = name; this.location = location; this.className = className; } - public void setConfigurationManager(ConfigurationManager configurationManager) { + /** + * Sets the configuration manager that hosts this serialized object. + * @param configurationManager The host configuration manager. + */ + void setConfigurationManager(ConfigurationManager configurationManager) { this.configurationManager = configurationManager; } + /** + * The name of the serialized object. + * @return The name. + */ public String getName() { return name; } + /** + * The location of the serialized object (either a path on disk or a classpath URL). + * @return The location. + */ public String getLocation() { return location; } + /** + * The class name of the serialized object. + * @return The class name. + */ public String getClassName() { return className; } @@ -81,30 +101,28 @@ public String getClassName() { * @throws PropertyException if the object cannot be deserialized. */ @SuppressWarnings("unchecked")// throws PropertyException if the serialised type doesn't match the class name. - public final T getObject() throws PropertyException { + public T getObject() throws PropertyException { if (object == null) { - object = AccessController.doPrivileged((PrivilegedAction) () -> { - String actualLocation = configurationManager.getImmutableGlobalProperties().replaceGlobalProperties(name, null, location); - InputStream serStream = IOUtil.getInputStreamForLocation(actualLocation); - try { - Class objectClass = (Class) Class.forName(className); - if (serStream != null) { - try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(serStream, 1024 * 1024))) { - // - // Read the object and cast it into this class for return; - return objectClass.cast(ois.readObject()); - } catch (ClassCastException ex) { - throw new PropertyException(ex, name, "Failed to cast object to type " + objectClass.getName()); - } catch (IOException ex) { - throw new PropertyException(ex, name, "Error reading serialized form from " + actualLocation); - } - } else { - throw new PropertyException(name, "Failed to open stream from location " + actualLocation); + String actualLocation = configurationManager.getImmutableGlobalProperties().replaceGlobalProperties(name, null, location); + InputStream serStream = IOUtil.getInputStreamForLocation(actualLocation); + try { + Class objectClass = (Class) Class.forName(className); + if (serStream != null) { + try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(serStream, 1024 * 1024))) { + // + // Read the object and cast it into this class for return; + object = objectClass.cast(ois.readObject()); + } catch (ClassCastException ex) { + throw new PropertyException(ex, name, "Failed to cast object to type " + objectClass.getName()); + } catch (IOException ex) { + throw new PropertyException(ex, name, "Error reading serialized form from " + actualLocation); } - } catch (ClassNotFoundException ex) { - throw new PropertyException(ex, name, "Serialized class " + className + " not found for " + actualLocation); + } else { + throw new PropertyException(name, "Failed to open stream from location " + actualLocation); } - }); + } catch (ClassNotFoundException ex) { + throw new PropertyException(ex, name, "Serialized class " + className + " not found for " + actualLocation); + } } return object; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/UsageException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/UsageException.java index 2b6ccd03..c2f90183 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/UsageException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/UsageException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -32,10 +32,18 @@ * An exception which denotes the usage statement was requested. */ public class UsageException extends ArgumentException { + /** + * Constructs a UsageException with the specified message. + * @param msg The help message for the options. + */ public UsageException(String msg) { super("--usage", msg); } + /** + * The usage/help message. + * @return The usage message. + */ public String getUsage() { return msg; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoader.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoader.java index 5ef6cb1a..f6029f70 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoader.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -71,7 +71,7 @@ public interface ConfigLoader { /** * Loads configuration from the stream. - * + *

* Note: does not close the stream. * @param stream The stream to load from. * @throws ConfigLoaderException Thrown if the configuration is malformed. diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoaderException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoaderException.java index 7ad57479..4bdc1eb1 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoaderException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigLoaderException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -33,14 +33,27 @@ */ public class ConfigLoaderException extends RuntimeException { + /** + * Constructs a config loader exception wrapping the supplied exception. + * @param e The exception to wrap. + */ public ConfigLoaderException(Exception e) { super(e); } + /** + * Constructs a config loader exception wrapping the supplied exception with a new message. + * @param e The exception to wrap. + * @param msg The new message. + */ public ConfigLoaderException(Exception e, String msg) { super(msg,e); } + /** + * Constructs a config loader exception with the specified message. + * @param msg The exception message. + */ public ConfigLoaderException(String msg) { super(msg); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigWriterException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigWriterException.java index e4abe993..3ac8d066 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigWriterException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/ConfigWriterException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -33,6 +33,10 @@ */ public class ConfigWriterException extends RuntimeException { + /** + * Constructs a config writer exception wrapping the supplied exception. + * @param e The exception to wrap. + */ public ConfigWriterException(Exception e) { super(e); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/FileFormatFactory.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/FileFormatFactory.java index f8023710..bd212034 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/FileFormatFactory.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/FileFormatFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -40,14 +40,34 @@ */ public interface FileFormatFactory { + /** + * The file extension this factory supports. + * @return The file extension. + */ public String getExtension(); + /** + * Constructs a loader for this file format. + * @param parent The parent loader for discovering parent components. + * @param rpdMap The current property map. + * @param existingRPD Any existing configurations. + * @param serializedObjects Any serialized objects. + * @param globalProperties The global property map. + * @return A loader for this file format. + * @throws ConfigLoaderException If the loader could not be instantiated. + */ public ConfigLoader getLoader(URLLoader parent, Map rpdMap, Map existingRPD, Map serializedObjects, GlobalProperties globalProperties) throws ConfigLoaderException; + /** + * Constructs a writer for this file format. + * @param os The output stream to write to. + * @return A writer for this file format. + * @throws ConfigWriterException If the writer could not be instantiated. + */ public ConfigWriter getWriter(OutputStream os) throws ConfigWriterException; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/URLLoader.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/URLLoader.java index d550a6ab..bceeb64a 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/URLLoader.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/io/URLLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -42,7 +42,7 @@ /** * Loads in configurations from URLs. Manages the queue of URLs to be processed. */ -public class URLLoader { +public final class URLLoader { private final Map loaderMap = new HashMap<>(); @@ -68,6 +68,10 @@ public URLLoader(Queue urlQueue, Map formatFacto this.existingRPD = existingRPD; } + /** + * Loads the URLs from the URL queue. + * @throws ConfigLoaderException If a URL contained an invalid configuration. + */ public void load() throws ConfigLoaderException { URL curURL; while (!urlQueue.isEmpty()) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java index e2997982..550aedd2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -31,8 +31,6 @@ import com.oracle.labs.mlrg.olcut.config.ConfigurationManager; import com.oracle.labs.mlrg.olcut.config.PropertyException; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Map; import java.util.Properties; import java.util.regex.Matcher; @@ -63,7 +61,7 @@ public GlobalProperties(GlobalProperties globalProperties) { * Imports the system properties into this GlobalProperties. */ public final void importSystemProperties() { - Properties props = AccessController.doPrivileged((PrivilegedAction) System::getProperties); + Properties props = System.getProperties(); importProperties(props); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java index d0a1b026..7067f8ee 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java @@ -2,7 +2,7 @@ * Copyright 1999-2004 Carnegie Mellon University. * Portions Copyright 2004 Sun Microsystems, Inc. * Portions Copyright 2004 Mitsubishi Electric Research Laboratories. - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -35,8 +35,6 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -109,24 +107,19 @@ public SAXLoader(URLLoader parent, Map rpdMap, Map) - () -> { - if (url.getProtocol().equals("file")) { - String workingDir = new File(url.getFile()).getParent(); - handler.setCurWorkingDir(workingDir); - } else if (IOUtil.isDisallowedProtocol(url)) { - throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); - } else { - handler.setCurWorkingDir(""); - } - try (InputStream is = url.openStream()) { - innerLoad(is, url.toString()); - } catch (IOException e) { - throw new ConfigLoaderException(e, e.getMessage()); - } - return null; - } - ); + if (url.getProtocol().equals("file")) { + String workingDir = new File(url.getFile()).getParent(); + handler.setCurWorkingDir(workingDir); + } else if (IOUtil.isDisallowedProtocol(url)) { + throw new ConfigLoaderException("Unable to load configurations from URLs with protocol: " + url.getProtocol()); + } else { + handler.setCurWorkingDir(""); + } + try (InputStream is = url.openStream()) { + innerLoad(is, url.toString()); + } catch (IOException e) { + throw new ConfigLoaderException(e, e.getMessage()); + } } /** @@ -213,36 +206,7 @@ public void startElement(String uri, String localName, String qName, String curComponent = attributes.getValue(ConfigLoader.NAME); String curType = attributes.getValue(ConfigLoader.TYPE); String override = attributes.getValue(ConfigLoader.INHERIT); - String export = attributes.getValue(ConfigLoader.EXPORT); - String entriesName = attributes.getValue(ConfigLoader.ENTRIES); String serializedForm = attributes.getValue(ConfigLoader.SERIALIZED); - boolean exportable = Boolean.parseBoolean(export); - String imp = attributes.getValue(ConfigLoader.IMPORT); - boolean importable = Boolean.parseBoolean(imp); - String lt = attributes.getValue(ConfigLoader.LEASETIME); - if (export == null && lt != null) { - throw new SAXParseException("lease timeout " - + lt - + " specified for component that" - + " does not have export set", - locator); - } - long leaseTime = ConfigurationData.DEFAULT_LEASE_TIME; - if (lt != null) { - try { - leaseTime = Long.parseLong(lt); - if (leaseTime < 0) { - throw new SAXParseException("lease timeout " - + lt - + " must be greater than 0", - locator); - } - } catch (NumberFormatException nfe) { - throw new SAXParseException("lease timeout " - + lt + " must be a long", - locator); - } - } // // Check for a badly formed component tag. @@ -277,13 +241,13 @@ public void startElement(String uri, String localName, String qName, if (curType == null) { curType = spd.getClassName(); } - rpd = new ConfigurationData(curComponent, curType, spd.getProperties(), serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(curComponent, curType, spd.getProperties(), serializedForm); overriding = true; } else { if (rpdMap.get(curComponent) != null) { throw new SAXParseException("duplicate definition for " + curComponent, locator); } - rpd = new ConfigurationData(curComponent, curType, serializedForm, entriesName, exportable, importable, leaseTime); + rpd = new ConfigurationData(curComponent, curType, serializedForm); } break; case PROPERTY: { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java index dc51b7c3..c6697ec6 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java @@ -121,14 +121,6 @@ public void writeComponent(Map attributes, Map writer.writeStartElement(ConfigLoader.COMPONENT); writer.writeAttribute(ConfigLoader.NAME, attributes.get(ConfigLoader.NAME)); writer.writeAttribute(ConfigLoader.TYPE, attributes.get(ConfigLoader.TYPE)); - writer.writeAttribute(ConfigLoader.EXPORT, attributes.get(ConfigLoader.EXPORT)); - writer.writeAttribute(ConfigLoader.IMPORT, attributes.get(ConfigLoader.IMPORT)); - if (attributes.containsKey(ConfigLoader.ENTRIES)) { - writer.writeAttribute(ConfigLoader.ENTRIES, attributes.get(ConfigLoader.ENTRIES)); - } - if (attributes.containsKey(ConfigLoader.LEASETIME)) { - writer.writeAttribute(ConfigLoader.LEASETIME, attributes.get(ConfigLoader.LEASETIME)); - } if (attributes.containsKey(ConfigLoader.SERIALIZED)) { writer.writeAttribute(ConfigLoader.SERIALIZED, attributes.get(ConfigLoader.SERIALIZED)); } @@ -194,14 +186,6 @@ public void writeComponent(Map attributes, Map writer.writeEmptyElement(ConfigLoader.COMPONENT); writer.writeAttribute(ConfigLoader.NAME, attributes.get(ConfigLoader.NAME)); writer.writeAttribute(ConfigLoader.TYPE, attributes.get(ConfigLoader.TYPE)); - writer.writeAttribute(ConfigLoader.EXPORT, attributes.get(ConfigLoader.EXPORT)); - writer.writeAttribute(ConfigLoader.IMPORT, attributes.get(ConfigLoader.IMPORT)); - if (attributes.containsKey(ConfigLoader.ENTRIES)) { - writer.writeAttribute(ConfigLoader.ENTRIES, attributes.get(ConfigLoader.ENTRIES)); - } - if (attributes.containsKey(ConfigLoader.LEASETIME)) { - writer.writeAttribute(ConfigLoader.LEASETIME, attributes.get(ConfigLoader.LEASETIME)); - } if (attributes.containsKey(ConfigLoader.SERIALIZED)) { writer.writeAttribute(ConfigLoader.SERIALIZED, attributes.get(ConfigLoader.SERIALIZED)); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java index 53229bf0..0a676f1d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -891,12 +891,11 @@ public static void writeObject(Provenancable readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException { ConfiguredObjectProvenance provenance = (ConfiguredObjectProvenance) inputStream.readObject(); List configurationData = ProvenanceUtil.extractConfiguration(provenance); - String componentName = configurationData.get(0).getName(); + String componentName = configurationData.getFirst().getName(); ConfigurationManager cm = new ConfigurationManager(); cm.addConfiguration(configurationData); @SuppressWarnings("unchecked") Provenancable provenancable = (Provenancable) cm.lookup(componentName); - cm.close(); return provenancable; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java index f50a613f..8d694ba3 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -59,8 +59,6 @@ import java.lang.reflect.Field; import java.net.URL; import java.nio.file.Path; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.OffsetTime; @@ -80,13 +78,12 @@ /** * A pile of reflection based magic used to automatically extract the values of configurable - * fields. Supports all the types used by the configuration system, except for - * Random as it's impossible to generate a true provenance for a {@link java.util.Random} instance. - * + * fields. Supports all the types used by the configuration system. + *

* This class can be used as the basis for ConfiguredObjectProvenance implementations, it * automatically extracts any configured fields from the host object and stores the values * in the appropriate provenance type. - * + *

* It is recommended that subclasses of this class implement a static method which accepts * a Map<String,Provenance> and returns a {@link ExtractedInfo}. * As with all subclasses of {@link com.oracle.labs.mlrg.olcut.provenance.ObjectProvenance} @@ -112,7 +109,7 @@ public abstract class SkeletalConfiguredObjectProvenance implements ConfiguredOb protected SkeletalConfiguredObjectProvenance(T host, String hostShortName) { this.className = host.getClass().getName(); this.hostShortName = hostShortName; - Map provMap = AccessController.doPrivileged((PrivilegedAction>)() -> getConfiguredFields(host)); + Map provMap = getConfiguredFields(host); this.configuredParameters = Collections.unmodifiableMap(provMap); } @@ -198,7 +195,6 @@ private static Map getConfiguredFie Set fields = PropertySheet.getAllFields(hostClass); try { for (Field f : fields) { - boolean accessible = f.isAccessible(); f.setAccessible(true); // if configurable and not redacted Config configAnnotation = f.getAnnotation(Config.class); @@ -266,14 +262,13 @@ private static Map getConfiguredFie } break; } - case RANDOM: default: logger.log(Level.SEVERE, "Automatic provenance not supported for field type " + ft + ", field '" + f.getName() + "' not recorded."); break; } } } - f.setAccessible(accessible); + f.setAccessible(false); } } catch (ClassCastException e) { logger.log(Level.SEVERE, "Failed to cast field from host object " + host.toString() + ". Fields not recorded.", e); @@ -551,9 +546,6 @@ private static Optional convertPrimitive(FieldType ft, Class fiel } else { return Optional.of(new LongProvenance(fieldName, ((AtomicLong) o).get())); } - case RANDOM: - logger.log(Level.SEVERE, "Random is deprecated and not supported in the provenance system, field '" + fieldName + "' not recorded."); - return Optional.empty(); case BYTE_ARRAY: case CHAR_ARRAY: case SHORT_ARRAY: diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java index bbf79dd0..05bc3a72 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java @@ -640,14 +640,10 @@ public static boolean isDisallowedProtocol(URL url) { if (protocol == null) { return true; } - switch (protocol) { - case "http": - case "https": - case "ftp": - return true; - default: - return false; - } + return switch (protocol) { + case "http", "https", "ftp" -> true; + default -> false; + }; } public static class NamesPathIterator implements Iterator{ diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LabsLogFormatter.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LabsLogFormatter.java index df4326b2..1350e8b5 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LabsLogFormatter.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LabsLogFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -29,8 +29,6 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; @@ -50,7 +48,6 @@ public class LabsLogFormatter extends Formatter { private boolean terse; - /** * Sets the level of output * @@ -60,7 +57,6 @@ public void setTerse(boolean terse) { this.terse = terse; } - /** * Retrieves the level of output * @@ -70,7 +66,6 @@ public boolean getTerse() { return terse; } - /** * Formats the given log record and return the formatted string. * @@ -113,20 +108,15 @@ public static void setAllLogFormatters() { } public static void setAllLogFormatters(Level level) { - AccessController.doPrivileged((PrivilegedAction) - () -> { - for (Handler h : Logger.getLogger("").getHandlers()) { - h.setLevel(level); - h.setFormatter(new LabsLogFormatter()); - try { - h.setEncoding("utf-8"); - } catch (Exception ex) { - logger.severe("Error setting output encoding"); - } - } - return null; + for (Handler h : Logger.getLogger("").getHandlers()) { + h.setLevel(level); + h.setFormatter(new LabsLogFormatter()); + try { + h.setEncoding("utf-8"); + } catch (Exception ex) { + logger.severe("Error setting output encoding"); } - ); + } } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SimpleLabsLogFormatter.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SimpleLabsLogFormatter.java index 1aeacf53..8c49c1c2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SimpleLabsLogFormatter.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SimpleLabsLogFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -29,8 +29,6 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; @@ -102,20 +100,15 @@ public static void setAllLogFormatters() { } public static void setAllLogFormatters(Level level) { - AccessController.doPrivileged((PrivilegedAction) - () -> { - for (Handler h : Logger.getLogger("").getHandlers()) { - h.setLevel(level); - h.setFormatter(new SimpleLabsLogFormatter()); - try { - h.setEncoding("utf-8"); - } catch (Exception ex) { - logger.severe("Error setting output encoding"); - } - } - return null; - } - ); + for (Handler h : Logger.getLogger("").getHandlers()) { + h.setLevel(level); + h.setFormatter(new SimpleLabsLogFormatter()); + try { + h.setEncoding("utf-8"); + } catch (Exception ex) { + logger.severe("Error setting output encoding"); + } + } } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StopWatch.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StopWatch.java index 6c152851..36cd993d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StopWatch.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StopWatch.java @@ -92,6 +92,7 @@ public void reset() { * @deprecated Ambiguous units, use unit-specific get methods instead. Behavior of this method is undefined in subclasses. * @return The number of milliseconds on the timer. */ + @Deprecated public long getTime() { return time; } @@ -111,6 +112,7 @@ public long getTimeMillis() { * * @return most recent start/stop time in milliseconds */ + @Deprecated public long getLastTime() { return lastTime; } @@ -129,6 +131,7 @@ public long getLastTimeMillis() { * @deprecated Ambiguous units, use unit-specific get methods instead. Behavior of this method is undefined in subclasses. * @return the last start time */ + @Deprecated public long getLastStart() { return lastStart; } @@ -147,6 +150,7 @@ public long getLastStartMillis() { * @deprecated Ambiguous units, use unit-specific get methods instead. Behavior of this method is undefined in subclasses. * @return The average time. */ + @Deprecated public double getAvgTime() { return getTime() / (double) clicks; } diff --git a/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/BooleanOptionTest.java b/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/BooleanOptionTest.java index 2fec690d..13bdbcc1 100644 --- a/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/BooleanOptionTest.java +++ b/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/BooleanOptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -94,8 +94,6 @@ public void testCombinationOptions() { assertFalse(o.defaultTrue); assertTrue(o.defaultFalse); - cm.close(); - args = new String[]{"-adb","true"}; o = new TestOptions(); diff --git a/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/OptionsTest.java b/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/OptionsTest.java index 35d4f796..7fcde1ec 100644 --- a/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/OptionsTest.java +++ b/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/config/OptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -61,13 +61,12 @@ public void testBasic() { assertEquals("input.txt", options.foo.inputFile.getName()); assertEquals("output.txt", options.foo.outputFile.getFileName().toString()); assertEquals(Arrays.asList("X", "Y", "Z"), options.foo.baz); - assertEquals(-1_170_105_035, options.bar.rng.nextInt()); + assertEquals(-1_170_105_035, new Random(options.bar.seed).nextInt()); assertEquals(OptionsEnum.THINGS, options.bar.optEnum); assertEquals("ringstay putoutay", options.bar.outputString); assertEquals("double bass", options.bar.deepOptions.deepString); assertEquals("How low can you go?", options.bar.deepOptions.deeperOptions.deeperString); - cm.close(); - + String[] unparsedArgs = cm.getUnnamedArguments(); assertEquals(0, unparsedArgs.length); @@ -80,8 +79,6 @@ public void testBackSlash() { TestOptions options = new TestOptions(); ConfigurationManager cm = new ConfigurationManager(args,options); assertEquals("\\s+", options.bar.deepOptions.deeperOptions.deeperString); - cm.close(); - } public static class CommaOptions implements Options { @@ -94,7 +91,6 @@ public void testComma() { String[] args = new String[] {"--my-chars", "a," + ConfigurationManager.CUR_ESCAPE_CHAR + ",,b,c"}; CommaOptions options = new CommaOptions(); ConfigurationManager cm = new ConfigurationManager(args, options); - cm.close(); assertEquals(4, options.myChars.length); assertEquals('a', options.myChars[0]); assertEquals(',', options.myChars[1]); @@ -224,7 +220,7 @@ public String getOptionsDescription() { public DeepOptions deepOptions; @Option(charName='r', longName="seed", usage="Random seed") - public Random rng = new Random(1); + public long seed = 1L; @Option(charName='a', longName="output-string", usage="String to output") public String outputString = ""; @@ -234,7 +230,7 @@ public String getOptionsDescription() { @Override public String toString() { - return "rngDraw="+rng.nextInt()+",outputString="+outputString+",deepOptions("+deepOptions.toString()+")"; + return "rngDraw="+new Random(seed)+",outputString="+outputString+",deepOptions("+deepOptions.toString()+")"; } } From c69a4f9a1ae0488e42e6ffd5b380525d0013615a Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 22:23:46 -0500 Subject: [PATCH 3/8] Sealing & making things into records. - Sealed Property and converted instanceof checks to switches. - Sealed MarshalledProvenance and converted instanceof checks to switches. - Sealed Provenance and PrimitiveProvenance, converted instanceof checks to switches. - Also removed StreamUtil.boundParallelism as it only applies to Java 8 or 9, neither of which are supported in this version. - Made a bunch of things final. - Other small cleanups. --- .../olcut/config/edn/EdnConfigWriter.java | 60 ++-- .../labs/mlrg/olcut/config/edn/EdnLoader.java | 24 +- .../olcut/config/json/JsonConfigWriter.java | 49 +-- .../json/JsonProvenanceDeserializer.java | 2 +- .../config/json/JsonProvenanceModule.java | 2 +- .../config/json/JsonProvenanceSerializer.java | 64 ++-- .../ProtoProvenanceSerialization.java | 34 +- .../labs/mlrg/olcut/config/PropertySheet.java | 44 +-- .../config/property/GlobalProperties.java | 4 +- .../olcut/config/property/GlobalProperty.java | 8 +- .../property/ImmutableGlobalProperties.java | 6 +- .../config/property/LazyGlobalProperty.java | 4 +- .../mlrg/olcut/config/property/Property.java | 11 +- .../ConfiguredObjectProvenance.java | 4 +- .../mlrg/olcut/provenance/ListProvenance.java | 2 +- .../mlrg/olcut/provenance/MapProvenance.java | 2 +- .../olcut/provenance/ObjectProvenance.java | 13 +- .../olcut/provenance/PrimitiveProvenance.java | 29 +- .../mlrg/olcut/provenance/Provenance.java | 12 +- .../olcut/provenance/ProvenanceException.java | 11 +- .../mlrg/olcut/provenance/ProvenanceUtil.java | 313 +++++++++--------- .../impl/ConfiguredObjectProvenanceImpl.java | 6 +- .../impl/NullConfiguredProvenance.java | 4 +- .../SkeletalConfiguredObjectProvenance.java | 22 +- .../olcut/provenance/impl/package-info.java | 4 +- .../io/FlatMarshalledProvenance.java | 6 +- .../io/ListMarshalledProvenance.java | 35 +- .../io/MapMarshalledProvenance.java | 40 +-- .../provenance/io/MarshalledProvenance.java | 7 +- .../io/ObjectMarshalledProvenance.java | 8 +- .../io/SimpleMarshalledProvenance.java | 4 +- .../io/XMLProvenanceSerialization.java | 24 +- .../oracle/labs/mlrg/olcut/util/IOUtil.java | 6 +- .../oracle/labs/mlrg/olcut/util/LRACache.java | 1 - .../com/oracle/labs/mlrg/olcut/util/Pair.java | 13 +- .../oracle/labs/mlrg/olcut/util/SortUtil.java | 44 +-- .../labs/mlrg/olcut/util/StreamUtil.java | 100 +----- .../labs/mlrg/olcut/util/StringUtil.java | 30 +- .../oracle/labs/mlrg/olcut/util/TimeSpec.java | 24 +- .../labs/mlrg/olcut/util/StreamUtilTest.java | 147 -------- 40 files changed, 436 insertions(+), 787 deletions(-) delete mode 100644 olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/util/StreamUtilTest.java diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java index dfd3e324..fc181545 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java @@ -113,39 +113,39 @@ public void writeStartComponents() throws ConfigWriterException { private Object writeProperty(Property p) throws ConfigWriterException { Object res; - if(p instanceof MapProperty) { - // map configurable field - Map mRes = new HashMap<>(); - for(Map.Entry e: ((MapProperty) p).getMap().entrySet()) { - if(e.getKey()==null) { - throw new ConfigWriterException(new IllegalArgumentException("Can't write a map with null keys" + p.toString())); + switch (p) { + case MapProperty mapProperty -> { + // map configurable field + Map mRes = new HashMap<>(); + for (Map.Entry e : mapProperty.getMap().entrySet()) { + if (e.getKey() == null) { + throw new ConfigWriterException(new IllegalArgumentException("Can't write a map with null keys" + p.toString())); + } + if (e.getValue() == null) { + throw new ConfigWriterException(new IllegalArgumentException("Can't write a map with null values: " + p.toString())); + } + mRes.put(Keyword.newKeyword(e.getKey()), e.getValue().getValue()); } - if(e.getValue()==null) { - throw new ConfigWriterException(new IllegalArgumentException("Can't write a map with null values: " + p.toString())); - } - mRes.put(Keyword.newKeyword(e.getKey()), e.getValue().getValue()); + res = mRes; } - res = mRes; - } else if(p instanceof ListProperty) { - // list configurable field - List lRes = new ArrayList<>(); - for (SimpleProperty s : ((ListProperty)p).getSimpleList()) { - if(s==null) { - throw new ConfigWriterException(new IllegalArgumentException("Can't write a list with null values: " + p.toString())); + case ListProperty listProperty -> { + // list configurable field + List lRes = new ArrayList<>(); + for (SimpleProperty s : listProperty.getSimpleList()) { + if (s == null) { + throw new ConfigWriterException(new IllegalArgumentException("Can't write a list with null values: " + p.toString())); + } + lRes.add(s.getValue()); } - lRes.add(s.getValue()); - } - for (Class c : ((ListProperty) p).getClassList()) { - if(c==null) { - throw new ConfigWriterException(new IllegalArgumentException("Can't write a list with null values: " + p.toString())); + for (Class c : listProperty.getClassList()) { + if (c == null) { + throw new ConfigWriterException(new IllegalArgumentException("Can't write a list with null values: " + p.toString())); + } + lRes.add(cnMapper.write(c.getCanonicalName())); } - lRes.add(cnMapper.write(c.getCanonicalName())); + res = lRes; } - res = lRes; - } else if(p instanceof SimpleProperty) { - res = ((SimpleProperty) p).getValue(); - } else { - throw new ConfigWriterException(new IllegalArgumentException("Unexpected type for property value " + p.getClass().toString() + " with value " + p)); + case SimpleProperty simpleProperty -> res = simpleProperty.getValue(); } return res; } @@ -173,9 +173,7 @@ public void writeComponent(Map attributes, Map } @Override - public void writeEndComponents() throws ConfigWriterException { - - } + public void writeEndComponents() throws ConfigWriterException { } @Override public void close() throws ConfigWriterException { diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java index 7199d8b5..fedb3dc2 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java @@ -209,24 +209,12 @@ private void parseEdn(Parseable in) { for(Object configObj : rest(config)) { if(configObj instanceof List configListItem) { switch (checkSymbol(configListItem.getFirst())) { - case FILE: - parseFile(rest(configListItem)); - break; - case SERIALIZED: - parseSerializedObject(rest(configListItem)); - break; - case PROPERTIES: - parseGlobalProperties(rest(configListItem)); - break; - case PROPERTY: - parseGlobalProperty(rest(configListItem)); - break; - case COMPONENTS: - parseComponents(rest(configListItem)); - break; - case COMPONENT: - parseComponent(rest(configListItem)); - break; + case FILE -> parseFile(rest(configListItem)); + case SERIALIZED -> parseSerializedObject(rest(configListItem)); + case PROPERTIES -> parseGlobalProperties(rest(configListItem)); + case PROPERTY -> parseGlobalProperty(rest(configListItem)); + case COMPONENTS -> parseComponents(rest(configListItem)); + case COMPONENT -> parseComponent(rest(configListItem)); } } } diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java index 55199d9d..c8ac3d68 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java @@ -135,33 +135,34 @@ public void writeComponent(Map attributes, Map for (Entry property : properties.entrySet()) { String key = property.getKey(); Property value = property.getValue(); - if (value instanceof ListProperty) { - // - // Must be a string or component list - writer.writeArrayFieldStart(key); - for (SimpleProperty s : ((ListProperty) value).getSimpleList()) { - writer.writeStartObject(); - writer.writeStringField(ConfigLoader.ITEM,s.getValue()); - writer.writeEndObject(); + switch (value) { + case ListProperty list -> { + // + // Must be a string or component list + writer.writeArrayFieldStart(key); + for (SimpleProperty s : list.getSimpleList()) { + writer.writeStartObject(); + writer.writeStringField(ConfigLoader.ITEM,s.getValue()); + writer.writeEndObject(); + } + for (Class c : list.getClassList()) { + writer.writeStartObject(); + writer.writeStringField(ConfigLoader.TYPE,c.getName()); + writer.writeEndObject(); + } + writer.writeEndArray(); + } - for (Class c : ((ListProperty) value).getClassList()) { - writer.writeStartObject(); - writer.writeStringField(ConfigLoader.TYPE,c.getName()); + case MapProperty map -> { + // + // Must be a string,string map + writer.writeObjectFieldStart(key); + for (Map.Entry e : map.getMap().entrySet()) { + writer.writeStringField(e.getKey(),e.getValue().getValue()); + } writer.writeEndObject(); } - writer.writeEndArray(); - } else if (value instanceof MapProperty) { - // - // Must be a string,string map - writer.writeObjectFieldStart(key); - for (Map.Entry e : ((MapProperty) value).getMap().entrySet()) { - writer.writeStringField(e.getKey(),e.getValue().getValue()); - } - writer.writeEndObject(); - } else { - // - // Standard property - writer.writeStringField(key,value.toString()); + case SimpleProperty sp -> writer.writeStringField(key,sp.toString()); } } writer.writeEndObject(); diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceDeserializer.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceDeserializer.java index 129c3629..1828b351 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceDeserializer.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceDeserializer.java @@ -51,7 +51,7 @@ /** * Deserialization class to convert JSON into {@link MarshalledProvenance}. */ -public class JsonProvenanceDeserializer extends StdDeserializer { +public final class JsonProvenanceDeserializer extends StdDeserializer { public JsonProvenanceDeserializer(Class provClass) { super(provClass); diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceModule.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceModule.java index 67888b47..8159a8bc 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceModule.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceModule.java @@ -35,7 +35,7 @@ /** * The {@link MarshalledProvenance} serialization module. */ -public class JsonProvenanceModule extends SimpleModule { +public final class JsonProvenanceModule extends SimpleModule { static final String MARSHALLED_CLASS = "marshalled-class"; static final String LIST = "list"; static final String MAP = "map"; diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java index 6bf5309c..db78fe1f 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -45,7 +45,7 @@ /** * Serialization class to convert {@link MarshalledProvenance} into JSON. */ -public class JsonProvenanceSerializer extends StdSerializer { +public final class JsonProvenanceSerializer extends StdSerializer { public JsonProvenanceSerializer(Class provClass) { super(provClass); @@ -56,39 +56,39 @@ public void serialize(MarshalledProvenance marshalledProvenance, JsonGenerator j Class provClass = marshalledProvenance.getClass(); jsonGenerator.writeStartObject(); jsonGenerator.writeStringField(JsonProvenanceModule.MARSHALLED_CLASS,provClass.getName()); - if (marshalledProvenance instanceof ListMarshalledProvenance) { - ListMarshalledProvenance lmp = (ListMarshalledProvenance) marshalledProvenance; - jsonGenerator.writeArrayFieldStart(JsonProvenanceModule.LIST); - for (FlatMarshalledProvenance e : lmp) { - jsonGenerator.writeObject(e); + switch (marshalledProvenance) { + case ListMarshalledProvenance lmp -> { + jsonGenerator.writeArrayFieldStart(JsonProvenanceModule.LIST); + for (FlatMarshalledProvenance e : lmp) { + jsonGenerator.writeObject(e); + } + jsonGenerator.writeEndArray(); } - jsonGenerator.writeEndArray(); - } else if (marshalledProvenance instanceof MapMarshalledProvenance) { - MapMarshalledProvenance mmp = (MapMarshalledProvenance) marshalledProvenance; - jsonGenerator.writeObjectFieldStart(JsonProvenanceModule.MAP); - for (Pair e : mmp) { - jsonGenerator.writeObjectField(e.getA(),e.getB()); + case MapMarshalledProvenance mmp -> { + jsonGenerator.writeObjectFieldStart(JsonProvenanceModule.MAP); + for (Pair e : mmp) { + jsonGenerator.writeObjectField(e.getA(), e.getB()); + } + jsonGenerator.writeEndObject(); } - jsonGenerator.writeEndObject(); - } else if (marshalledProvenance instanceof ObjectMarshalledProvenance) { - ObjectMarshalledProvenance omp = (ObjectMarshalledProvenance) marshalledProvenance; - jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_NAME,omp.getName()); - jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_CLASS_NAME,omp.getObjectClassName()); - jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS,omp.getProvenanceClassName()); - jsonGenerator.writeObjectFieldStart(JsonProvenanceModule.MAP); - for (Map.Entry e : omp.getMap().entrySet()) { - jsonGenerator.writeObjectField(e.getKey(),e.getValue()); + case ObjectMarshalledProvenance omp -> { + jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_NAME, omp.getName()); + jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_CLASS_NAME, omp.getObjectClassName()); + jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS, omp.getProvenanceClassName()); + jsonGenerator.writeObjectFieldStart(JsonProvenanceModule.MAP); + for (Map.Entry e : omp.getMap().entrySet()) { + jsonGenerator.writeObjectField(e.getKey(), e.getValue()); + } + jsonGenerator.writeEndObject(); } - jsonGenerator.writeEndObject(); - } else if (marshalledProvenance instanceof SimpleMarshalledProvenance) { - SimpleMarshalledProvenance smp = (SimpleMarshalledProvenance) marshalledProvenance; - jsonGenerator.writeStringField(JsonProvenanceModule.KEY,smp.getKey()); - jsonGenerator.writeStringField(JsonProvenanceModule.VALUE,smp.getValue()); - jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS,smp.getProvenanceClassName()); - jsonGenerator.writeStringField(JsonProvenanceModule.ADDITIONAL,smp.getAdditional()); - jsonGenerator.writeBooleanField(JsonProvenanceModule.IS_REFERENCE,smp.isReference()); - } else { - throw new IOException("Unexpected provenance class, found " + provClass.getName()); + case SimpleMarshalledProvenance smp -> { + jsonGenerator.writeStringField(JsonProvenanceModule.KEY, smp.getKey()); + jsonGenerator.writeStringField(JsonProvenanceModule.VALUE, smp.getValue()); + jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS, smp.getProvenanceClassName()); + jsonGenerator.writeStringField(JsonProvenanceModule.ADDITIONAL, smp.getAdditional()); + jsonGenerator.writeBooleanField(JsonProvenanceModule.IS_REFERENCE, smp.isReference()); + } + default -> throw new IOException("Unexpected provenance class, found " + provClass.getName()); } jsonGenerator.writeEndObject(); } diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java index e410a2d1..96ba884c 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -189,15 +189,12 @@ public List deserializeFromProto(RootProvenanceProto */ private static FlatMarshalledProvenance dispatchMessage(Message[] messages, int index) { Message curMessage = messages[index]; - if (curMessage instanceof SimpleProvenanceProto) { - return decodeSMP((SimpleProvenanceProto) curMessage); - } else if (curMessage instanceof ListProvenanceProto) { - return decodeLMP(messages, (ListProvenanceProto) curMessage); - } else if (curMessage instanceof MapProvenanceProto) { - return decodeMMP(messages, (MapProvenanceProto) curMessage); - } else { - throw new IllegalStateException("Invalid protobuf, a message index points to an ObjectMarshalledProvenance"); - } + return switch (curMessage) { + case SimpleProvenanceProto simpleProvenanceProto -> decodeSMP(simpleProvenanceProto); + case ListProvenanceProto listProvenanceProto -> decodeLMP(messages, listProvenanceProto); + case MapProvenanceProto mapProvenanceProto -> decodeMMP(messages, mapProvenanceProto); + default -> throw new IllegalStateException("Invalid protobuf, a message index points to an ObjectMarshalledProvenance"); + }; } /** @@ -289,18 +286,11 @@ private static void convertProvenance(RootProvenanceProto.Builder builder, Mutab * @param fmp The FMP to dispatch on. */ private static int dispatchFMP(RootProvenanceProto.Builder builder, MutableLong counter, FlatMarshalledProvenance fmp) { - if (fmp instanceof SimpleMarshalledProvenance) { - SimpleMarshalledProvenance smp = (SimpleMarshalledProvenance) fmp; - return encodeSMP(builder,counter,smp); - } else if (fmp instanceof ListMarshalledProvenance) { - ListMarshalledProvenance lmp = (ListMarshalledProvenance) fmp; - return encodeLMP(builder,counter,lmp); - } else if (fmp instanceof MapMarshalledProvenance) { - MapMarshalledProvenance mmp = (MapMarshalledProvenance) fmp; - return encodeMMP(builder,counter,mmp); - } else { - throw new RuntimeException("Should not reach here, unexpected FlatMarshalledProvenance subclass " + fmp.getClass()); - } + return switch (fmp) { + case SimpleMarshalledProvenance smp -> encodeSMP(builder, counter, smp); + case ListMarshalledProvenance lmp -> encodeLMP(builder, counter, lmp); + case MapMarshalledProvenance mmp -> encodeMMP(builder, counter, mmp); + }; } /** diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java index d02c0d56..b6add7e1 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java @@ -77,7 +77,7 @@ * A property sheet which defines a collection of properties for a single * component in the system. */ -public class PropertySheet { +public final class PropertySheet { private static final Logger logger = Logger.getLogger(PropertySheet.class.getName()); /** @@ -128,13 +128,13 @@ public enum StoredFieldType { protected final ConfigurationData data; @SuppressWarnings("unchecked") - protected PropertySheet(T configurable, + PropertySheet(T configurable, ConfigurationManager cm, ConfigurationData rpd) { this((Class)configurable.getClass(), cm, rpd); owner = configurable; } - protected PropertySheet(Class confClass, + PropertySheet(Class confClass, ConfigurationManager cm, ConfigurationData rpd) { this.ownerClass = confClass; this.cm = cm; @@ -160,7 +160,7 @@ protected PropertySheet(Class confClass, * Copy constructor. Does not copy the instantiated object, and disconnects it from that object. * @param other The property sheet to copy. */ - protected PropertySheet(PropertySheet other) { + PropertySheet(PropertySheet other) { this(other, other.cm); } @@ -169,7 +169,7 @@ protected PropertySheet(PropertySheet other) { * @param other The property sheet to copy. * @param newCM The new configuration manager. */ - protected PropertySheet(PropertySheet other, ConfigurationManager newCM) { + PropertySheet(PropertySheet other, ConfigurationManager newCM) { this.ownerClass = other.ownerClass; this.cm = newCM; this.instanceName = other.instanceName; @@ -327,21 +327,7 @@ public synchronized T getOwner(ComponentListener cl, boolean reuseComponent) logger.info(String.format("Creating %s type %s", instanceName, ownerClass.getName())); } - T newObj; - try { - Constructor constructor = ownerClass.getDeclaredConstructor(); - constructor.setAccessible(true); - newObj = constructor.newInstance(); - constructor.setAccessible(false); - } catch (NoSuchMethodException ex) { - throw new PropertyException(ex, instanceName, null, - "No-args constructor not found for class " + ownerClass); - } catch (InvocationTargetException ex) { - throw new InternalConfigurationException(ex, instanceName, null, - "Can't instantiate class " + ownerClass); - } - setConfiguredFields(newObj, this); - owner = newObj; + owner = instantiateOwner(); try { owner.postConfig(); } catch (IOException e) { @@ -380,6 +366,24 @@ public synchronized T getOwner(ComponentListener cl, boolean reuseComponent) return owner; } + private T instantiateOwner() throws InstantiationException, IllegalAccessException { + T newObj; + try { + Constructor constructor = ownerClass.getDeclaredConstructor(); + constructor.setAccessible(true); + newObj = constructor.newInstance(); + constructor.setAccessible(false); + } catch (NoSuchMethodException ex) { + throw new PropertyException(ex, instanceName, null, + "No-args constructor not found for class " + ownerClass); + } catch (InvocationTargetException ex) { + throw new InternalConfigurationException(ex, instanceName, null, + "Can't instantiate class " + ownerClass); + } + setConfiguredFields(newObj, this); + return newObj; + } + /** * Sets the variables in the class that are annotated using the @Config * annotation (if there are any), using the values given in the property diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java index 550aedd2..cdfbc940 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperties.java @@ -40,7 +40,7 @@ * * @see ConfigurationManager */ -public class GlobalProperties extends ImmutableGlobalProperties { +public final class GlobalProperties extends ImmutableGlobalProperties { /** * Creates a GlobalProperties which only contains the built in properties. @@ -60,7 +60,7 @@ public GlobalProperties(GlobalProperties globalProperties) { /** * Imports the system properties into this GlobalProperties. */ - public final void importSystemProperties() { + public void importSystemProperties() { Properties props = System.getProperties(); importProperties(props); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperty.java index 07cbce14..0e21784f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/GlobalProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -28,6 +28,7 @@ package com.oracle.labs.mlrg.olcut.config.property; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -83,13 +84,12 @@ public String toString() { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof GlobalProperty)) return false; + if (!(o instanceof GlobalProperty that)) return false; - GlobalProperty that = (GlobalProperty) o; String tmpValue = getValue(); String otherValue = that.getValue(); - return tmpValue != null ? tmpValue.equals(otherValue) : otherValue == null; + return Objects.equals(tmpValue, otherValue); } /** diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ImmutableGlobalProperties.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ImmutableGlobalProperties.java index 9fb766f4..98023dc5 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ImmutableGlobalProperties.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ImmutableGlobalProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -46,7 +46,7 @@ * preset properties. This set currently includes {@link #HOSTNAME} * which lazily resolves to the system hostname. */ -public class ImmutableGlobalProperties implements Iterable> { +public sealed class ImmutableGlobalProperties implements Iterable> permits GlobalProperties { public static final String HOSTNAME = "gp.hostName"; @@ -128,7 +128,7 @@ public String replaceGlobalProperties(String instanceName, String propName, String val) { Matcher m = GlobalProperty.globalSymbolPattern.matcher(val); boolean matched = false; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); while (m.find()) { matched = true; // diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/LazyGlobalProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/LazyGlobalProperty.java index 80ba8c66..c260b592 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/LazyGlobalProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/LazyGlobalProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -30,7 +30,7 @@ import java.util.function.Supplier; -public class LazyGlobalProperty extends GlobalProperty { +public final class LazyGlobalProperty extends GlobalProperty { private final Supplier supplier; diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java index ea0c028a..0a128b1e 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -32,13 +32,10 @@ /** * Tag interface for the types extracted from a configuration file. - * + *

* Property implementations should be immutable and final. - * - * One day this interface will be sealed, at the moment it is implemented - * by {@link SimpleProperty}, {@link ListProperty}, and {@link MapProperty}. - * Other subclasses will not be recognised by the configuration processing machinery. + *

*/ -public interface Property extends Serializable { +public sealed interface Property extends Serializable permits ListProperty, MapProperty, SimpleProperty { public Property copy(); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ConfiguredObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ConfiguredObjectProvenance.java index 293880c4..788c3a34 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ConfiguredObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ConfiguredObjectProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -39,7 +39,7 @@ /** * Provenance for a specific object known to the config system. - * + *

* By convention all provenances which do not refer to an object field * use hyphens as separators. Provenances which refer to an object field * use standard Java camel case. diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java index 3e79cd39..4bacad8a 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java @@ -49,7 +49,7 @@ public final class ListProvenance implements Provenance, I * @param list The input list. */ public ListProvenance(List list) { - this.list = Collections.unmodifiableList(new ArrayList<>(list)); + this.list = List.copyOf(list); } /** diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java index 79de5e65..48003302 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java @@ -52,7 +52,7 @@ public final class MapProvenance implements Provenance, It * @param map The map of provenances. */ public MapProvenance(Map map) { - this.map = Collections.unmodifiableMap(new HashMap<>(map)); + this.map = Map.copyOf(map); } /** diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java index 269463f7..feaf931a 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019-2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -36,18 +36,18 @@ /** * A provenance object which records object fields. - * + *

* Must record the class name of the host object so it can be recovered. - * + *

* All classes which implement this interface must expose a public constructor * which accepts a Map<String,Provenance> which is used in deserialisation, * and have consistent implementations of equals and hashCode. - * + *

* By convention all provenances which do not refer to an object field * use hyphens as separators for their name. Provenances which refer to an object field * use standard Java camel case. */ -public interface ObjectProvenance extends Provenance, Iterable> { +public non-sealed interface ObjectProvenance extends Provenance, Iterable> { public static final String CLASS_NAME = "class-name"; public static final HashType DEFAULT_HASH_TYPE = HashType.SHA256; @@ -60,7 +60,7 @@ public interface ObjectProvenance extends Provenance, Iterable * Commonly used to implement toString. * @param name The name to give the provenance. * @return A string representation. @@ -94,7 +94,6 @@ default public String generateString(String name) { * @return The specified provenance object. * @throws ProvenanceException if the key is not found, or the value is not the requested type. */ - @SuppressWarnings("unchecked") // Guarded by isInstance check public static T checkAndExtractProvenance(Map map, String key, Class type, String provClassName) throws ProvenanceException { Optional prov = maybeExtractProvenance(map,key,type,provClassName); if (prov.isPresent()) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java index d13b7bf0..24fe44cf 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -28,15 +28,36 @@ package com.oracle.labs.mlrg.olcut.provenance; +import com.oracle.labs.mlrg.olcut.provenance.io.SimpleMarshalledProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.BooleanProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.ByteProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.CharProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.DateProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.DateTimeProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.DoubleProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.EnumProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.FileProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.FloatProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.HashProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.IntProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.LongProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.ShortProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.StringProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.TimeProvenance; +import com.oracle.labs.mlrg.olcut.provenance.primitives.URLProvenance; + /** * A supertype for {@link Provenance}s which are well understood * by the provenance system, and are expressible as a single {@link String}. * These classes form a sealed set and live in {@link com.oracle.labs.mlrg.olcut.provenance.primitives}. - * - * When adding a new PrimitiveProvenance the ProvenanceUtil and SimpleMarshalledProvenance + *

+ * When adding a new PrimitiveProvenance the {@link ProvenanceUtil} and {@link SimpleMarshalledProvenance} * classes must also be updated to be taught about the new type. */ -public interface PrimitiveProvenance extends Provenance { +public sealed interface PrimitiveProvenance extends Provenance permits BooleanProvenance, ByteProvenance, + CharProvenance, DateProvenance, DateTimeProvenance, DoubleProvenance, EnumProvenance, FileProvenance, + FloatProvenance, HashProvenance, IntProvenance, LongProvenance, ShortProvenance, StringProvenance, + TimeProvenance, URLProvenance { /** * Gets the key associated with this provenance, diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/Provenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/Provenance.java index 8af78413..a0be5e1d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/Provenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/Provenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -33,17 +33,11 @@ /** * A supertype for Provenance objects. *

- * One day it will be sealed, currently it is only - * extended by {@link ListProvenance}, {@link MapProvenance}, - * {@link ObjectProvenance} and {@link PrimitiveProvenance}. - *

- * Directly subclassing this will cause the serialisation mechanisms - * for this package to throw ProvenanceException. - *

* Provenance implementations must override {@link Object#equals}, * {@link Object#hashCode} and {@link Object#toString} to ensure * correct operation. *

* Provenance implementations should be immutable. */ -public interface Provenance extends Serializable { } +public sealed interface Provenance extends Serializable permits ListProvenance, MapProvenance, + ObjectProvenance, PrimitiveProvenance { } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceException.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceException.java index b1f26b78..90da373d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceException.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -34,10 +34,19 @@ */ public class ProvenanceException extends RuntimeException { + /** + * Constructs a provenance exception with the supplied message. + * @param message The exception message. + */ public ProvenanceException(String message) { super(message); } + /** + * Constructs a provenance exception wrapping the supplied exception. + * @param message The exception message. + * @param cause The wrapped exception. + */ public ProvenanceException(String message, Throwable cause) { super(message,cause); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java index 0a676f1d..c18c4354 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java @@ -264,7 +264,7 @@ public static > Map unwrap(MapProv * If the url is a file or jar file url, extract the file modified time and return it. * If the file modified time of a jar entry is not available then it tries to * get the creation time. - * + *

* Otherwise return {@link Optional#empty}. * @param url The url to check * @return The {@link Optional#of} {@link OffsetDateTime} or {@link Optional#empty}. @@ -281,8 +281,7 @@ public static Optional getModifiedTime(URL url) { } } else if (protocol.equals("jar")) { URLConnection con = url.openConnection(); - if (con instanceof JarURLConnection) { - JarURLConnection jarCon = (JarURLConnection) con; + if (con instanceof JarURLConnection jarCon) { JarEntry entry = jarCon.getJarEntry(); if (entry != null) { FileTime modifiedTime = entry.getLastModifiedTime(); @@ -363,45 +362,44 @@ private static String formattedProvenanceString(ObjectProvenance prov, int depth * @param depth The current object depth. */ private static void formatProvenance(Provenance innerProv, StringBuilder builder, String tabs, int depth) { - if (innerProv instanceof PrimitiveProvenance) { - builder.append(((PrimitiveProvenance)innerProv).getValue()); - } else if (innerProv instanceof ListProvenance) { - ListProvenance listProv = (ListProvenance) innerProv; - if (listProv.getList().isEmpty()) { - builder.append("List[]"); - } else { - builder.append("List[\n"); - for (Provenance provElem : listProv) { + switch (innerProv) { + case PrimitiveProvenance primitiveProvenance -> builder.append(primitiveProvenance.getValue()); + case ListProvenance listProv -> { + if (listProv.getList().isEmpty()) { + builder.append("List[]"); + } else { + builder.append("List[\n"); + for (Provenance provElem : listProv) { + builder.append(tabs); + builder.append("\t\t"); + formatProvenance(provElem, builder, tabs, depth + 1); + builder.append('\n'); + } builder.append(tabs); - builder.append("\t\t"); - formatProvenance(provElem,builder,tabs,depth+1); - builder.append('\n'); + builder.append("\t]"); } - builder.append(tabs); - builder.append("\t]"); } - } else if (innerProv instanceof MapProvenance) { - MapProvenance mapProv = (MapProvenance) innerProv; - if (mapProv.getMap().isEmpty()) { - builder.append("Map{}"); - } else { - builder.append("Map{\n"); - for (Pair provElem : mapProv) { + case MapProvenance mapProv -> { + if (mapProv.getMap().isEmpty()) { + builder.append("Map{}"); + } else { + builder.append("Map{\n"); + for (Pair provElem : mapProv) { + builder.append(tabs); + builder.append("\t\t"); + builder.append(provElem.getA()); + builder.append('='); + formatProvenance(provElem.getB(), builder, tabs, depth + 1); + builder.append('\n'); + } builder.append(tabs); - builder.append("\t\t"); - builder.append(provElem.getA()); - builder.append('='); - formatProvenance(provElem.getB(),builder,tabs,depth+1); - builder.append('\n'); + builder.append("\t}"); } - builder.append(tabs); - builder.append("\t}"); } - } else if (innerProv instanceof ObjectProvenance) { - String innerProvString = formattedProvenanceString((ObjectProvenance)innerProv,depth+1); - builder.append(innerProvString); - } else { - throw new IllegalStateException("Unrecognised provenance base type " + innerProv.getClass()); + case ObjectProvenance pairs -> { + String innerProvString = formattedProvenanceString(pairs, depth + 1); + builder.append(innerProvString); + } } } @@ -434,36 +432,37 @@ public static Map convertToMap(ObjectProvenance prov) { * @return A structure suitable for display or conversion into JSON. */ private static Object innerConvertToMap(Provenance prov) { - if (prov instanceof PrimitiveProvenance) { - return String.valueOf(((PrimitiveProvenance)prov).getValue()); - } else if (prov instanceof ListProvenance) { - ListProvenance listProv = (ListProvenance) prov; - if (listProv.getList().isEmpty()) { - return Collections.emptyList(); - } else { - List list = new ArrayList<>(); - for (Provenance provElem : listProv) { - list.add(innerConvertToMap(provElem)); + switch (prov) { + case PrimitiveProvenance primitiveProvenance -> { + return String.valueOf(primitiveProvenance.getValue()); + } + case ListProvenance listProv -> { + if (listProv.getList().isEmpty()) { + return Collections.emptyList(); + } else { + List list = new ArrayList<>(); + for (Provenance provElem : listProv) { + list.add(innerConvertToMap(provElem)); + } + return Collections.unmodifiableList(list); } - return Collections.unmodifiableList(list); } - } else if (prov instanceof MapProvenance) { - MapProvenance mapProv = (MapProvenance) prov; - if (mapProv.getMap().isEmpty()) { - return Collections.emptyMap(); - } else { - Map map = new HashMap<>(); - for (Pair provElem : mapProv) { - String newKey = provElem.getA(); - Object newValue = innerConvertToMap(provElem.getB()); - map.put(newKey,newValue); + case MapProvenance mapProv -> { + if (mapProv.getMap().isEmpty()) { + return Collections.emptyMap(); + } else { + Map map = new HashMap<>(); + for (Pair provElem : mapProv) { + String newKey = provElem.getA(); + Object newValue = innerConvertToMap(provElem.getB()); + map.put(newKey, newValue); + } + return Collections.unmodifiableMap(map); } - return Collections.unmodifiableMap(map); } - } else if (prov instanceof ObjectProvenance) { - return convertToMap((ObjectProvenance)prov); - } else { - throw new IllegalStateException("Unrecognised provenance base type " + prov.getClass()); + case ObjectProvenance pairs -> { + return convertToMap(pairs); + } } } @@ -514,10 +513,10 @@ public static ProvenanceOrdering orderProvenances(ObjectProvenance provenance) { ObjectProvenance curProv = processingQueue.poll(); // skip null provenances if (!(curProv instanceof NullConfiguredProvenance)) { - if (curProv instanceof ConfiguredObjectProvenance) { - if (!provenanceTracker.containsKey((ConfiguredObjectProvenance) curProv)) { - provenanceTracker.put((ConfiguredObjectProvenance) curProv, counter); - traversalOrder.add((ConfiguredObjectProvenance) curProv); + if (curProv instanceof ConfiguredObjectProvenance confProv) { + if (!provenanceTracker.containsKey(confProv)) { + provenanceTracker.put(confProv, counter); + traversalOrder.add(confProv); counter++; } } @@ -565,44 +564,47 @@ private static ConfigurationData extractSingleConfiguration(ConfiguredObjectProv for (Map.Entry e : obj.getConfiguredParameters().entrySet()) { Provenance prov = e.getValue(); - if (prov instanceof ListProvenance) { - List list = new ArrayList<>(); - - for (Provenance p : (ListProvenance)prov) { - if (p instanceof ConfiguredObjectProvenance) { - // skip nulls - if (!(p instanceof NullConfiguredProvenance)) { - list.add(new SimpleProperty(computeName((ConfiguredObjectProvenance) p, map.get(p)))); - } - } else { - list.add(new SimpleProperty(p.toString())); + switch (prov) { + case ListProvenance listProvenance -> { + List list = new ArrayList<>(); + + for (Provenance p : listProvenance) { + if (p instanceof ConfiguredObjectProvenance confProv) { + // skip nulls + if (!(p instanceof NullConfiguredProvenance)) { + list.add(new SimpleProperty(computeName(confProv, map.get(confProv)))); + } + } else { + list.add(new SimpleProperty(p.toString())); + } } - } - data.add(e.getKey(),new ListProperty(list)); - } else if (prov instanceof MapProvenance) { - Map propMap = new HashMap<>(); - - for (Pair pair : (MapProvenance) prov) { - Provenance valueProv = pair.getB(); - if (valueProv instanceof ConfiguredObjectProvenance) { - // skip nulls - if (!(valueProv instanceof NullConfiguredProvenance)) { - propMap.put(pair.getA(), new SimpleProperty(computeName((ConfiguredObjectProvenance) valueProv, map.get(valueProv)))); + data.add(e.getKey(), new ListProperty(list)); + } + case MapProvenance mapProvenance -> { + Map propMap = new HashMap<>(); + + for (Pair pair : mapProvenance) { + Provenance valueProv = pair.getB(); + if (valueProv instanceof ConfiguredObjectProvenance confProv) { + // skip nulls + if (!(confProv instanceof NullConfiguredProvenance)) { + propMap.put(pair.getA(), new SimpleProperty(computeName(confProv, map.get(confProv)))); + } + } else { + propMap.put(pair.getA(), new SimpleProperty(valueProv.toString())); } - } else { - propMap.put(pair.getA(), new SimpleProperty(valueProv.toString())); } - } - data.add(e.getKey(), new MapProperty(propMap)); - } else if (prov instanceof ConfiguredObjectProvenance) { - // Skip nulls; - if (!(prov instanceof NullConfiguredProvenance)) { - data.add(e.getKey(), new SimpleProperty(computeName((ConfiguredObjectProvenance) prov, map.get(prov)))); + data.add(e.getKey(), new MapProperty(propMap)); } - } else { - data.add(e.getKey(),new SimpleProperty(prov.toString())); + case ConfiguredObjectProvenance confProv -> { + // Skip nulls; + if (!(confProv instanceof NullConfiguredProvenance)) { + data.add(e.getKey(), new SimpleProperty(computeName(confProv, map.get(confProv)))); + } + } + default -> data.add(e.getKey(), new SimpleProperty(prov.toString())); } } @@ -687,33 +689,39 @@ private static ObjectMarshalledProvenance marshalSingleProvenance(ObjectProvenan * @return A single flattened marshalled provenance. */ private static FlatMarshalledProvenance flattenSingleProvenance(Provenance prov, String key, Map map) { - if (prov instanceof ListProvenance) { - List list = new ArrayList<>(); + switch (prov) { + case ListProvenance listProvenance -> { + List list = new ArrayList<>(); + + for (Provenance p : listProvenance) { + list.add(flattenSingleProvenance(p, key, map)); + } - for (Provenance p : (ListProvenance)prov) { - list.add(flattenSingleProvenance(p,key,map)); + return new ListMarshalledProvenance(list); } + case MapProvenance mapProvenance -> { + Map propMap = new HashMap<>(); - return new ListMarshalledProvenance(list); - } else if (prov instanceof MapProvenance) { - Map propMap = new HashMap<>(); + for (Pair pair : mapProvenance) { + propMap.put(pair.getA(), flattenSingleProvenance(pair.getB(), pair.getA(), map)); + } - for (Pair pair : (MapProvenance)prov) { - propMap.put(pair.getA(),flattenSingleProvenance(pair.getB(),pair.getA(),map)); + return new MapMarshalledProvenance(propMap); + } + case ObjectProvenance objProv -> { + return new SimpleMarshalledProvenance(key, computeName(objProv, map.get(objProv)), objProv); + } + case HashProvenance hashProvenance -> { + return new SimpleMarshalledProvenance(hashProvenance); + } + case EnumProvenance enumProvenance -> { + @SuppressWarnings("unchecked") + var smp = new SimpleMarshalledProvenance(enumProvenance); + return smp; + } + case PrimitiveProvenance primitiveProvenance -> { + return new SimpleMarshalledProvenance(primitiveProvenance); } - - return new MapMarshalledProvenance(propMap); - } else if (prov instanceof ObjectProvenance) { - ObjectProvenance objProv = (ObjectProvenance) prov; - return new SimpleMarshalledProvenance(key, computeName(objProv, map.get(objProv)), objProv); - } else if (prov instanceof HashProvenance) { - return new SimpleMarshalledProvenance((HashProvenance) prov); - } else if (prov instanceof EnumProvenance) { - return new SimpleMarshalledProvenance((EnumProvenance)prov); - } else if (prov instanceof PrimitiveProvenance) { - return new SimpleMarshalledProvenance((PrimitiveProvenance)prov); - } else { - throw new ProvenanceException("Unexpected Provenance subclass - found " + prov.getClass().getName() + " expected {ListProvenance, MapProvenance, PrimitiveProvenance, ObjectProvenance}"); } } @@ -761,7 +769,7 @@ public static ObjectProvenance unmarshalProvenance(List unmarshalledObjects, Map marshalledObjects) { - if (fmp instanceof SimpleMarshalledProvenance) { - SimpleMarshalledProvenance smp = (SimpleMarshalledProvenance) fmp; - if (smp.isReference()) { - String refName = smp.getValue(); - if (unmarshalledObjects.containsKey(refName)) { - return unmarshalledObjects.get(refName); - } else if (marshalledObjects.containsKey(refName)) { - // Need to recurse into the object as it's not been unmarshalled. - // First remove it from the list (so if we reference it again it will throw ProvenanceException). - ObjectMarshalledProvenance omp = marshalledObjects.remove(refName); - // Recurse into the marshalled object provenance - ObjectProvenance unmarshalled = unmarshalProvenance(omp, unmarshalledObjects, marshalledObjects); - // Put the unmarshalled object provenance into the map and return it. - unmarshalledObjects.put(refName, unmarshalled); - return unmarshalled; + switch (fmp) { + case SimpleMarshalledProvenance smp -> { + if (smp.isReference()) { + String refName = smp.getValue(); + if (unmarshalledObjects.containsKey(refName)) { + return unmarshalledObjects.get(refName); + } else if (marshalledObjects.containsKey(refName)) { + // Need to recurse into the object as it's not been unmarshalled. + // First remove it from the list (so if we reference it again it will throw ProvenanceException). + ObjectMarshalledProvenance omp = marshalledObjects.remove(refName); + // Recurse into the marshalled object provenance + ObjectProvenance unmarshalled = unmarshalProvenance(omp, unmarshalledObjects, marshalledObjects); + // Put the unmarshalled object provenance into the map and return it. + unmarshalledObjects.put(refName, unmarshalled); + return unmarshalled; + } else { + throw new ProvenanceException("Invalid provenance object " + hostProvName + " refers to an object called " + refName + " which is not present (or forms a cycle)."); + } } else { - throw new ProvenanceException("Invalid provenance object " + hostProvName + " refers to an object called " + refName + " which is not present (or forms a cycle)."); + return smp.unmarshallPrimitive(); } - } else { - return smp.unmarshallPrimitive(); } - } else if (fmp instanceof ListMarshalledProvenance) { - ListMarshalledProvenance lmp = (ListMarshalledProvenance) fmp; - List convertedList = new ArrayList<>(); - for (FlatMarshalledProvenance smp : lmp) { - convertedList.add(unmarshalFlat(hostProvName,smp,unmarshalledObjects,marshalledObjects)); + case ListMarshalledProvenance lmp -> { + List convertedList = new ArrayList<>(); + for (FlatMarshalledProvenance smp : lmp) { + convertedList.add(unmarshalFlat(hostProvName, smp, unmarshalledObjects, marshalledObjects)); + } + return new ListProvenance<>(convertedList); } - return new ListProvenance<>(convertedList); - } else if (fmp instanceof MapMarshalledProvenance) { - MapMarshalledProvenance mmp = (MapMarshalledProvenance) fmp; - Map convertedMap = new HashMap<>(); - for (Pair tuple : mmp) { - convertedMap.put(tuple.getA(), unmarshalFlat(hostProvName,tuple.getB(),unmarshalledObjects,marshalledObjects)); + case MapMarshalledProvenance mmp -> { + Map convertedMap = new HashMap<>(); + for (Pair tuple : mmp) { + convertedMap.put(tuple.getA(), unmarshalFlat(hostProvName, tuple.getB(), unmarshalledObjects, marshalledObjects)); + } + return new MapProvenance<>(convertedMap); } - return new MapProvenance<>(convertedMap); - } else { - throw new ProvenanceException("Unexpected FlatMarshalledProvenance subclass, found " + fmp.getClass().getName()); } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/ConfiguredObjectProvenanceImpl.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/ConfiguredObjectProvenanceImpl.java index 751b12ee..b79b3db3 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/ConfiguredObjectProvenanceImpl.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/ConfiguredObjectProvenanceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -58,9 +58,9 @@ public ConfiguredObjectProvenanceImpl(T host, String ho /** * Constructs a ConfiguredObjectProvenanceImpl from a provenance map. - * + *

* This constructor cannot verify that the map contains only configured parameters, as - * that could trigger class loading of the host class. Thus it must contain at most + * that could trigger class loading of the host class, thus it must contain at most * the configured parameters, {@link ObjectProvenance#CLASS_NAME}, and * {@link SkeletalConfiguredObjectProvenance#HOST_SHORT_NAME} provenances. * @param map The configured parameters map. diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/NullConfiguredProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/NullConfiguredProvenance.java index fd0cd8f1..3857b428 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/NullConfiguredProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/NullConfiguredProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -39,7 +39,7 @@ /** * A provenance object to use for null valued fields of {@link Provenancable} objects. - * + *

* Only contains the class name. */ public final class NullConfiguredProvenance implements ConfiguredObjectProvenance { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java index 8d694ba3..5abefede 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java @@ -126,7 +126,7 @@ protected SkeletalConfiguredObjectProvenance(T host, St protected SkeletalConfiguredObjectProvenance(ExtractedInfo info) { this.className = info.className; this.hostShortName = info.hostShortName; - this.configuredParameters = Collections.unmodifiableMap(new HashMap<>(info.configuredParameters)); + this.configuredParameters = Map.copyOf(info.configuredParameters); } /** @@ -136,7 +136,7 @@ protected SkeletalConfiguredObjectProvenance(ExtractedInfo info) { * to the {@link SkeletalConfiguredObjectProvenance#SkeletalConfiguredObjectProvenance(ExtractedInfo)} * constructor to prevent that constructor from triggering class loading of the * host class. - * + *

* The class loading would be required to separate out the configured parameters from the instance * values, however subclasses of {@link SkeletalConfiguredObjectProvenance} must supply it * themselves via an extraction method. @@ -158,7 +158,7 @@ public ExtractedInfo(String className, String hostShortName, Map * Throws ProvenanceException if it's not found or it's an incorrect type. * @param info The ExtractedInfo to check. * @param key The key to look up. @@ -249,7 +249,7 @@ private static Map getConfiguredFie if (genericClasses.size() != 1) { logger.log(Level.SEVERE, "Invalid configurable field definition, field not recorded - found too many or too few generic type parameters for field " + f.getName()); } else { - map.put(f.getName(), convertCollection(f, (Collection) f.get(host), genericClasses.get(0))); + map.put(f.getName(), convertCollection(f, (Collection) f.get(host), genericClasses.getFirst())); } break; } @@ -258,7 +258,7 @@ private static Map getConfiguredFie if (genericClasses.size() != 2) { logger.log(Level.SEVERE, "Invalid configurable field definition, field not recorded - found too many or too few generic type parameters for field " + f.getName()); } else { - map.put(f.getName(), convertMap(f, (Map) f.get(host), genericClasses.get(1))); + map.put(f.getName(), convertMap(f, (Map) f.get(host), genericClasses.get(1))); } break; } @@ -291,7 +291,7 @@ private static ListProvenance convertPrimitiveArray(FieldType ft, Field f, Ob return new ListProvenance<>(); } String fieldName = f.getName(); - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); switch (ft) { case BYTE_ARRAY: { byte[] array = (byte[]) object; @@ -404,7 +404,7 @@ private static ListProvenance convertObjectArray(FieldType ft, Field f, Objec * @param genericType The generic type bound of the collection. * @return A ListProvenance. */ - private static ListProvenance convertCollection(Field f, Collection collection, Class genericType) { + private static ListProvenance convertCollection(Field f, Collection collection, Class genericType) { if (collection == null) { return new ListProvenance<>(); } else { @@ -523,13 +523,13 @@ private static Optional convertPrimitive(FieldType ft, Class fiel if (o == null) { return Optional.empty(); } else { - return Optional.of(new EnumProvenance<>(fieldName, (Enum) o)); + return Optional.of(new EnumProvenance<>(fieldName, (Enum) o)); } case CONFIGURABLE: if (o == null) { return Optional.of(ConfiguredObjectProvenance.getEmptyProvenance(fieldClass.getName())); - } else if (o instanceof Provenancable) { - return Optional.of(((Provenancable) o).getProvenance()); + } else if (o instanceof Provenancable prov) { + return Optional.of(prov.getProvenance()); } else { logger.log(Level.WARNING, "Automatic provenance generated for Configurable class, consider opting into provenance by implementing Provenancable on " + o.getClass().toString()); return Optional.of(new ConfiguredObjectProvenanceImpl((Configurable)o, fieldName)); @@ -567,7 +567,7 @@ private static Optional convertPrimitive(FieldType ft, Class fiel /** * Returns the instance parameters for this provenance. - * + *

* Subclasses must call this first, before adding additional instance * parameters to the returned map. * @return A map of provenances. diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/package-info.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/package-info.java index 7f0cffb2..5b379c23 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/package-info.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -29,7 +29,7 @@ /** * Provides concrete and skeletal implementations of * {@link com.oracle.labs.mlrg.olcut.provenance.ConfiguredObjectProvenance}. - * + *

* These implementations use reflection to extract the field names and * values automatically. */ diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/FlatMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/FlatMarshalledProvenance.java index c0837c21..726f7d3a 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/FlatMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/FlatMarshalledProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -31,7 +31,5 @@ /** * A marshalled provenance that is either a {@link ListMarshalledProvenance}, * a {@link MapMarshalledProvenance} or a {@link SimpleMarshalledProvenance}. - *

- * Will be sealed to those types one day. */ -public interface FlatMarshalledProvenance extends MarshalledProvenance { } +public sealed interface FlatMarshalledProvenance extends MarshalledProvenance permits ListMarshalledProvenance, MapMarshalledProvenance, SimpleMarshalledProvenance { } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ListMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ListMarshalledProvenance.java index 35825513..2ff99b49 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ListMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ListMarshalledProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -28,48 +28,23 @@ package com.oracle.labs.mlrg.olcut.provenance.io; -import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Objects; -import java.util.logging.Logger; /** * A marshalled provenance which contains a list of other {@link FlatMarshalledProvenance} objects. * This can recursively include other lists or maps. */ -public final class ListMarshalledProvenance implements FlatMarshalledProvenance, Iterable { - private static final Logger logger = Logger.getLogger(ListMarshalledProvenance.class.getName()); - - private final List list; +public record ListMarshalledProvenance( + List list) implements FlatMarshalledProvenance, Iterable { /** * Constructs a ListMarshalledProvenance wrapped around the supplied list. + * * @param list The list. */ public ListMarshalledProvenance(List list) { - this.list = Collections.unmodifiableList(list); - } - - /** - * Gets an unmodifiable view on the marshalled provenance list. - * @return The marshalled provenance list. - */ - public List getList() { - return list; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ListMarshalledProvenance)) return false; - ListMarshalledProvenance that = (ListMarshalledProvenance) o; - return getList().equals(that.getList()); - } - - @Override - public int hashCode() { - return Objects.hash(getList()); + this.list = List.copyOf(list); } @Override diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MapMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MapMarshalledProvenance.java index 4225486b..916d126f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MapMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MapMarshalledProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -31,37 +31,36 @@ import com.oracle.labs.mlrg.olcut.util.Pair; import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; -import java.util.Objects; /** * A marshalled provenance which contains a map of other {@link FlatMarshalledProvenance} objects. * This can recursively include other lists or maps. */ -public final class MapMarshalledProvenance implements FlatMarshalledProvenance, Iterable> { - - private final Map map; +public record MapMarshalledProvenance(Map map) implements + FlatMarshalledProvenance, Iterable> { /** * Constructs a MapMarshalledProvenance wrapped around the supplied map. + * * @param map The map. */ public MapMarshalledProvenance(Map map) { - this.map = Collections.unmodifiableMap(new HashMap<>(map)); + this.map = Map.copyOf(map); } /** * Constructs an empty MapMarshalledProvenance. */ - public MapMarshalledProvenance() { - this.map = Collections.emptyMap(); - } + public MapMarshalledProvenance() { + this(Collections.emptyMap()); + } /** * Is this MapMarshalledProvenance empty? + * * @return True if the provenance contains no other provenances. */ public boolean isEmpty() { @@ -78,24 +77,11 @@ public String toString() { return "MapMarshalledProvenance" + map.toString(); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof MapMarshalledProvenance)) return false; - MapMarshalledProvenance that = (MapMarshalledProvenance) o; - return map.equals(that.map); - } - - @Override - public int hashCode() { - return Objects.hash(map); - } - - private static class MapMarshalledProvenanceIterator implements Iterator> { + private static final class MapMarshalledProvenanceIterator implements Iterator> { private final Iterator> itr; - public MapMarshalledProvenanceIterator(Iterator> itr) { + public MapMarshalledProvenanceIterator(Iterator> itr) { this.itr = itr; } @@ -106,8 +92,8 @@ public boolean hasNext() { @Override public Pair next() { - Map.Entry item = itr.next(); - return new Pair<>(item.getKey(),item.getValue()); + Entry item = itr.next(); + return new Pair<>(item.getKey(), item.getValue()); } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MarshalledProvenance.java index 1c155263..64498d16 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/MarshalledProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -30,8 +30,5 @@ /** * An interface for marshalled provenance types. - *

- * Will be sealed to {@link FlatMarshalledProvenance} and {@link ObjectMarshalledProvenance} - * one day. */ -public interface MarshalledProvenance { } +public sealed interface MarshalledProvenance permits FlatMarshalledProvenance, ObjectMarshalledProvenance { } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java index 84f4b49a..37dfaa05 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -28,7 +28,6 @@ package com.oracle.labs.mlrg.olcut.provenance.io; -import java.util.Collections; import java.util.Map; import java.util.Objects; @@ -58,7 +57,7 @@ public final class ObjectMarshalledProvenance implements MarshalledProvenance { */ public ObjectMarshalledProvenance(String objectName, Map map, String objectClassName, String provenanceClassName) { this.objectName = objectName; - this.map = Collections.unmodifiableMap(map); + this.map = Map.copyOf(map); this.objectClassName = objectClassName; this.provenanceClassName = provenanceClassName; } @@ -108,8 +107,7 @@ public String toString() { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ObjectMarshalledProvenance)) return false; - ObjectMarshalledProvenance that = (ObjectMarshalledProvenance) o; + if (!(o instanceof ObjectMarshalledProvenance that)) return false; return map.equals(that.map) && objectName.equals(that.objectName) && objectClassName.equals(that.objectClassName) && diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java index 4ba5224a..d0c50277 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java @@ -84,7 +84,7 @@ public final class SimpleMarshalledProvenance implements FlatMarshalledProvenanc * @param enumProv The enum provenance to store. * @param The type of the enum. */ - public SimpleMarshalledProvenance(EnumProvenance enumProv) { + public > SimpleMarshalledProvenance(EnumProvenance enumProv) { this(enumProv.getKey(), enumProv.getValue().toString(), enumProv.getClass().getName(), false, enumProv.getEnumClass()); } @@ -151,7 +151,7 @@ public String toString() { * @param The type of the PrimitiveProvenance. * @return A PrimitiveProvenance instance. */ - @SuppressWarnings("unchecked")//Suppressing enum casting warnings. + @SuppressWarnings({"unchecked","rawtypes"})//Suppressing enum casting warnings. public PrimitiveProvenance unmarshallPrimitive() { if (isReference) { throw new ProvenanceException("Attempted to unmarshall a reference via 'unmarshallPrimitive'"); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java index 6259f65e..4730ad03 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -302,7 +302,7 @@ private void writeLMP(XMLStreamWriter writer, String key, ListMarshalledProvenan writer.writeCharacters("\t"); } } - if (lmp.getList().isEmpty()) { + if (lmp.list().isEmpty()) { writer.writeEmptyElement(LIST_MARSHALLED_PROVENANCE); writer.writeAttribute(PROV_KEY, key); } else { @@ -311,7 +311,7 @@ private void writeLMP(XMLStreamWriter writer, String key, ListMarshalledProvenan if (prettyPrint) { writer.writeCharacters(System.lineSeparator()); } - for (FlatMarshalledProvenance fmp : lmp.getList()) { + for (FlatMarshalledProvenance fmp : lmp.list()) { dispatchFMP(writer, "", fmp, depth + 1); } if (prettyPrint) { @@ -374,17 +374,11 @@ private void writeMMP(XMLStreamWriter writer, String key, MapMarshalledProvenanc * @throws XMLStreamException If the XML is invalid. */ private void dispatchFMP(XMLStreamWriter writer, String key, FlatMarshalledProvenance fmp, int depth) throws XMLStreamException { - if (fmp instanceof SimpleMarshalledProvenance) { - SimpleMarshalledProvenance smp = (SimpleMarshalledProvenance) fmp; - writeSMP(writer, smp, depth); - } else if (fmp instanceof ListMarshalledProvenance) { - ListMarshalledProvenance lmp = (ListMarshalledProvenance) fmp; - writeLMP(writer, key, lmp, depth); - } else if (fmp instanceof MapMarshalledProvenance) { - MapMarshalledProvenance mmp = (MapMarshalledProvenance) fmp; - writeMMP(writer, key, mmp, depth); - } else { - throw new RuntimeException("Should not reach here, unexpected FlatMarshalledProvenance subclass " + fmp.getClass()); + switch (fmp) { + case SimpleMarshalledProvenance smp -> writeSMP(writer, smp, depth); + case ListMarshalledProvenance lmp -> writeLMP(writer, key, lmp, depth); + case MapMarshalledProvenance mmp -> writeMMP(writer, key, mmp, depth); + default -> throw new RuntimeException("Should not reach here, unexpected FlatMarshalledProvenance subclass " + fmp.getClass()); } } @@ -400,7 +394,7 @@ private static class ProvenanceSAXHandler extends DefaultHandler { private Map ompAttributeMap; private Map ompProvMap; - private Deque provenanceChain; + private final Deque provenanceChain; private SimpleMarshalledProvenance curSMP; private String curKey; diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java index 05bc3a72..bad6c530 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/IOUtil.java @@ -445,11 +445,7 @@ public static PrintStream getPrintStream(File file, int bufferSize) throws FileN file.getParentFile().mkdirs(); } BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), bufferSize); - try { - return new PrintStream(bos, false, StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException("UTF-8 isn't supported. Not sure what's wrong with the world.",e); - } + return new PrintStream(bos, false, StandardCharsets.UTF_8); } public static OutputStream getOutputStream(String path) throws FileNotFoundException { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LRACache.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LRACache.java index 74552a2f..e298e5d8 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LRACache.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/LRACache.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2004-2020, Oracle and/or its affiliates. * diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java index cf4ecf04..5de556cb 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -30,6 +30,7 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Objects; import java.util.logging.Logger; /** @@ -128,17 +129,13 @@ public boolean equals(Object obj) { if(obj == null) { return false; } - if(!(obj instanceof Pair)) { + if(!(obj instanceof Pair other)) { return false; } - final Pair other = (Pair) obj; - if(this.a != other.a && (this.a == null || !this.a.equals(other.a))) { + if(!Objects.equals(this.a, other.a)) { return false; } - if(this.b != other.b && (this.b == null || !this.b.equals(other.b))) { - return false; - } - return true; + return Objects.equals(this.b, other.b); } @Override diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SortUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SortUtil.java index b15bfd58..e28b6b60 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SortUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/SortUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -142,21 +142,11 @@ public static int[] argsort(int[] input, int start, int end, boolean ascending) } /** - * A tuple of two ints and a boolean. It wants to be a record. Or a value type. + * A tuple of two ints and a boolean. It wants to be a value type. *

* Used to provide something comparable for {@link SortUtil#argsort}. */ - private static class SortIntegerTuple implements Comparable { - private final boolean ascending; - public final int value; - public final int index; - - public SortIntegerTuple(boolean ascending, int value, int index) { - this.ascending = ascending; - this.value = value; - this.index = index; - } - + private record SortIntegerTuple(boolean ascending, int value, int index) implements Comparable { @Override public int compareTo(SortIntegerTuple o) { if (ascending) { @@ -221,21 +211,11 @@ public static int[] argsort(double[] input, int start, int end, boolean ascendin } /** - * A tuple of an int, a double and a boolean. It wants to be a record. Or a value type. + * A tuple of an int, a double and a boolean. It wants to be a value type. *

* Used to provide something comparable for {@link SortUtil#argsort}. */ - private static class SortDoubleTuple implements Comparable { - private final boolean ascending; - public final double value; - public final int index; - - public SortDoubleTuple(boolean ascending, double value, int index) { - this.ascending = ascending; - this.value = value; - this.index = index; - } - + private record SortDoubleTuple(boolean ascending, double value, int index) implements Comparable { @Override public int compareTo(SortDoubleTuple o) { if (ascending) { @@ -348,20 +328,12 @@ public static > int[] argsort(T[] input, int start, int } /** - * A tuple of an int, a T and a boolean. It wants to be a record. Or a value type. + * A tuple of an int, a T and a boolean. It wants to be a value type. *

* Used to provide something comparable for {@link SortUtil#argsort}. */ - private static class SortTuple> implements Comparable> { - private final boolean ascending; - public final T value; - public final int index; - - public SortTuple(boolean ascending, T value, int index) { - this.ascending = ascending; - this.value = value; - this.index = index; - } + private record SortTuple>(boolean ascending, T value, + int index) implements Comparable> { @Override public int compareTo(SortTuple o) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StreamUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StreamUtil.java index 9a13d877..1546911e 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StreamUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StreamUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, Oracle and/or its affiliates. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -27,16 +27,11 @@ */ package com.oracle.labs.mlrg.olcut.util; -import java.util.Comparator; import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinWorkerThread; import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -55,23 +50,6 @@ private StreamUtil(){} */ static final Object NONE = new Object(); - /** - * Takes a stream and returns a stream which bounds the parallelism available - * based on the size of the {@link ForkJoinPool} it is executing in. - *

- * This is a workaround for code running on Java 8 and 9, as it's fixed in Java 10 which - * makes all {@link Stream}s have this property. - *

- * @param inputStream A Stream of T. - * @param The type of the Stream. - * @return A Stream which bounds the parallelism to the size of the FJP. - */ - public static Stream boundParallelism(Stream inputStream) { - Spliterator boundedSpliterator = new BoundedSpliterator<>(inputStream.spliterator()); - - return StreamSupport.stream(boundedSpliterator,true); - } - /** * Creates a lazy and sequential combined {@link Stream} whose elements are * the result of combining the elements of two streams. The resulting @@ -239,80 +217,4 @@ public boolean tryAdvance(Consumer action) { } } - /** - * A spliterator with bounded parallelism, it calculates the target size - * based upon the number of threads available in the ForkJoinPool it executes in. - * @param The element type of the spliterator. - */ - private static class BoundedSpliterator implements Spliterator { - private static final Logger logger = Logger.getLogger(BoundedSpliterator.class.getName()); - - private final Spliterator spliterator; - private long targetSize = -1L; - - public BoundedSpliterator(Spliterator spliterator) { - this.spliterator = spliterator; - } - - public BoundedSpliterator(Spliterator spliterator, long targetSize) { - this.spliterator = spliterator; - this.targetSize = targetSize; - } - - @Override - public boolean tryAdvance(Consumer action) { - return spliterator.tryAdvance(action); - } - - @Override - public void forEachRemaining(Consumer action) { - spliterator.forEachRemaining(action); - } - - @Override - public Spliterator trySplit() { - if (targetSize == -1L) { - Thread curThread = Thread.currentThread(); - if (curThread instanceof ForkJoinWorkerThread) { - targetSize = spliterator.estimateSize() / (((ForkJoinWorkerThread) curThread).getPool().getParallelism() << 2); - logger.log(Level.FINEST,"In FJP - setting targetSize to " + targetSize); - } else { - targetSize = spliterator.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() << 2); - logger.log(Level.FINEST,"Common pool - setting targetSize to " + targetSize); - } - } - if (targetSize < spliterator.estimateSize()) { - Spliterator tmp = spliterator.trySplit(); - if (tmp != null) { - return new BoundedSpliterator<>(tmp, targetSize); - } - } - return null; - } - - @Override - public long estimateSize() { - return spliterator.estimateSize(); - } - - @Override - public long getExactSizeIfKnown() { - return spliterator.getExactSizeIfKnown(); - } - - @Override - public int characteristics() { - return spliterator.characteristics(); - } - - @Override - public boolean hasCharacteristics(int characteristics) { - return spliterator.hasCharacteristics(characteristics); - } - - @Override - public Comparator getComparator() { - return spliterator.getComparator(); - } - } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StringUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StringUtil.java index 73cb1cce..ac43fedf 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StringUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/StringUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -30,7 +30,6 @@ import java.io.PrintWriter; import java.text.Normalizer; - /** * String utilities. */ @@ -39,26 +38,6 @@ public final class StringUtil { // Unconstructable. private StringUtil() { } - /** - * Returns a string with the given number of - * spaces. - * - * @param padding the number of spaces in the string - * @return a string of length 'padding' containing only the SPACE - * char. - */ - public static String pad(int padding) { - if (padding > 0) { - StringBuilder sb = new StringBuilder(padding); - for (int i = 0; i < padding; i++) { - sb.append(' '); - } - return sb.toString(); - } else { - return ""; - } - } - /** * Pads with spaces or truncates the given string to guarantee that it is * exactly the desired length. @@ -72,7 +51,7 @@ public static String pad(String string, int minLength) { String result = string; int pad = minLength - string.length(); if (pad > 0) { - result = string + pad(minLength - string.length()); + result = string + " ".repeat(minLength - string.length()); } else if (pad < 0) { result = string.substring(0, minLength); } @@ -105,7 +84,6 @@ public static String pad(double val, int minLength) { return pad("" + val, minLength); } - /** * Dumps padded text. This is a simple tool for helping dump text * with padding to a Writer. @@ -115,14 +93,14 @@ public static String pad(double val, int minLength) { * @param string the string to output */ public static void dump(PrintWriter pw, int padding, String string) { - pw.print(pad(padding)); + pw.print(" ".repeat(padding)); pw.println(string); } public static String normalize(String text) { text = Normalizer.normalize(text, Normalizer.Form.NFD); text = text.replaceAll("\\p{M}", ""); //assumes unicode data -// text = text.replaceAll("[^\\p{ASCII}]", ""); + //text = text.replaceAll("[^\\p{ASCII}]", ""); return text; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/TimeSpec.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/TimeSpec.java index 53cb8ec6..296a12a7 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/TimeSpec.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/TimeSpec.java @@ -2,7 +2,7 @@ * Copyright 1999-2002 Carnegie Mellon University. * Portions Copyright 2002 Sun Microsystems, Inc. * Portions Copyright 2002 Mitsubishi Electric Research Laboratories. - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -31,7 +31,6 @@ package com.oracle.labs.mlrg.olcut.util; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -43,20 +42,17 @@ * be parsed using a regular expression, so things like 1d300m are allowed and will be * parsed correctly. */ -public class TimeSpec { +public final class TimeSpec { - private static Pattern timepat = Pattern.compile("(?:(\\d+)(d))??(?:(\\d+)(h))??(?:(\\d+)(m))??(?:(\\d+)(s))??(?:(\\d+)(ms))??"); + private static final Pattern timepat = Pattern.compile("(?:(\\d+)(d))??(?:(\\d+)(h))??(?:(\\d+)(m))??(?:(\\d+)(s))??(?:(\\d+)(ms))??"); - private final static Map tum; - - static { - tum = new HashMap<>(); - tum.put("d", TimeUnit.DAYS); - tum.put("h", TimeUnit.HOURS); - tum.put("m", TimeUnit.MINUTES); - tum.put("s", TimeUnit.SECONDS); - tum.put("ms", TimeUnit.MILLISECONDS); - } + private static final Map tum = Map.of( + "d", TimeUnit.DAYS, + "h", TimeUnit.HOURS, + "m", TimeUnit.MINUTES, + "s", TimeUnit.SECONDS, + "ms", TimeUnit.MINUTES + ); public static long parse(String timespec) throws IllegalArgumentException { Matcher m = timepat.matcher(timespec); diff --git a/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/util/StreamUtilTest.java b/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/util/StreamUtilTest.java deleted file mode 100644 index 784da4f6..00000000 --- a/olcut-core/src/test/java/com/oracle/labs/mlrg/olcut/util/StreamUtilTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. - * - * Licensed under the 2-clause BSD license. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package com.oracle.labs.mlrg.olcut.util; - - -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; -import java.util.Spliterator; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - - -public class StreamUtilTest { - private static final Logger logger = Logger.getLogger(StreamUtilTest.class.getName()); - - @Test - public void testBoundedParallelism() throws ExecutionException, InterruptedException { - // This hack is to ensure that tests pass on Github Actions, which uses weird VMs for macOS that confuse the - // parallelism checks. - int parallelismLevel; - String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); - if (os.contains("mac") || os.contains("darwin")) { - parallelismLevel = 1; - } else { - parallelismLevel = 2; - } - ForkJoinPool fjp = new ForkJoinPool(parallelismLevel); - - AtomicInteger unboundedCounter = new AtomicInteger(); - Stream unbounded = wrapStream(StreamUtil.boundParallelism(arrayFactory(10000).parallel()),unboundedCounter); - List output = unbounded.map(a -> a + 5).collect(Collectors.toList()); - - AtomicInteger boundedCounter = new AtomicInteger(); - Stream bounded = wrapStream(StreamUtil.boundParallelism(arrayFactory(10000).parallel()),boundedCounter); - List otherOutput = fjp.submit(() -> bounded.map(a -> a + 5).collect(Collectors.toList())).get(); - - logger.finer("Unbounded = " + unboundedCounter.get() + ", bounded = " + boundedCounter.get()); - assertNotEquals(boundedCounter.get(), unboundedCounter.get(), "Parallelism wasn't bounded"); - assertEquals(parallelismLevel << 2, boundedCounter.get(), "Parallelism wasn't bounded"); - } - - public static Stream arrayFactory(int size) { - Integer[] array = new Integer[size]; - for (int i = 0; i < size; i++) { - array[i] = i; - } - - return Arrays.stream(array); - } - - public static Stream wrapStream(Stream stream, AtomicInteger counter) { - Spliterator countingSpliterator = new CountingSpliterator<>(stream.spliterator(),counter); - - return StreamSupport.stream(countingSpliterator,true); - } - - private static class CountingSpliterator implements Spliterator { - private final AtomicInteger taskCounter; - private final Spliterator spliterator; - - public CountingSpliterator(Spliterator spliterator, AtomicInteger taskCounter) { - this.spliterator = spliterator; - this.taskCounter = taskCounter; - } - - @Override - public boolean tryAdvance(Consumer action) { - return spliterator.tryAdvance(action); - } - - @Override - public void forEachRemaining(Consumer action) { - if (!(spliterator instanceof CountingSpliterator)) { - taskCounter.incrementAndGet(); - } - spliterator.forEachRemaining(action); - } - - @Override - public Spliterator trySplit() { - Spliterator tmp = spliterator.trySplit(); - if (tmp != null) { - return new CountingSpliterator<>(tmp,taskCounter); - } else { - return null; - } - } - - @Override - public long estimateSize() { - return spliterator.estimateSize(); - } - - @Override - public long getExactSizeIfKnown() { - return spliterator.getExactSizeIfKnown(); - } - - @Override - public Comparator getComparator() { - return spliterator.getComparator(); - } - - @Override - public int characteristics() { - return spliterator.characteristics(); - } - } -} From 783fb5f0ac17d6683ae16804e88b1aa504fe8700 Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 22:36:11 -0500 Subject: [PATCH 4/8] Making SimpleProperty, MapProperty and ListProperty into records. - Now with more record patterns. --- .../olcut/config/edn/EdnConfigWriter.java | 12 +-- .../olcut/config/json/JsonConfigWriter.java | 10 +-- .../config/protobuf/ProtoConfigWriter.java | 10 +-- .../mlrg/olcut/config/ConfigurationData.java | 12 +-- .../labs/mlrg/olcut/config/PropertySheet.java | 16 ++-- .../olcut/config/property/ListProperty.java | 37 +-------- .../olcut/config/property/MapProperty.java | 37 +++------ .../olcut/config/property/SimpleProperty.java | 28 +------ .../olcut/config/xml/XMLConfigWriter.java | 81 +++++++++---------- 9 files changed, 84 insertions(+), 159 deletions(-) diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java index fc181545..638decfb 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnConfigWriter.java @@ -117,27 +117,27 @@ private Object writeProperty(Property p) throws ConfigWriterException { case MapProperty mapProperty -> { // map configurable field Map mRes = new HashMap<>(); - for (Map.Entry e : mapProperty.getMap().entrySet()) { + for (Map.Entry e : mapProperty.map().entrySet()) { if (e.getKey() == null) { throw new ConfigWriterException(new IllegalArgumentException("Can't write a map with null keys" + p.toString())); } if (e.getValue() == null) { throw new ConfigWriterException(new IllegalArgumentException("Can't write a map with null values: " + p.toString())); } - mRes.put(Keyword.newKeyword(e.getKey()), e.getValue().getValue()); + mRes.put(Keyword.newKeyword(e.getKey()), e.getValue().value()); } res = mRes; } case ListProperty listProperty -> { // list configurable field List lRes = new ArrayList<>(); - for (SimpleProperty s : listProperty.getSimpleList()) { + for (SimpleProperty s : listProperty.simpleList()) { if (s == null) { throw new ConfigWriterException(new IllegalArgumentException("Can't write a list with null values: " + p.toString())); } - lRes.add(s.getValue()); + lRes.add(s.value()); } - for (Class c : listProperty.getClassList()) { + for (Class c : listProperty.classList()) { if (c == null) { throw new ConfigWriterException(new IllegalArgumentException("Can't write a list with null values: " + p.toString())); } @@ -145,7 +145,7 @@ private Object writeProperty(Property p) throws ConfigWriterException { } res = lRes; } - case SimpleProperty simpleProperty -> res = simpleProperty.getValue(); + case SimpleProperty simpleProperty -> res = simpleProperty.value(); } return res; } diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java index c8ac3d68..68ab6a5d 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonConfigWriter.java @@ -140,12 +140,12 @@ public void writeComponent(Map attributes, Map // // Must be a string or component list writer.writeArrayFieldStart(key); - for (SimpleProperty s : list.getSimpleList()) { + for (SimpleProperty s : list.simpleList()) { writer.writeStartObject(); - writer.writeStringField(ConfigLoader.ITEM,s.getValue()); + writer.writeStringField(ConfigLoader.ITEM,s.value()); writer.writeEndObject(); } - for (Class c : list.getClassList()) { + for (Class c : list.classList()) { writer.writeStartObject(); writer.writeStringField(ConfigLoader.TYPE,c.getName()); writer.writeEndObject(); @@ -157,8 +157,8 @@ public void writeComponent(Map attributes, Map // // Must be a string,string map writer.writeObjectFieldStart(key); - for (Map.Entry e : map.getMap().entrySet()) { - writer.writeStringField(e.getKey(),e.getValue().getValue()); + for (Map.Entry e : map.map().entrySet()) { + writer.writeStringField(e.getKey(),e.getValue().value()); } writer.writeEndObject(); } diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java index b2c8ee89..f3b02b0f 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoConfigWriter.java @@ -118,10 +118,10 @@ public void writeComponent(Map attributes, Map // Must be a string/component list PropertyListProto.Builder listBuilder = PropertyListProto.newBuilder(); listBuilder.setName(key); - for (SimpleProperty s : ((ListProperty) value).getSimpleList()) { - listBuilder.addItem(s.getValue()); + for (SimpleProperty s : ((ListProperty) value).simpleList()) { + listBuilder.addItem(s.value()); } - for (Class c : ((ListProperty) value).getClassList()) { + for (Class c : ((ListProperty) value).classList()) { listBuilder.addType(c.getName()); } componentBuilder.addListProperty(listBuilder.build()); @@ -130,8 +130,8 @@ public void writeComponent(Map attributes, Map // Must be a string,string map PropertyMapProto.Builder mapBuilder = PropertyMapProto.newBuilder(); mapBuilder.setName(key); - for (Map.Entry e : ((MapProperty) value).getMap().entrySet()) { - mapBuilder.putElements(e.getKey(), e.getValue().getValue()); + for (Map.Entry e : ((MapProperty) value).map().entrySet()) { + mapBuilder.putElements(e.getKey(), e.getValue().value()); } componentBuilder.addMapProperty(mapBuilder.build()); } else { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java index c9249811..825f0d8e 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java @@ -250,14 +250,14 @@ public StructuralConfigurationData(Map contextMap, Co this.simpleProperties.put(propName, new DerefedProperty(contextMap, simpleProperty, propName, "")); case ListProperty listProperty -> { this.listProperties.put(propName, - IntStream.range(0, listProperty.getSimpleList().size()) + IntStream.range(0, listProperty.simpleList().size()) .mapToObj(i -> - new DerefedProperty(contextMap, listProperty.getSimpleList().get(i), propName, ", index: " + i)) + new DerefedProperty(contextMap, listProperty.simpleList().get(i), propName, ", index: " + i)) .collect(Collectors.toList())); - this.listClassProperties.put(propName, listProperty.getClassList()); + this.listClassProperties.put(propName, listProperty.classList()); } case MapProperty mapProperty -> - this.mapProperties.put(propName, mapProperty.getMap().entrySet().stream() + this.mapProperties.put(propName, mapProperty.map().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> new DerefedProperty(contextMap, e.getValue(), propName, ", PropValue key: " + e.getKey())))); @@ -379,7 +379,7 @@ private static class DerefedProperty { public DerefedProperty(Map confs, SimpleProperty prop, String propName, String locationContext) { this.propName = propName; this.locationContext = locationContext; - this.innerValue = prop.getValue(); + this.innerValue = prop.value(); // we do it this way because Boolean.parseBoolean doesn't throw like other parse methods if(this.innerValue.trim().equalsIgnoreCase("true") || this.innerValue.trim().equalsIgnoreCase("false")) { this.innerBool = Optional.of(Boolean.parseBoolean(this.innerValue)); @@ -401,7 +401,7 @@ public DerefedProperty(Map confs, SimpleProperty prop } catch (DateTimeParseException e) { this.innerTime = Optional.empty(); } - Optional maybeDeref = Optional.ofNullable(confs.get(prop.getValue())); + Optional maybeDeref = Optional.ofNullable(confs.get(prop.value())); isDerefed = maybeDeref.isPresent(); if(isDerefed) { innerConf = new StructuralConfigurationData(confs, maybeDeref.get()); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java index b6add7e1..0b5f8f3e 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java @@ -483,8 +483,8 @@ static Map parseMapField(ConfigurationManager cm, String instance FieldType genericft = FieldType.getFieldType(genericType); if (genericft != null) { Map map = new HashMap<>(); - for (Map.Entry e : input.getMap().entrySet()) { - String newVal = cm.getImmutableGlobalProperties().replaceGlobalProperties(instanceName, fieldName, e.getValue().getValue()); + for (Map.Entry e : input.map().entrySet()) { + String newVal = cm.getImmutableGlobalProperties().replaceGlobalProperties(instanceName, fieldName, e.getValue().value()); map.put(e.getKey(), parseSimpleField(cm, instanceName, fieldName, genericType, genericft, newVal)); } return map; @@ -501,9 +501,9 @@ static Object parseArrayField(ConfigurationManager cm, String instanceName, Stri // from the xml file, so we have to check it. List replaced = new ArrayList<>(); List> removeList = new ArrayList<>(); - List> classVals = new ArrayList<>(input.getClassList()); - for (SimpleProperty val : input.getSimpleList()) { - replaced.add(cm.getImmutableGlobalProperties().replaceGlobalProperties(instanceName, fieldName, val.getValue())); + List> classVals = new ArrayList<>(input.classList()); + for (SimpleProperty val : input.simpleList()) { + replaced.add(cm.getImmutableGlobalProperties().replaceGlobalProperties(instanceName, fieldName, val.value())); } // @@ -644,9 +644,9 @@ static Object parseListField(ConfigurationManager cm, String instanceName, Strin // from the xml file, so we have to check it. List replaced = new ArrayList<>(); List> removeList = new ArrayList<>(); - List> classVals = new ArrayList<>(input.getClassList()); - for (SimpleProperty val : input.getSimpleList()) { - replaced.add(cm.getImmutableGlobalProperties().replaceGlobalProperties(instanceName, fieldName, val.getValue())); + List> classVals = new ArrayList<>(input.classList()); + for (SimpleProperty val : input.simpleList()) { + replaced.add(cm.getImmutableGlobalProperties().replaceGlobalProperties(instanceName, fieldName, val.value())); } // diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java index dfc3e7d5..b5add842 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -31,39 +31,22 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; -import java.util.logging.Logger; /** * A ListProperty is a container for two lists, one of {@link SimpleProperty} instances and * one of {@link Class} instances. The Class instances are used to look up all instances of that class and * insert them into the field. */ -public final class ListProperty implements Property { +public record ListProperty(List simpleList, List> classList) implements Property { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(ListProperty.class.getName()); - - private final List simpleList; - - private final List> classList; - public ListProperty(List simpleList, List> classList) { this.simpleList = Collections.unmodifiableList(simpleList); this.classList = Collections.unmodifiableList(classList); } public ListProperty(List simpleList) { - this.simpleList = Collections.unmodifiableList(simpleList); - this.classList = Collections.emptyList(); - } - - public List getSimpleList() { - return simpleList; - } - - public List> getClassList() { - return classList; + this(simpleList, Collections.emptyList()); } @Override @@ -79,20 +62,6 @@ public ListProperty copy() { } } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ListProperty)) return false; - ListProperty that = (ListProperty) o; - return getSimpleList().equals(that.getSimpleList()) && - getClassList().equals(that.getClassList()); - } - - @Override - public int hashCode() { - return Objects.hash(getSimpleList(), getClassList()); - } - @Override public String toString() { return "[" + simpleList.toString() + ", " + classList.toString() + "]"; diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java index 8388f29f..ad06388c 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -35,53 +35,34 @@ /** * A MapProperty is a container for a Map from String to Property. */ -public final class MapProperty implements Property { +public record MapProperty(Map map) implements Property { private static final long serialVersionUID = 1L; - private final Map map; - - public MapProperty(Map map) { + public MapProperty(Map map) { this.map = Collections.unmodifiableMap(map); } - public Map getMap() { - return map; - } - @Override public MapProperty copy() { - Map output = new HashMap<>(); + Map output = new HashMap<>(); - for (Map.Entry e : map.entrySet()) { - output.put(e.getKey(),e.getValue().copy()); + for (Map.Entry e : map.entrySet()) { + output.put(e.getKey(), e.getValue().copy()); } return new MapProperty(output); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof MapProperty)) return false; - MapProperty that = (MapProperty) o; - return getMap().equals(that.getMap()); - } - - @Override - public int hashCode() { - return map.hashCode(); - } - @Override public String toString() { return map.toString(); } - public static MapProperty createFromStringMap(Map input) { + public static MapProperty createFromStringMap(Map input) { Map output = new HashMap<>(); - for (Map.Entry e : input.entrySet()) { - output.put(e.getKey(),new SimpleProperty(e.getValue())); + for (Map.Entry e : input.entrySet()) { + output.put(e.getKey(), new SimpleProperty(e.getValue())); } return new MapProperty(output); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java index 0d9bd2ad..3f1595bf 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -34,39 +34,15 @@ * A simple property is a single String which can be parsed as a field value (either by conversion or lookup in * a {@link ConfigurationManager}). */ -public final class SimpleProperty implements Property { +public record SimpleProperty(String value) implements Property { private static final long serialVersionUID = 1L; - private final String value; - - public SimpleProperty(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - public SimpleProperty copy() { return new SimpleProperty(value); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SimpleProperty)) return false; - SimpleProperty that = (SimpleProperty) o; - return getValue().equals(that.getValue()); - } - - @Override - public int hashCode() { - return value.hashCode(); - } - @Override public String toString() { return value; } - } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java index c6697ec6..ecc2d61f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/XMLConfigWriter.java @@ -40,6 +40,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -129,55 +130,53 @@ public void writeComponent(Map attributes, Map for (Entry property : properties.entrySet()) { String key = property.getKey(); Property value = property.getValue(); - if (value instanceof ListProperty) { - // - // Must be a string or component list - writer.writeCharacters("\t"); - writer.writeStartElement(ConfigLoader.PROPERTYLIST); - writer.writeAttribute(ConfigLoader.NAME, key); - writer.writeCharacters(System.lineSeparator()); - for (SimpleProperty s : ((ListProperty) value).getSimpleList()) { - writer.writeCharacters("\t\t"); - writer.writeStartElement(ConfigLoader.ITEM); - writer.writeCharacters(s.getValue()); + switch (value) { + case ListProperty(List simpleList, List> classList) -> { + writer.writeCharacters("\t"); + writer.writeStartElement(ConfigLoader.PROPERTYLIST); + writer.writeAttribute(ConfigLoader.NAME, key); + writer.writeCharacters(System.lineSeparator()); + for (SimpleProperty s : simpleList) { + writer.writeCharacters("\t\t"); + writer.writeStartElement(ConfigLoader.ITEM); + writer.writeCharacters(s.value()); + writer.writeEndElement(); + writer.writeCharacters(System.lineSeparator()); + } + for (Class c : classList) { + writer.writeCharacters("\t\t"); + writer.writeStartElement(ConfigLoader.TYPE); + writer.writeCharacters(c.getName()); + writer.writeEndElement(); + writer.writeCharacters(System.lineSeparator()); + } + writer.writeCharacters("\t"); writer.writeEndElement(); writer.writeCharacters(System.lineSeparator()); } - for (Class c : ((ListProperty)value).getClassList()) { - writer.writeCharacters("\t\t"); - writer.writeStartElement(ConfigLoader.TYPE); - writer.writeCharacters(c.getName()); + case MapProperty(Map map) -> { + writer.writeCharacters("\t"); + writer.writeStartElement(ConfigLoader.PROPERTYMAP); + writer.writeAttribute(ConfigLoader.NAME, key); + writer.writeCharacters(System.lineSeparator()); + for (Map.Entry e : map.entrySet()) { + writer.writeCharacters("\t\t"); + writer.writeEmptyElement(ConfigLoader.ENTRY); + writer.writeAttribute(ConfigLoader.KEY, e.getKey()); + writer.writeAttribute(ConfigLoader.VALUE, e.getValue().value()); + writer.writeCharacters(System.lineSeparator()); + } + writer.writeCharacters("\t"); writer.writeEndElement(); writer.writeCharacters(System.lineSeparator()); } - writer.writeCharacters("\t"); - writer.writeEndElement(); - writer.writeCharacters(System.lineSeparator()); - } else if (value instanceof MapProperty) { - // - // Must be a string,string map - writer.writeCharacters("\t"); - writer.writeStartElement(ConfigLoader.PROPERTYMAP); - writer.writeAttribute(ConfigLoader.NAME, key); - writer.writeCharacters(System.lineSeparator()); - for (Map.Entry e : ((MapProperty) value).getMap().entrySet()) { - writer.writeCharacters("\t\t"); - writer.writeEmptyElement(ConfigLoader.ENTRY); - writer.writeAttribute(ConfigLoader.KEY, e.getKey()); - writer.writeAttribute(ConfigLoader.VALUE, e.getValue().getValue()); + case SimpleProperty(String valueStr) -> { + writer.writeCharacters("\t"); + writer.writeEmptyElement(ConfigLoader.PROPERTY); + writer.writeAttribute(ConfigLoader.NAME, key); + writer.writeAttribute(ConfigLoader.VALUE, valueStr); writer.writeCharacters(System.lineSeparator()); } - writer.writeCharacters("\t"); - writer.writeEndElement(); - writer.writeCharacters(System.lineSeparator()); - } else { - // - // Standard property - writer.writeCharacters("\t"); - writer.writeEmptyElement(ConfigLoader.PROPERTY); - writer.writeAttribute(ConfigLoader.NAME, key); - writer.writeAttribute(ConfigLoader.VALUE, value.toString()); - writer.writeCharacters(System.lineSeparator()); } } From ef38d3fb3ee2bc99c38e33d4e41e46400c9821de Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 22:54:50 -0500 Subject: [PATCH 5/8] More records. - ConfigurationData is now a record. - Suitable PrimitiveProvenances are now records. --- .../labs/mlrg/olcut/config/edn/EdnLoader.java | 8 +- .../mlrg/olcut/config/json/JsonLoader.java | 10 +- .../config/json/JsonProvenanceSerializer.java | 2 +- .../olcut/config/protobuf/ProtoLoader.java | 10 +- .../ProtoProvenanceSerialization.java | 2 +- .../ExampleProvenancableConfigurable.java | 2 +- .../config_tests/ConfigurationDataTest.java | 6 +- .../mlrg/olcut/config/ConfigurationData.java | 151 +++++++----------- .../olcut/config/ConfigurationManager.java | 64 ++++---- .../labs/mlrg/olcut/config/Options.java | 4 +- .../labs/mlrg/olcut/config/PropertySheet.java | 10 +- .../olcut/config/property/ListProperty.java | 2 - .../olcut/config/property/MapProperty.java | 2 - .../mlrg/olcut/config/property/Property.java | 5 +- .../olcut/config/property/SimpleProperty.java | 2 - .../labs/mlrg/olcut/config/xml/SAXLoader.java | 10 +- .../olcut/provenance/ObjectProvenance.java | 4 +- .../olcut/provenance/PrimitiveProvenance.java | 4 +- .../mlrg/olcut/provenance/ProvenanceUtil.java | 46 +++--- .../SkeletalConfiguredObjectProvenance.java | 2 +- .../io/SimpleMarshalledProvenance.java | 9 +- .../io/XMLProvenanceSerialization.java | 8 +- .../primitives/BooleanProvenance.java | 7 +- .../provenance/primitives/ByteProvenance.java | 7 +- .../provenance/primitives/CharProvenance.java | 7 +- .../provenance/primitives/DateProvenance.java | 38 +---- .../primitives/DateTimeProvenance.java | 37 +---- .../primitives/DoubleProvenance.java | 7 +- .../provenance/primitives/EnumProvenance.java | 9 +- .../provenance/primitives/FileProvenance.java | 35 +--- .../primitives/FloatProvenance.java | 7 +- .../provenance/primitives/HashProvenance.java | 51 +----- .../provenance/primitives/IntProvenance.java | 7 +- .../provenance/primitives/LongProvenance.java | 7 +- .../primitives/ShortProvenance.java | 7 +- .../primitives/StringProvenance.java | 35 +--- .../provenance/primitives/TimeProvenance.java | 35 +--- .../provenance/primitives/URLProvenance.java | 36 +---- .../com/oracle/labs/mlrg/olcut/util/Pair.java | 54 ++----- 39 files changed, 217 insertions(+), 532 deletions(-) diff --git a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java index fedb3dc2..5c8dea36 100644 --- a/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java +++ b/olcut-config-edn/src/main/java/com/oracle/labs/mlrg/olcut/config/edn/EdnLoader.java @@ -351,11 +351,11 @@ private void parseComponent(List componentListItem) { throw new ConfigLoaderException("Override for undefined component: " + override + ", with name " + name); } - if (!type.equals(spd.getClassName())) { + if (!type.equals(spd.className())) { logger.log(Level.FINE, String.format("Overriding component %s with component %s, new type is %s overridden type was %s", - spd.getName(), name , type, spd.getClassName())); + spd.name(), name , type, spd.className())); } - rpd = new ConfigurationData(name, type, spd.getProperties(), serializedForm); + rpd = new ConfigurationData(name, type, spd.properties(), serializedForm); } else { if (rpdMap.get(name) != null) { throw new ConfigLoaderException("duplicate definition for " @@ -422,7 +422,7 @@ private void parseComponent(List componentListItem) { throw new ConfigLoaderException("Unexpected type for property value " + valObj.getClass().toString() + " with value " + valObj); } } - rpdMap.put(rpd.getName(), rpd); + rpdMap.put(rpd.name(), rpd); } private void parseSerializedObject(List serializedListItem) { diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java index 374d9f61..23e7c7da 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonLoader.java @@ -220,14 +220,14 @@ private void parseComponent(ObjectNode node) { spd = existingRPD.get(override); } } - if (curType != null && !curType.equals(spd.getClassName())) { + if (curType != null && !curType.equals(spd.className())) { logger.log(Level.FINE, String.format("Overriding component %s with component %s, new type is %s overridden type was %s", - spd.getName(), curComponent, curType, spd.getClassName())); + spd.name(), curComponent, curType, spd.className())); } if (curType == null) { - curType = spd.getClassName(); + curType = spd.className(); } - rpd = new ConfigurationData(curComponent, curType, spd.getProperties(), serializedForm); + rpd = new ConfigurationData(curComponent, curType, spd.properties(), serializedForm); overriding = true; } else { if (rpdMap.get(curComponent) != null) { @@ -311,7 +311,7 @@ private void parseComponent(ObjectNode node) { } } } - rpdMap.put(rpd.getName(),rpd); + rpdMap.put(rpd.name(),rpd); } private void parseFile(ObjectNode node) { diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java index db78fe1f..61ca5bff 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java @@ -67,7 +67,7 @@ public void serialize(MarshalledProvenance marshalledProvenance, JsonGenerator j case MapMarshalledProvenance mmp -> { jsonGenerator.writeObjectFieldStart(JsonProvenanceModule.MAP); for (Pair e : mmp) { - jsonGenerator.writeObjectField(e.getA(), e.getB()); + jsonGenerator.writeObjectField(e.a(), e.b()); } jsonGenerator.writeEndObject(); } diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java index b892ca10..4b1e0df8 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoLoader.java @@ -236,14 +236,14 @@ private void parseComponentProto(ComponentProto component) { spd = existingRPD.get(override); } } - if (!type.isEmpty() && !type.equals(spd.getClassName())) { + if (!type.isEmpty() && !type.equals(spd.className())) { logger.log(Level.FINE, String.format("Overriding component %s with component %s, new type is %s overridden type was %s", - spd.getName(), name, type, spd.getClassName())); + spd.name(), name, type, spd.className())); } if (type.isEmpty()) { - type = spd.getClassName(); + type = spd.className(); } - rpd = new ConfigurationData(name, type, spd.getProperties(), serializedForm); + rpd = new ConfigurationData(name, type, spd.properties(), serializedForm); } else { if (rpdMap.get(name) != null) { throw new ConfigLoaderException("duplicate definition for " @@ -293,6 +293,6 @@ private void parseComponentProto(ComponentProto component) { } rpd.add(e.getName(), listProp); } - rpdMap.put(rpd.getName(),rpd); + rpdMap.put(rpd.name(),rpd); } } diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java index 96ba884c..bc0a9753 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java @@ -354,7 +354,7 @@ private static int encodeMMP(RootProvenanceProto.Builder builder, MutableLong co counter.increment(); for (Pair p : mmp) { - mmpBuilder.putValues(p.getA(),dispatchFMP(builder,counter,p.getB())); + mmpBuilder.putValues(p.a(),dispatchFMP(builder,counter,p.b())); } builder.addMmp(mmpBuilder.build()); diff --git a/olcut-core-test/src/main/java/com/oracle/labs/mlrg/olcut/test/provenance/ExampleProvenancableConfigurable.java b/olcut-core-test/src/main/java/com/oracle/labs/mlrg/olcut/test/provenance/ExampleProvenancableConfigurable.java index 19c8e1e5..43da1fb6 100644 --- a/olcut-core-test/src/main/java/com/oracle/labs/mlrg/olcut/test/provenance/ExampleProvenancableConfigurable.java +++ b/olcut-core-test/src/main/java/com/oracle/labs/mlrg/olcut/test/provenance/ExampleProvenancableConfigurable.java @@ -132,7 +132,7 @@ public ExampleProvenance(ExampleProvenancableConfigurable host) { @SuppressWarnings("unchecked") public ExampleProvenance(Map provenances) { - this.className = ObjectProvenance.checkAndExtractProvenance(provenances,ObjectProvenance.CLASS_NAME,StringProvenance.class,ExampleProvenance.class.getName()).getValue(); + this.className = ObjectProvenance.checkAndExtractProvenance(provenances,ObjectProvenance.CLASS_NAME,StringProvenance.class,ExampleProvenance.class.getName()).value(); this.map = ObjectProvenance.checkAndExtractProvenance(provenances,MAP,MapProvenance.class,ExampleProvenance.class.getName()); Optional opt = ObjectProvenance.maybeExtractProvenance(provenances,DOUBLE_FIELD,DoubleProvenance.class,ExampleProvenance.class.getName()); if (opt.isPresent()) { diff --git a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java index 303e9aa3..3e79dce7 100644 --- a/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java +++ b/olcut-core-test/src/test/java/com/oracle/labs/mlrg/olcut/test/config_tests/ConfigurationDataTest.java @@ -67,8 +67,8 @@ public void structuralEqualsAllConfig() { .map(Optional::get) .collect(Collectors.toList()); - ConfigurationData aRoot = a.stream().filter(cd -> cd.getName().equals(aName)).findFirst().get(); - ConfigurationData bRoot = b.stream().filter(cd -> cd.getName().equals(bName)).findFirst().get(); + ConfigurationData aRoot = a.stream().filter(cd -> cd.name().equals(aName)).findFirst().get(); + ConfigurationData bRoot = b.stream().filter(cd -> cd.name().equals(bName)).findFirst().get(); assertTrue(ConfigurationData.structuralEquals(a, b, aName, bName)); @@ -103,7 +103,7 @@ public void structuralEqualsProvenanceRoundtrip() { List b = ProvenanceUtil.extractConfiguration(ac.getProvenance()); - String bName = b.get(0).getName(); + String bName = b.get(0).name(); assertTrue(ConfigurationData.structuralEquals(a, b, aName, bName)); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java index 825f0d8e..7a66bcd7 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationData.java @@ -2,7 +2,7 @@ * Copyright 1999-2004 Carnegie Mellon University. * Portions Copyright 2004 Sun Microsystems, Inc. * Portions Copyright 2003 Mitsubishi Electric Research Laboratories. - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -39,7 +39,6 @@ import com.oracle.labs.mlrg.olcut.config.property.SimpleProperty; import com.oracle.labs.mlrg.olcut.util.Util; -import java.io.Serializable; import java.time.OffsetDateTime; import java.time.OffsetTime; import java.time.format.DateTimeParseException; @@ -60,24 +59,17 @@ /** * Carrier for property data. Principally a {@link Map} from {@link String} to {@link Property}, and * a class name. + * + * @param name The name of the configured object. + * @param className The class name of the configured object. + * @param properties The properties to apply to that object. + * @param serializedForm A URL for a resource indicating from where the component can be + * deserialized. */ -public final class ConfigurationData implements Serializable { +public record ConfigurationData(String name, String className, Map properties, + String serializedForm) { private static final Logger logger = Logger.getLogger(ConfigurationData.class.getName()); - private static final long serialVersionUID = 1L; - - private final String name; - - private final String className; - - private final Map properties; - - /** - * A URL for a resource indicating from where the component can be - * deserialized. - */ - private final String serializedForm; - /** * Creates an empty ConfigurationData. * @param name the name of the item @@ -111,9 +103,10 @@ public ConfigurationData(String name, String className, String serializedForm) { /** * Creates a ConfigurationData with the specified properties. The properties are validated elsewhere as * this does not trigger class loading. - * @param name The name of the configured object. - * @param className The class name of the configured object. - * @param properties The properties to apply to that object. + * + * @param name The name of the configured object. + * @param className The class name of the configured object. + * @param properties The properties to apply to that object. * @param serializedForm A path to load the serialised form of this object (or null). */ public ConfigurationData(String name, String className, Map properties, String serializedForm) { @@ -133,32 +126,18 @@ public void add(String propName, Property propValue) { properties.put(propName, propValue); } - /** @return Returns the className. */ - public String getClassName() { - return className; - } - - /** @return Returns the name. */ - public String getName() { - return name; - } - /** - * Returns the path to the serialised form. - * @return The path to the serialised form. + * @return Returns an unmodifiable view on the properties. */ - public String getSerializedForm() { - return serializedForm; - } - - /** @return Returns an unmodifiable view on the properties. */ - public Map getProperties() { + @Override + public Map properties() { return Collections.unmodifiableMap(properties); } /** * Returns the value associated with that property name, or {@link Optional#empty} * if it doesn't exist. + * * @param propertyName The property name. * @return The {@link Optional#of} the property value or optional empty. */ @@ -184,25 +163,11 @@ public boolean contains(String propName) { /** * Copies this ConfigurationData. The copy is disconnected from the original as * it contains a different map (though all the elements are immutable and the same references). + * * @return A copy of this object. */ public ConfigurationData copy() { - return new ConfigurationData(name,className,properties,serializedForm); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ConfigurationData that)) return false; - return name.equals(that.name) && - className.equals(that.className) && - properties.equals(that.properties) && - Objects.equals(serializedForm, that.serializedForm); - } - - @Override - public int hashCode() { - return Objects.hash(name, className, properties, serializedForm); + return new ConfigurationData(name, className, properties, serializedForm); } @Override @@ -242,7 +207,7 @@ public StructuralConfigurationData(Map contextMap, Co this.listProperties = new HashMap<>(); this.listClassProperties = new HashMap<>(); this.mapProperties = new HashMap<>(); - for(Map.Entry propertyEntry: referencedCD.properties.entrySet()) { + for (Map.Entry propertyEntry : referencedCD.properties.entrySet()) { String propName = propertyEntry.getKey(); Property prop = propertyEntry.getValue(); switch (prop) { @@ -301,8 +266,8 @@ public boolean equals(Object o) { boolean simpleMatch = checkPresenceAllMatch(this.simpleProperties, that.simpleProperties, DerefedProperty::equals); - if(!simpleMatch) { - logger.fine("SimpleProperties don't match: as: " + this.simpleProperties + " bs: " +that.simpleProperties); + if (!simpleMatch) { + logger.fine("SimpleProperties don't match: as: " + this.simpleProperties + " bs: " + that.simpleProperties); } boolean mapMatch = checkPresenceAllMatch(this.mapProperties, that.mapProperties, @@ -311,27 +276,27 @@ public boolean equals(Object o) { aMap.keySet().stream() .allMatch(k -> aMap.get(k).equals(bMap.get(k)))); - if(!mapMatch) { + if (!mapMatch) { logger.fine("MapProperties don't match: as: " + this.mapProperties + " bs: " + that.mapProperties); } - boolean listMatch = checkPresenceAllMatch(this.listProperties,that.listProperties, (as, bs) -> { - boolean eq = Util.bagEquality(as, bs); - if(!eq) { - logger.fine("ListProperties not equal using bag equality:\na: " + as.toString() + "\nb: " + bs.toString()); + boolean listMatch = checkPresenceAllMatch(this.listProperties, that.listProperties, (as, bs) -> { + boolean eq = Util.bagEquality(as, bs); + if (!eq) { + logger.fine("ListProperties not equal using bag equality:\na: " + as.toString() + "\nb: " + bs.toString()); } return eq; }) && checkPresenceAllMatch(this.listClassProperties, that.listClassProperties, (as, bs) -> { boolean eq = Util.bagEquality(as, bs); - if(!eq) { - logger.fine("ListClassProperties not equal using bag equality:\na: " + as.toString() + "\nb: " + bs.toString()); + if (!eq) { + logger.fine("ListClassProperties not equal using bag equality:\na: " + as.toString() + "\nb: " + bs.toString()); } return eq; }); - if(!listMatch) { - logger.fine("ListProperties don't match: as: " + this.listProperties+ " bs: " + that.listProperties); + if (!listMatch) { + logger.fine("ListProperties don't match: as: " + this.listProperties + " bs: " + that.listProperties); logger.fine("ListClassProperties don't match: as: " + this.listClassProperties + " bs: " + that.listClassProperties); } @@ -381,7 +346,7 @@ public DerefedProperty(Map confs, SimpleProperty prop this.locationContext = locationContext; this.innerValue = prop.value(); // we do it this way because Boolean.parseBoolean doesn't throw like other parse methods - if(this.innerValue.trim().equalsIgnoreCase("true") || this.innerValue.trim().equalsIgnoreCase("false")) { + if (this.innerValue.trim().equalsIgnoreCase("true") || this.innerValue.trim().equalsIgnoreCase("false")) { this.innerBool = Optional.of(Boolean.parseBoolean(this.innerValue)); } else { this.innerBool = Optional.empty(); @@ -403,7 +368,7 @@ public DerefedProperty(Map confs, SimpleProperty prop } Optional maybeDeref = Optional.ofNullable(confs.get(prop.value())); isDerefed = maybeDeref.isPresent(); - if(isDerefed) { + if (isDerefed) { innerConf = new StructuralConfigurationData(confs, maybeDeref.get()); } } @@ -415,18 +380,18 @@ public DerefedProperty(Map confs, SimpleProperty prop private String reportString() { return String.format("Property Key: %s%s, with value %s %s %s %s %s", propName, locationContext, innerValue, (isDerefed ? "(is a reference)" : "(is not a reference)"), - innerDoubleValue.map(d -> "(parsed as double " + d +")").orElse("(not parsed as double)"), + innerDoubleValue.map(d -> "(parsed as double " + d + ")").orElse("(not parsed as double)"), innerDateTime.map(d -> "(parsed as date " + d + ")").orElse("(not parsed as date)"), innerBool.map(d -> "(parsed as bool " + d + ")").orElse("(not parsed as bool)")); } @Override public int hashCode() { - if(this.isDerefed) { + if (this.isDerefed) { return Objects.hash(this.isDerefed, this.innerConf); - } else if(this.innerBool.isPresent()) { + } else if (this.innerBool.isPresent()) { return Objects.hash(this.isDerefed, this.innerBool.get()); - } else if(this.innerDoubleValue.isPresent()){ + } else if (this.innerDoubleValue.isPresent()) { return Objects.hash(this.isDerefed, this.innerDoubleValue.get()); } else if (this.innerDateTime.isPresent()) { return Objects.hash(this.isDerefed, this.innerDateTime.get()); @@ -452,14 +417,14 @@ public int hashCode() { @Override public boolean equals(Object o) { if (o instanceof DerefedProperty that) { - if(this.isDerefed && that.isDerefed) { + if (this.isDerefed && that.isDerefed) { return this.innerConf.equals(that.innerConf); - } else if(!this.isDerefed && !that.isDerefed) { + } else if (!this.isDerefed && !that.isDerefed) { boolean valueMatch; if (this.innerBool.isPresent() && that.innerBool.isPresent()) { valueMatch = this.innerBool.get().booleanValue() == that.innerBool.get().booleanValue(); - } else if(this.innerDoubleValue.isPresent() && that.innerDoubleValue.isPresent()) { + } else if (this.innerDoubleValue.isPresent() && that.innerDoubleValue.isPresent()) { valueMatch = Util.doubleEquals(this.innerDoubleValue.get(), that.innerDoubleValue.get()); } else if (this.innerDateTime.isPresent() && that.innerDateTime.isPresent()) { valueMatch = this.innerDateTime.get().equals(that.innerDateTime.get()); @@ -468,7 +433,7 @@ public boolean equals(Object o) { } else { valueMatch = this.innerValue.equals(that.innerValue); } - if(!valueMatch) { + if (!valueMatch) { logger.fine(String.format("Property Value mismatch: %s and %s", this.reportString(), that.reportString())); } return valueMatch; @@ -534,52 +499,54 @@ private static boolean innerStructuralEquals(Map a, M * instances differ, together with the property values that differ between those instances. Any time this method * returns {@code false}, it should also log at least one message. * - * @param a ConfigurationData List for the first object and its children - * @param b ConfigurationData List for the second object and its children + * @param a ConfigurationData List for the first object and its children + * @param b ConfigurationData List for the second object and its children * @param aName Name of the first object * @param bName Name of the second object * @return {@code true} if class and all values of {@code aName} and {@code bName} are the same once * they have been dereferenced by name according to {@code a} and {@code b}. */ - public static boolean structuralEquals(List a, List b , String aName, String bName) { + public static boolean structuralEquals(List a, List b, String aName, String bName) { return innerStructuralEquals( - a.stream().collect(Collectors.toMap(ConfigurationData::getName, Function.identity())), - b.stream().collect(Collectors.toMap(ConfigurationData::getName, Function.identity())), + a.stream().collect(Collectors.toMap(ConfigurationData::name, Function.identity())), + b.stream().collect(Collectors.toMap(ConfigurationData::name, Function.identity())), aName, bName); } /** * Writes out the configuration data. + * * @param configWriter The writer to use. * @throws ConfigWriterException If the writer throws an exception. */ public void save(ConfigWriter configWriter) throws ConfigWriterException { - save(configWriter,Collections.emptySet()); + save(configWriter, Collections.emptySet()); } /** * Writes out the configuration data, redacting (i.e.,\ ignoring) fields if necessary. - * @param configWriter The writer to use. + * + * @param configWriter The writer to use. * @param redactedFields The fields to redact. * @throws ConfigWriterException If the writer throws an exception. */ public void save(ConfigWriter configWriter, Set redactedFields) { - Map attributes = new HashMap<>(); + Map attributes = new HashMap<>(); - attributes.put(ConfigLoader.NAME,name); - attributes.put(ConfigLoader.TYPE,className); - if (getSerializedForm() != null) { - attributes.put(ConfigLoader.SERIALIZED,getSerializedForm()); + attributes.put(ConfigLoader.NAME, name); + attributes.put(ConfigLoader.TYPE, className); + if (serializedForm() != null) { + attributes.put(ConfigLoader.SERIALIZED, serializedForm()); } - Map writtenProperties = new HashMap<>(); - for (Map.Entry p : properties.entrySet()) { + Map writtenProperties = new HashMap<>(); + for (Map.Entry p : properties.entrySet()) { if (!redactedFields.contains(p.getKey())) { - writtenProperties.put(p.getKey(),p.getValue()); + writtenProperties.put(p.getKey(), p.getValue()); } } - configWriter.writeComponent(attributes,writtenProperties); + configWriter.writeComponent(attributes, writtenProperties); } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java index 50f595b2..d8cb9cf0 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/ConfigurationManager.java @@ -453,7 +453,7 @@ public ConfigurationManager(String[] arguments, List configDa origGlobal = new GlobalProperties(globalProperties); for (ConfigurationData cd : configData) { - String instanceName = cd.getName(); + String instanceName = cd.name(); if (symbolTable.containsKey(instanceName)) { logger.fine("Overwriting " + instanceName + " loaded from file."); } @@ -756,7 +756,7 @@ private void parseConfigurableArguments(List arguments) throws ArgumentE if (split.length == 2) { ConfigurationData rpd = configurationDataMap.get(split[0]); if (rpd != null) { - if (checkConfigurableField(rpd.getClassName(),split[1])) { + if (checkConfigurableField(rpd.className(),split[1])) { // Found a valid configurable field, consume argument. argsItr.remove(); if (argsItr.hasNext()) { @@ -772,7 +772,7 @@ private void parseConfigurableArguments(List arguments) throws ArgumentE throw new ArgumentException(curArg,"No parameter for configurable override argument"); } } else { - throw new ArgumentException(curArg,"Failed to find field " + split[1] + " in component " + split[0] + " with class " + rpd.getClassName()); + throw new ArgumentException(curArg,"Failed to find field " + split[1] + " in component " + split[0] + " with class " + rpd.className()); } } else { throw new ArgumentException(curArg,"Failed to find component " + split[0]); @@ -846,7 +846,7 @@ private String[] parseOptionArguments(List arguments, Options options) t String argName = curArg.substring(2); Pair arg = longNameMap.get(argName); if (arg != null) { - Field f = arg.getA(); + Field f = arg.a(); FieldType ft = FieldType.getFieldType(f); // Consume argument. arguments.remove(i); @@ -856,17 +856,17 @@ private String[] parseOptionArguments(List arguments, Options options) t String param = arguments.get(i); List list = parseStringList(param); if (FieldType.arrayTypes.contains(ft)) { - f.set(arg.getB(), PropertySheet.parseArrayField(this, curArg, f.getName(), f.getType(), ft, ListProperty.createFromStringList(list))); + f.set(arg.b(), PropertySheet.parseArrayField(this, curArg, f.getName(), f.getType(), ft, ListProperty.createFromStringList(list))); } else if (FieldType.listTypes.contains(ft)) { List> genericList = PropertySheet.getGenericClass(f); if (genericList.size() == 1) { - f.set(arg.getB(), PropertySheet.parseListField(this, curArg, f.getName(), f.getType(), genericList.get(0), ft, ListProperty.createFromStringList(list))); + f.set(arg.b(), PropertySheet.parseListField(this, curArg, f.getName(), f.getType(), genericList.get(0), ft, ListProperty.createFromStringList(list))); } else { f.setAccessible(false); throw new ArgumentException(curArg,"Unknown generic type in argument"); } } else if (list.size() == 1) { - f.set(arg.getB(), PropertySheet.parseSimpleField(this,curArg,f.getName(),f.getType(),ft,list.get(0))); + f.set(arg.b(), PropertySheet.parseSimpleField(this,curArg,f.getName(),f.getType(),ft,list.get(0))); } else { f.setAccessible(false); throw new ArgumentException(curArg,"Parsed a list where a single argument was expected. Type = " + f.getType() + ", parsed output = " + list.toString()); @@ -890,11 +890,11 @@ private String[] parseOptionArguments(List arguments, Options options) t for (int j = 0; j < args.length - 1; j++) { Pair arg = charNameMap.get(args[j]); if (arg != null) { - Field f = arg.getA(); + Field f = arg.a(); f.setAccessible(true); FieldType ft = FieldType.getFieldType(f); if (FieldType.isBoolean(ft)) { - f.set(arg.getB(),true); + f.set(arg.b(),true); } else { f.setAccessible(false); throw new ArgumentException(curArg + " on element " + args[j], "Non boolean argument found where boolean expected"); @@ -907,7 +907,7 @@ private String[] parseOptionArguments(List arguments, Options options) t Pair arg = charNameMap.get(args[args.length-1]); if (arg != null) { - Field f = arg.getA(); + Field f = arg.a(); f.setAccessible(true); FieldType ft = FieldType.getFieldType(f); if (FieldType.isBoolean(ft)) { @@ -917,14 +917,14 @@ private String[] parseOptionArguments(List arguments, Options options) t // It only accepts things which lower case to "false" and "true". String nextArg = arguments.get(i); if (parseableAsBoolean(nextArg)) { - f.set(arg.getB(), Boolean.parseBoolean(nextArg)); + f.set(arg.b(), Boolean.parseBoolean(nextArg)); arguments.remove(i); } else { // Next arg is an option or something else, leave unparsed. - f.set(arg.getB(), true); + f.set(arg.b(), true); } } else { - f.set(arg.getB(), true); + f.set(arg.b(), true); } } else { // Now we need to accept the next parameter. @@ -933,17 +933,17 @@ private String[] parseOptionArguments(List arguments, Options options) t String param = arguments.get(i); List list = parseStringList(param); if (FieldType.arrayTypes.contains(ft)) { - f.set(arg.getB(), PropertySheet.parseArrayField(this, curArg, f.getName(), f.getType(), ft, ListProperty.createFromStringList(list))); + f.set(arg.b(), PropertySheet.parseArrayField(this, curArg, f.getName(), f.getType(), ft, ListProperty.createFromStringList(list))); } else if (FieldType.listTypes.contains(ft)) { List> genericList = PropertySheet.getGenericClass(f); if (genericList.size() == 1) { - f.set(arg.getB(), PropertySheet.parseListField(this, curArg, f.getName(), f.getType(), genericList.get(0), ft, ListProperty.createFromStringList(list))); + f.set(arg.b(), PropertySheet.parseListField(this, curArg, f.getName(), f.getType(), genericList.get(0), ft, ListProperty.createFromStringList(list))); } else { f.setAccessible(false); throw new ArgumentException(curArg,"Unknown generic type in argument"); } } else if (list.size() == 1) { - f.set(arg.getB(), PropertySheet.parseSimpleField(this,curArg,f.getName(),f.getType(),ft,list.get(0))); + f.set(arg.b(), PropertySheet.parseSimpleField(this,curArg,f.getName(),f.getType(),ft,list.get(0))); } else { f.setAccessible(false); throw new ArgumentException(curArg,"Parsed a list where a single argument was expected. Type = " + f.getType() + ", parsed output = " + list.toString()); @@ -1201,7 +1201,7 @@ public void overrideConfigurableProperty(String componentName, String propertyNa ConfigurationData rpd = configurationDataMap.get(componentName); if (rpd != null) { if (!symbolTable.containsKey(componentName)) { - StoredFieldType type = getStoredFieldType(rpd.getClassName(), propertyName); + StoredFieldType type = getStoredFieldType(rpd.className(), propertyName); if ((type == StoredFieldType.STRING) && (value instanceof SimpleProperty)) { rpd.add(propertyName, value); } else if ((type == StoredFieldType.LIST) && (value instanceof ListProperty)) { @@ -1209,7 +1209,7 @@ public void overrideConfigurableProperty(String componentName, String propertyNa } else if ((type == StoredFieldType.MAP) && (value instanceof MapProperty)) { rpd.add(propertyName, value); } else if (type == StoredFieldType.NONE) { - throw new PropertyException(componentName, propertyName, "Failed to find field " + propertyName + " in component " + componentName + " with class " + rpd.getClassName()); + throw new PropertyException(componentName, propertyName, "Failed to find field " + propertyName + " in component " + componentName + " with class " + rpd.className()); } else { throw new PropertyException(componentName, propertyName, "Incompatible field type, found " + type + ", expected " + value.getClass().getSimpleName()); } @@ -1283,17 +1283,17 @@ private PropertySheet getPropertySheet(String instanceNa // it based upon our raw property data ConfigurationData rpd = configurationDataMap.get(instanceName); if(rpd != null) { - String className = rpd.getClassName(); + String className = rpd.className(); try { Class confClass = Class.forName(className); if (Configurable.class.isAssignableFrom(confClass)) { PropertySheet propertySheet = new PropertySheet<>((Class)confClass,this,rpd); symbolTable.put(instanceName, propertySheet); } else { - throw new PropertyException(rpd.getName(), "Class " + className + " does not implement Configurable."); + throw new PropertyException(rpd.name(), "Class " + className + " does not implement Configurable."); } } catch (ClassNotFoundException e) { - throw new PropertyException(e, rpd.getName(), "Class " + className + " not found"); + throw new PropertyException(e, rpd.name(), "Class " + className + " not found"); } } } @@ -1506,7 +1506,7 @@ public Map lookupAllMap(Class c) { if(!c.isInterface()) { String className = c.getName(); for (Map.Entry e : configurationDataMap.entrySet()) { - if (e.getValue().getClassName().equals(className)) { + if (e.getValue().className().equals(className)) { ret.put(e.getKey(),(T)lookup(e.getKey())); } } @@ -1516,7 +1516,7 @@ public Map lookupAllMap(Class c) { // implementing classes and return them. for (Map.Entry e : configurationDataMap.entrySet()) { try { - Class clazz = Class.forName(e.getValue().getClassName()); + Class clazz = Class.forName(e.getValue().className()); if (c.isAssignableFrom(clazz) && !clazz.isInterface()) { ret.put(e.getKey(),(T)innerLookup(e.getKey(),null,true)); } @@ -1545,7 +1545,7 @@ public List lookupAll(Class c) { if(!c.isInterface()) { String className = c.getName(); for (Map.Entry e : configurationDataMap.entrySet()) { - if (e.getValue().getClassName().equals(className)) { + if (e.getValue().className().equals(className)) { ret.add((T)lookup(e.getKey())); } } @@ -1555,7 +1555,7 @@ public List lookupAll(Class c) { // implementing classes and return them. for (Map.Entry e : configurationDataMap.entrySet()) { try { - Class clazz = Class.forName(e.getValue().getClassName()); + Class clazz = Class.forName(e.getValue().className()); if (c.isAssignableFrom(clazz) && !clazz.isInterface()) { ret.add((T)innerLookup(e.getKey(),null,true)); } @@ -1602,14 +1602,14 @@ public T lookupSingleton(Class c, boolean allowAssig for(Map.Entry e : configurationDataMap.entrySet()) { ConfigurationData rpd = e.getValue(); try { - Class pclass = Class.forName(rpd.getClassName()); + Class pclass = Class.forName(rpd.className()); if ((allowAssignable && c.isAssignableFrom(pclass)) || - (!allowAssignable && rpd.getClassName().equals(c.getName()))) { + (!allowAssignable && rpd.className().equals(c.getName()))) { instanceNames.add(e.getKey()); } } catch(ClassNotFoundException ex) { logger.warning(String.format("No class %s found in ConfigurationManager", - rpd.getClassName())); + rpd.className())); } } @@ -1626,7 +1626,7 @@ public T lookupSingleton(Class c, boolean allowAssig String matchedName = instanceNames.getFirst(); ConfigurationData cd = configurationDataMap.get(matchedName); try { - Class matchedClass = Class.forName(cd.getClassName()); + Class matchedClass = Class.forName(cd.className()); if (!matchedClass.isInterface()) { return (T)lookup(matchedName); } else { @@ -1652,13 +1652,13 @@ public List listAll(Class c) { for(Map.Entry e : configurationDataMap.entrySet()) { ConfigurationData rpd = e.getValue(); try { - Class pclass = Class.forName(rpd.getClassName()); + Class pclass = Class.forName(rpd.className()); if (c.isAssignableFrom(pclass)) { ret.add(e.getKey()); } } catch(ClassNotFoundException ex) { logger.warning(String.format("No class %s found in ConfigurationManager", - rpd.getClassName())); + rpd.className())); } } @@ -1758,7 +1758,7 @@ public void addSubConfiguration(ConfigurationManager subCM, boolean overwrite) { * this configuration manager instance. */ public void addConfiguration(ConfigurationData newData) { - String instanceName = newData.getName(); + String instanceName = newData.name(); if (symbolTable.containsKey(instanceName)) { throw new IllegalArgumentException("tried to override existing instantiated component name"); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java index c5e77dff..59ff41cf 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/Options.java @@ -406,8 +406,8 @@ public static Set> getAllOptions(Class, Class> e : tempSet.entrySet()) { if (ret.containsKey(e.getValue())) { Pair otherOccurrence = ret.get(e.getValue()); - String firstOccurrence = otherOccurrence.getA() + "." + otherOccurrence.getB(); - String thisOccurrence = e.getKey().getA() + "." + e.getKey().getB(); + String firstOccurrence = otherOccurrence.a() + "." + otherOccurrence.b(); + String thisOccurrence = e.getKey().a() + "." + e.getKey().b(); throw new ArgumentException(firstOccurrence, thisOccurrence, "There are two instances of " + e.getValue().getName() + " in this Options tree."); } else { ret.put(e.getValue(), e.getKey()); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java index 0b5f8f3e..09908e19 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/PropertySheet.java @@ -138,7 +138,7 @@ public enum StoredFieldType { ConfigurationManager cm, ConfigurationData rpd) { this.ownerClass = confClass; this.cm = cm; - this.instanceName = rpd.getName(); + this.instanceName = rpd.name(); this.data = rpd; processAnnotations(this, confClass); @@ -146,14 +146,14 @@ public enum StoredFieldType { // // If there were any properties in the XML file that were not annotated, // then throw a property exception. - for (String propName : rpd.getProperties().keySet()) { + for (String propName : rpd.properties().keySet()) { if (!propValues.containsKey(propName)) { throw new PropertyException(instanceName, propName, "Unknown property in configuration file."); } } - propValues.putAll(rpd.getProperties()); + propValues.putAll(rpd.properties()); } /** @@ -292,8 +292,8 @@ public synchronized T getOwner(ComponentListener cl, boolean reuseComponent) // // Should we load a serialized form? - if (data.getSerializedForm() != null) { - String actualLocation = flattenString("", data.getSerializedForm()); + if (data.serializedForm() != null) { + String actualLocation = flattenString("", data.serializedForm()); T obj = null; InputStream serStream = IOUtil.getInputStreamForLocation(actualLocation); if (serStream != null) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java index b5add842..5a08672d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/ListProperty.java @@ -38,8 +38,6 @@ * insert them into the field. */ public record ListProperty(List simpleList, List> classList) implements Property { - private static final long serialVersionUID = 1L; - public ListProperty(List simpleList, List> classList) { this.simpleList = Collections.unmodifiableList(simpleList); this.classList = Collections.unmodifiableList(classList); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java index ad06388c..97ec020f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/MapProperty.java @@ -36,8 +36,6 @@ * A MapProperty is a container for a Map from String to Property. */ public record MapProperty(Map map) implements Property { - private static final long serialVersionUID = 1L; - public MapProperty(Map map) { this.map = Collections.unmodifiableMap(map); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java index 0a128b1e..f5b458f2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/Property.java @@ -28,14 +28,11 @@ package com.oracle.labs.mlrg.olcut.config.property; -import java.io.Serializable; - /** * Tag interface for the types extracted from a configuration file. *

* Property implementations should be immutable and final. - *

*/ -public sealed interface Property extends Serializable permits ListProperty, MapProperty, SimpleProperty { +public sealed interface Property permits ListProperty, MapProperty, SimpleProperty { public Property copy(); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java index 3f1595bf..4b337ed7 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/property/SimpleProperty.java @@ -35,8 +35,6 @@ * a {@link ConfigurationManager}). */ public record SimpleProperty(String value) implements Property { - private static final long serialVersionUID = 1L; - public SimpleProperty copy() { return new SimpleProperty(value); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java index 7067f8ee..ba2b035f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/config/xml/SAXLoader.java @@ -234,14 +234,14 @@ public void startElement(String uri, String localName, String qName, spd = existingRPD.get(override); } } - if (curType != null && !curType.equals(spd.getClassName())) { + if (curType != null && !curType.equals(spd.className())) { logger.log(Level.FINE, String.format("Overriding component %s with component %s, new type is %s overridden type was %s", - spd.getName(), curComponent, curType, spd.getClassName())); + spd.name(), curComponent, curType, spd.className())); } if (curType == null) { - curType = spd.getClassName(); + curType = spd.className(); } - rpd = new ConfigurationData(curComponent, curType, spd.getProperties(), serializedForm); + rpd = new ConfigurationData(curComponent, curType, spd.properties(), serializedForm); overriding = true; } else { if (rpdMap.get(curComponent) != null) { @@ -374,7 +374,7 @@ public void endElement(String uri, String localName, String qName) throws SAXParseException { switch (qName) { case COMPONENT: - rpdMap.put(rpd.getName(), rpd); + rpdMap.put(rpd.name(), rpd); rpd = null; overriding = false; break; diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java index feaf931a..470f5ce3 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ObjectProvenance.java @@ -71,9 +71,9 @@ default public String generateString(String name) { sb.append(name); sb.append("("); for (Pair p : this) { - sb.append(p.getA()); + sb.append(p.a()); sb.append('='); - sb.append(p.getB().toString()); + sb.append(p.b().toString()); sb.append(','); } sb.replace(sb.length()-1,sb.length(),")"); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java index 24fe44cf..fe8060b4 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/PrimitiveProvenance.java @@ -65,12 +65,12 @@ public sealed interface PrimitiveProvenance extends Provenance permits Boolea * object. * @return The key. */ - public String getKey(); + public String key(); /** * Gets the value of this provenance. * @return The value. */ - public T getValue(); + public T value(); } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java index c18c4354..3d5cd196 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java @@ -236,7 +236,7 @@ public static > List unwrap(ListProvenanc List output = new ArrayList<>(); for (PrimitiveProvenance p : listProvenance) { - output.add(p.getValue()); + output.add(p.value()); } return output; @@ -254,7 +254,7 @@ public static > Map unwrap(MapProv Map output = new HashMap<>(); for (Map.Entry p : mapProvenance.getMap().entrySet()) { - output.put(p.getKey(),p.getValue().getValue()); + output.put(p.getKey(),p.getValue().value()); } return output; @@ -342,9 +342,9 @@ private static String formattedProvenanceString(ObjectProvenance prov, int depth for (Pair p : prov) { builder.append(tabs); builder.append('\t'); - builder.append(p.getA()); + builder.append(p.a()); builder.append(" = "); - Provenance innerProv = p.getB(); + Provenance innerProv = p.b(); formatProvenance(innerProv,builder,tabs,depth); builder.append('\n'); } @@ -363,7 +363,7 @@ private static String formattedProvenanceString(ObjectProvenance prov, int depth */ private static void formatProvenance(Provenance innerProv, StringBuilder builder, String tabs, int depth) { switch (innerProv) { - case PrimitiveProvenance primitiveProvenance -> builder.append(primitiveProvenance.getValue()); + case PrimitiveProvenance primitiveProvenance -> builder.append(primitiveProvenance.value()); case ListProvenance listProv -> { if (listProv.getList().isEmpty()) { builder.append("List[]"); @@ -387,9 +387,9 @@ private static void formatProvenance(Provenance innerProv, StringBuilder builder for (Pair provElem : mapProv) { builder.append(tabs); builder.append("\t\t"); - builder.append(provElem.getA()); + builder.append(provElem.a()); builder.append('='); - formatProvenance(provElem.getB(), builder, tabs, depth + 1); + formatProvenance(provElem.b(), builder, tabs, depth + 1); builder.append('\n'); } builder.append(tabs); @@ -416,8 +416,8 @@ public static Map convertToMap(ObjectProvenance prov) { Map output = new HashMap<>(); for (Pair p : prov) { - String key = p.getA(); - Provenance innerProv = p.getB(); + String key = p.a(); + Provenance innerProv = p.b(); Object value = innerConvertToMap(innerProv); output.put(key,value); } @@ -434,7 +434,7 @@ public static Map convertToMap(ObjectProvenance prov) { private static Object innerConvertToMap(Provenance prov) { switch (prov) { case PrimitiveProvenance primitiveProvenance -> { - return String.valueOf(primitiveProvenance.getValue()); + return String.valueOf(primitiveProvenance.value()); } case ListProvenance listProv -> { if (listProv.getList().isEmpty()) { @@ -453,8 +453,8 @@ private static Object innerConvertToMap(Provenance prov) { } else { Map map = new HashMap<>(); for (Pair provElem : mapProv) { - String newKey = provElem.getA(); - Object newValue = innerConvertToMap(provElem.getB()); + String newKey = provElem.a(); + Object newValue = innerConvertToMap(provElem.b()); map.put(newKey, newValue); } return Collections.unmodifiableMap(map); @@ -585,14 +585,14 @@ private static ConfigurationData extractSingleConfiguration(ConfiguredObjectProv Map propMap = new HashMap<>(); for (Pair pair : mapProvenance) { - Provenance valueProv = pair.getB(); + Provenance valueProv = pair.b(); if (valueProv instanceof ConfiguredObjectProvenance confProv) { // skip nulls if (!(confProv instanceof NullConfiguredProvenance)) { - propMap.put(pair.getA(), new SimpleProperty(computeName(confProv, map.get(confProv)))); + propMap.put(pair.a(), new SimpleProperty(computeName(confProv, map.get(confProv)))); } } else { - propMap.put(pair.getA(), new SimpleProperty(valueProv.toString())); + propMap.put(pair.a(), new SimpleProperty(valueProv.toString())); } } @@ -671,8 +671,8 @@ private static ObjectMarshalledProvenance marshalSingleProvenance(ObjectProvenan Map outputMap = new HashMap<>(); for (Pair e : provenance) { - String key = e.getA(); - Provenance prov = e.getB(); + String key = e.a(); + Provenance prov = e.b(); FlatMarshalledProvenance marshalledProvenance = flattenSingleProvenance(prov,key,map); outputMap.put(key,marshalledProvenance); } @@ -703,7 +703,7 @@ private static FlatMarshalledProvenance flattenSingleProvenance(Provenance prov, Map propMap = new HashMap<>(); for (Pair pair : mapProvenance) { - propMap.put(pair.getA(), flattenSingleProvenance(pair.getB(), pair.getA(), map)); + propMap.put(pair.a(), flattenSingleProvenance(pair.b(), pair.a(), map)); } return new MapMarshalledProvenance(propMap); @@ -733,7 +733,7 @@ private static FlatMarshalledProvenance flattenSingleProvenance(Provenance prov, */ private static void extractProvenanceToQueue(Queue processingQueue, ObjectProvenance curProv) { for (Pair p : curProv) { - Provenance prov = p.getB(); + Provenance prov = p.b(); if (prov instanceof ObjectProvenance) { processingQueue.add((ObjectProvenance)prov); } else if (prov instanceof ListProvenance) { @@ -744,8 +744,8 @@ private static void extractProvenanceToQueue(Queue processingQ } } else if (prov instanceof MapProvenance) { for (Pair mapElement : (MapProvenance) prov) { - if (mapElement.getB() instanceof ObjectProvenance) { - processingQueue.add((ObjectProvenance)mapElement.getB()); + if (mapElement.b() instanceof ObjectProvenance) { + processingQueue.add((ObjectProvenance)mapElement.b()); } } } @@ -857,7 +857,7 @@ private static Provenance unmarshalFlat(String hostProvName, FlatMarshalledProve case MapMarshalledProvenance mmp -> { Map convertedMap = new HashMap<>(); for (Pair tuple : mmp) { - convertedMap.put(tuple.getA(), unmarshalFlat(hostProvName, tuple.getB(), unmarshalledObjects, marshalledObjects)); + convertedMap.put(tuple.a(), unmarshalFlat(hostProvName, tuple.b(), unmarshalledObjects, marshalledObjects)); } return new MapProvenance<>(convertedMap); } @@ -898,7 +898,7 @@ public static void writeObject(Provenancable readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException { ConfiguredObjectProvenance provenance = (ConfiguredObjectProvenance) inputStream.readObject(); List configurationData = ProvenanceUtil.extractConfiguration(provenance); - String componentName = configurationData.getFirst().getName(); + String componentName = configurationData.getFirst().name(); ConfigurationManager cm = new ConfigurationManager(); cm.addConfiguration(configurationData); @SuppressWarnings("unchecked") diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java index 5abefede..ddc3e7dc 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java @@ -523,7 +523,7 @@ private static Optional convertPrimitive(FieldType ft, Class fiel if (o == null) { return Optional.empty(); } else { - return Optional.of(new EnumProvenance<>(fieldName, (Enum) o)); + return Optional.of(new EnumProvenance<>(fieldName, (Enum) o)); } case CONFIGURABLE: if (o == null) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java index d0c50277..5f95791b 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java @@ -30,7 +30,6 @@ import com.oracle.labs.mlrg.olcut.provenance.ObjectProvenance; import com.oracle.labs.mlrg.olcut.provenance.PrimitiveProvenance; -import com.oracle.labs.mlrg.olcut.provenance.Provenance; import com.oracle.labs.mlrg.olcut.provenance.ProvenanceException; import com.oracle.labs.mlrg.olcut.provenance.ProvenanceUtil.HashType; import com.oracle.labs.mlrg.olcut.provenance.primitives.BooleanProvenance; @@ -85,7 +84,7 @@ public final class SimpleMarshalledProvenance implements FlatMarshalledProvenanc * @param The type of the enum. */ public > SimpleMarshalledProvenance(EnumProvenance enumProv) { - this(enumProv.getKey(), enumProv.getValue().toString(), enumProv.getClass().getName(), false, enumProv.getEnumClass()); + this(enumProv.key(), enumProv.value().toString(), enumProv.getClass().getName(), false, enumProv.getEnumClass()); } /** @@ -94,7 +93,7 @@ public > SimpleMarshalledProvenance(EnumProvenance enumProv * @param provenance A hash provenance. */ public SimpleMarshalledProvenance(HashProvenance provenance) { - this(provenance.getKey(), provenance.getValue(), provenance.getClass().getName(), false, provenance.getType().toString()); + this(provenance.key(), provenance.value(), provenance.getClass().getName(), false, provenance.type().toString()); } /** @@ -103,7 +102,7 @@ public SimpleMarshalledProvenance(HashProvenance provenance) { * @param The type of primitive. */ public SimpleMarshalledProvenance(PrimitiveProvenance provenance) { - this(provenance.getKey(), provenance.getValue().toString(), provenance.getClass().getName(), false, ""); + this(provenance.key(), provenance.value().toString(), provenance.getClass().getName(), false, ""); } /** @@ -174,7 +173,7 @@ public PrimitiveProvenance unmarshallPrimitive() { unmarshalled = new DoubleProvenance(key,Double.parseDouble(value)); } else if (provClass.equals(EnumProvenance.class)) { Class enumClass = (Class) Class.forName(additional); - Enum enumValue = Enum.valueOf(enumClass,value); + Enum enumValue = Enum.valueOf(enumClass,value); unmarshalled = new EnumProvenance<>(key,enumValue); } else if (provClass.equals(FileProvenance.class)) { unmarshalled = new FileProvenance(key,new File(value)); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java index 4730ad03..a6aabeac 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java @@ -350,7 +350,7 @@ private void writeMMP(XMLStreamWriter writer, String key, MapMarshalledProvenanc writer.writeCharacters(System.lineSeparator()); } for (Pair p : mmp) { - dispatchFMP(writer, p.getA(), p.getB(), depth + 1); + dispatchFMP(writer, p.a(), p.b(), depth + 1); } if (prettyPrint) { for (int i = 0; i < depth; i++) { @@ -512,13 +512,13 @@ public void endElement(String uri, String localName, String qName) Pair pair = provenanceChain.pollLast().emitProvenance(); if (provenanceChain.isEmpty()) { // Must be in the root node - ompProvMap.put(pair.getA(),pair.getB()); + ompProvMap.put(pair.a(),pair.b()); } else { ProvCollection pc = provenanceChain.peekLast(); if (pc.isMap()) { - pc.addProvenance(pair.getA(),pair.getB()); + pc.addProvenance(pair.a(),pair.b()); } else { - pc.addProvenance(pair.getB()); + pc.addProvenance(pair.b()); } } } else { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/BooleanProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/BooleanProvenance.java index 34cd397e..efc1cdf7 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/BooleanProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/BooleanProvenance.java @@ -48,20 +48,19 @@ public BooleanProvenance(String key, boolean value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Boolean getValue() { + public Boolean value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof BooleanProvenance)) return false; - BooleanProvenance that = (BooleanProvenance) o; + if (!(o instanceof BooleanProvenance that)) return false; return key.equals(that.key) && value == that.value; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ByteProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ByteProvenance.java index e446ef55..6bb070cd 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ByteProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ByteProvenance.java @@ -48,20 +48,19 @@ public ByteProvenance(String key, byte value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Byte getValue() { + public Byte value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ByteProvenance)) return false; - ByteProvenance that = (ByteProvenance) o; + if (!(o instanceof ByteProvenance that)) return false; return key.equals(that.key) && value == that.value; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/CharProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/CharProvenance.java index 88eadf1d..6657565d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/CharProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/CharProvenance.java @@ -48,20 +48,19 @@ public CharProvenance(String key, char value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Character getValue() { + public Character value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof CharProvenance)) return false; - CharProvenance that = (CharProvenance) o; + if (!(o instanceof CharProvenance that)) return false; return key.equals(that.key) && value == that.value; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateProvenance.java index e81043f4..7062bbf1 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -31,47 +31,13 @@ import com.oracle.labs.mlrg.olcut.provenance.PrimitiveProvenance; import java.time.LocalDate; -import java.util.Objects; /** * A {@link PrimitiveProvenance} which records a date value. */ -public final class DateProvenance implements PrimitiveProvenance { +public record DateProvenance(String key, LocalDate value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final String key; - - private final LocalDate value; - - public DateProvenance(String key, LocalDate value) { - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return key; - } - - @Override - public LocalDate getValue() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof DateProvenance)) return false; - DateProvenance that = (DateProvenance) o; - return key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - @Override public String toString() { return value.toString(); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateTimeProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateTimeProvenance.java index 170fc7fa..bfda55d2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateTimeProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DateTimeProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -36,42 +36,9 @@ /** * A {@link PrimitiveProvenance} which records a date/time value with time zone offset. */ -public final class DateTimeProvenance implements PrimitiveProvenance { +public record DateTimeProvenance(String key, OffsetDateTime value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final String key; - - private final OffsetDateTime value; - - public DateTimeProvenance(String key, OffsetDateTime value) { - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return key; - } - - @Override - public OffsetDateTime getValue() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof DateTimeProvenance)) return false; - DateTimeProvenance that = (DateTimeProvenance) o; - return key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - @Override public String toString() { return value.toString(); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DoubleProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DoubleProvenance.java index eb40f20d..362dff9f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DoubleProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/DoubleProvenance.java @@ -48,20 +48,19 @@ public DoubleProvenance(String key, double value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Double getValue() { + public Double value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof DoubleProvenance)) return false; - DoubleProvenance that = (DoubleProvenance) o; + if (!(o instanceof DoubleProvenance that)) return false; return key.equals(that.key) && Double.compare(value,that.value) == 0; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/EnumProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/EnumProvenance.java index b0f52a82..6701dc2f 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/EnumProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/EnumProvenance.java @@ -35,7 +35,7 @@ /** * A {@link PrimitiveProvenance} which records an enum value. */ -public final class EnumProvenance implements PrimitiveProvenance { +public final class EnumProvenance> implements PrimitiveProvenance { private static final long serialVersionUID = 1L; private final String key; @@ -55,20 +55,19 @@ public String getEnumClass() { } @Override - public String getKey() { + public String key() { return key; } @Override - public E getValue() { + public E value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof EnumProvenance)) return false; - EnumProvenance that = (EnumProvenance) o; + if (!(o instanceof EnumProvenance that)) return false; return key.equals(that.key) && value.equals(that.value) && enumClass.equals(that.enumClass); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FileProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FileProvenance.java index d30b3d9a..63f39580 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FileProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FileProvenance.java @@ -36,48 +36,19 @@ /** * A {@link PrimitiveProvenance} which records a file (also used for a Path). - * + *

* Converts each input into a path, gets the absolute path, normalizes it then stores the file. */ -public final class FileProvenance implements PrimitiveProvenance { +public record FileProvenance(String key, File value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final String key; - - private final File value; - public FileProvenance(String key, File value) { this.key = key; this.value = value.toPath().toAbsolutePath().normalize().toFile(); } public FileProvenance(String key, Path value) { - this.key = key; - this.value = value.toAbsolutePath().normalize().toFile(); - } - - @Override - public String getKey() { - return key; - } - - @Override - public File getValue() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof FileProvenance)) return false; - FileProvenance that = (FileProvenance) o; - return key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); + this(key, value.toAbsolutePath().normalize().toFile()); } @Override diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FloatProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FloatProvenance.java index 14e6f3b2..31571911 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FloatProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/FloatProvenance.java @@ -48,20 +48,19 @@ public FloatProvenance(String key, float value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Float getValue() { + public Float value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof FloatProvenance)) return false; - FloatProvenance that = (FloatProvenance) o; + if (!(o instanceof FloatProvenance that)) return false; return key.equals(that.key) && Float.compare(value,that.value) == 0; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/HashProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/HashProvenance.java index e9fc32fd..948449ff 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/HashProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/HashProvenance.java @@ -32,64 +32,19 @@ import com.oracle.labs.mlrg.olcut.provenance.ProvenanceUtil; import com.oracle.labs.mlrg.olcut.provenance.ProvenanceUtil.HashType; -import java.util.Objects; - /** * A provenance which records the String representation of a hash, * along with the type of hash function which generated it. */ -public final class HashProvenance implements PrimitiveProvenance { +public record HashProvenance(HashType type, String key, String value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final HashType type; - - private final String key; - - private final String value; - - public HashProvenance(HashType type, String key, String value) { - this.type = type; - this.key = key; - this.value = value; - } - public HashProvenance(HashType type, String key, byte[] value) { - this.type = type; - this.key = key; - this.value = ProvenanceUtil.bytesToHexString(value); - } - - @Override - public String getKey() { - return key; - } - - @Override - public String getValue() { - return value; - } - - public HashType getType() { - return type; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof HashProvenance)) return false; - HashProvenance that = (HashProvenance) o; - return type == that.type && - key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(type, key, value); + this(type, key, ProvenanceUtil.bytesToHexString(value)); } @Override public String toString() { - return type.name+"["+value+"]"; + return type.name + "[" + value + "]"; } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/IntProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/IntProvenance.java index 0745aa45..415e19e2 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/IntProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/IntProvenance.java @@ -48,20 +48,19 @@ public IntProvenance(String key, int value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Integer getValue() { + public Integer value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof IntProvenance)) return false; - IntProvenance that = (IntProvenance) o; + if (!(o instanceof IntProvenance that)) return false; return key.equals(that.key) && value == that.value; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/LongProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/LongProvenance.java index be79a142..7bda0075 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/LongProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/LongProvenance.java @@ -48,20 +48,19 @@ public LongProvenance(String key, long value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Long getValue() { + public Long value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof LongProvenance)) return false; - LongProvenance that = (LongProvenance) o; + if (!(o instanceof LongProvenance that)) return false; return key.equals(that.key) && value == that.value; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ShortProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ShortProvenance.java index a6e47b57..5017b2d0 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ShortProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/ShortProvenance.java @@ -48,20 +48,19 @@ public ShortProvenance(String key, short value) { } @Override - public String getKey() { + public String key() { return key; } @Override - public Short getValue() { + public Short value() { return value; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ShortProvenance)) return false; - ShortProvenance that = (ShortProvenance) o; + if (!(o instanceof ShortProvenance that)) return false; return key.equals(that.key) && value == that.value; } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/StringProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/StringProvenance.java index 8ac22fbb..3d862efe 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/StringProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/StringProvenance.java @@ -35,42 +35,9 @@ /** * A {@link PrimitiveProvenance} which records a String value. */ -public final class StringProvenance implements PrimitiveProvenance { +public record StringProvenance(String key, String value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final String key; - - private final String value; - - public StringProvenance(String key, String value) { - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return key; - } - - @Override - public String getValue() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof StringProvenance)) return false; - StringProvenance that = (StringProvenance) o; - return key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - @Override public String toString() { return value; diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/TimeProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/TimeProvenance.java index 56f2f97c..a3169756 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/TimeProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/TimeProvenance.java @@ -36,42 +36,9 @@ /** * A {@link PrimitiveProvenance} which records a time value with time zone offset. */ -public final class TimeProvenance implements PrimitiveProvenance { +public record TimeProvenance(String key, OffsetTime value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final String key; - - private final OffsetTime value; - - public TimeProvenance(String key, OffsetTime value) { - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return key; - } - - @Override - public OffsetTime getValue() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TimeProvenance)) return false; - TimeProvenance that = (TimeProvenance) o; - return key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - @Override public String toString() { return value.toString(); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/URLProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/URLProvenance.java index 2ce057c1..362aba4d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/URLProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/primitives/URLProvenance.java @@ -31,47 +31,13 @@ import com.oracle.labs.mlrg.olcut.provenance.PrimitiveProvenance; import java.net.URL; -import java.util.Objects; /** * A {@link PrimitiveProvenance} which records a resource location. */ -public final class URLProvenance implements PrimitiveProvenance { +public record URLProvenance(String key, URL value) implements PrimitiveProvenance { private static final long serialVersionUID = 1L; - private final String key; - - private final URL value; - - public URLProvenance(String key, URL value) { - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return key; - } - - @Override - public URL getValue() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof URLProvenance)) return false; - URLProvenance that = (URLProvenance) o; - return key.equals(that.key) && - value.equals(that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - @Override public String toString() { return value.toString(); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java index 5de556cb..edf887ca 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/util/Pair.java @@ -30,7 +30,6 @@ import java.io.Serializable; import java.util.ArrayList; -import java.util.Objects; import java.util.logging.Logger; /** @@ -40,42 +39,34 @@ * @param The type of the first object. * @param The type of the second object. */ -public class Pair implements Serializable { +public record Pair(T1 a, T2 b) implements Serializable { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(Pair.class.getName()); - - private final T1 a; - - private final T2 b; - - public Pair(T1 a, T2 b) { - this.a = a; - this.b = b; - } public T1 getA() { - return a; + return a(); } public T2 getB() { - return b; + return b(); } /** * Takes two arrays and zips them together into an array of Pairs. - * @param The type contained in the first array. - * @param The type contained in the second array. - * @param first An array of values. + * + * @param The type contained in the first array. + * @param The type contained in the second array. + * @param first An array of values. * @param second Another array of values. * @return The zipped array. */ - public static ArrayList> zipArrays(ArrayList first, ArrayList second) { + public static ArrayList> zipArrays(ArrayList first, ArrayList second) { if (first.size() == second.size()) { - ArrayList> output = new ArrayList<>(first.size()); + ArrayList> output = new ArrayList<>(first.size()); for (int i = 0; i < first.size(); i++) { - Pair pair = new Pair<>(first.get(i),second.get(i)); + Pair pair = new Pair<>(first.get(i), second.get(i)); output.add(i, pair); } @@ -84,7 +75,7 @@ public static ArrayList> zipArrays(ArrayList first, Arra throw new IllegalArgumentException("Zipping requires arrays of the same length. first.size() = " + first.size() + ", second.size() = " + second.size()); } } - + /** * Borrowed from java.util.SplittableRandom. Used to mix the integers in * hashcode. @@ -92,19 +83,20 @@ public static ArrayList> zipArrays(ArrayList first, Arra */ private static int mix32(long z) { z *= 0x62a9d9ed799705f5L; - return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32); + return (int) (((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32); } - + /** * Overridden hashcode. Checks to see if the types are ints or longs, and * runs them through the mixing function from java.util.SplittableRandom if * they are. Then XORs the two hashcodes together. + * * @return A 32-bit integer. */ @Override public int hashCode() { int aCode, bCode; - + if (a instanceof Integer) { aCode = mix32((Integer) a); } else if (a instanceof Long) { @@ -120,22 +112,8 @@ public int hashCode() { } else { bCode = b.hashCode(); } - - return aCode ^ bCode; - } - @Override - public boolean equals(Object obj) { - if(obj == null) { - return false; - } - if(!(obj instanceof Pair other)) { - return false; - } - if(!Objects.equals(this.a, other.a)) { - return false; - } - return Objects.equals(this.b, other.b); + return aCode ^ bCode; } @Override From bf133177b4b0d44387b18795e221abfb05c5a29f Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 22:58:24 -0500 Subject: [PATCH 6/8] ListProvenance and MapProvenance are now records. --- .../mlrg/olcut/provenance/ListProvenance.java | 40 +++----------- .../mlrg/olcut/provenance/MapProvenance.java | 55 ++++++------------- .../mlrg/olcut/provenance/ProvenanceUtil.java | 10 ++-- 3 files changed, 31 insertions(+), 74 deletions(-) diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java index 4bacad8a..f158cbe3 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ListProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -33,19 +33,17 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Objects; /** * Provenance for a list of provenance objects. */ -public final class ListProvenance implements Provenance, Iterable { +public record ListProvenance(List list) implements Provenance, Iterable { private static final long serialVersionUID = 1L; - private final List list; - /** * Creates a ListProvenance from the supplied list. The * list is defensively copied and immutable. + * * @param list The input list. */ public ListProvenance(List list) { @@ -55,17 +53,9 @@ public ListProvenance(List list) { /** * Creates an empty list provenance of the appropriate type. */ - public ListProvenance() { - this.list = Collections.emptyList(); - } - - /** - * An unmodifiable view on the provenance list. - * @return The provenance list. - */ - public List getList() { - return list; - } + public ListProvenance() { + this(Collections.emptyList()); + } @Override public Iterator iterator() { @@ -77,25 +67,13 @@ public String toString() { return list.toString(); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ListProvenance)) return false; - ListProvenance that = (ListProvenance) o; - return list.equals(that.list); - } - - @Override - public int hashCode() { - return Objects.hash(list); - } - /** * Creates a list provenance from a {@link Collection} of objects which * implement {@link Provenancable}. + * * @param collection The collection to extract provenance from. - * @param The type of the provenance. - * @param The provenancable type of the collection. + * @param The type of the provenance. + * @param The provenancable type of the collection. * @return A ListProvenance containing the provenances from the collection. */ public static > ListProvenance createListProvenance(Collection collection) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java index 48003302..65d3384d 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/MapProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -35,40 +35,30 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.Objects; /** * A Provenance which is a map from {@link String} to other {@link Provenance} * objects. */ -public final class MapProvenance implements Provenance, Iterable> { +public record MapProvenance(Map map) implements Provenance, Iterable> { private static final long serialVersionUID = 1L; - private final Map map; - /** * Creates a MapProvenance from a map. The map is defensively copied * and immutable. + * * @param map The map of provenances. */ - public MapProvenance(Map map) { + public MapProvenance(Map map) { this.map = Map.copyOf(map); } /** * Creates an empty MapProvenance. */ - public MapProvenance() { - this.map = Collections.emptyMap(); - } - - /** - * An unmodifiable view on the provenance map. - * @return The provenance map. - */ - public Map getMap() { - return map; - } + public MapProvenance() { + this(Collections.emptyMap()); + } @Override public Iterator> iterator() { @@ -80,28 +70,16 @@ public String toString() { return map.toString(); } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof MapProvenance)) return false; - MapProvenance that = (MapProvenance) o; - return map.equals(that.map); - } - - @Override - public int hashCode() { - return Objects.hash(map); - } - /** * Creates a map provenance from a map of {@link Provenancable} objects by calling {@link Provenancable#getProvenance()} * on each element. + * * @param map The map of provenancable objects. * @param The type of provenance emitted. * @param The provenancable type. * @return A MapProvenance. */ - public static > MapProvenance createMapProvenance(Map map) { + public static > MapProvenance createMapProvenance(Map map) { if (map == null || map.isEmpty()) { return new MapProvenance<>(); } else { @@ -117,28 +95,29 @@ public static > MapProvenance createMapProvenanceFromFloats(Map map) { + public static MapProvenance createMapProvenanceFromFloats(Map map) { if (map == null || map.isEmpty()) { return new MapProvenance<>(); } else { Map outputMap = new HashMap<>(); for (Map.Entry e : map.entrySet()) { - outputMap.put(e.getKey(), new FloatProvenance(e.getKey(),e.getValue())); + outputMap.put(e.getKey(), new FloatProvenance(e.getKey(), e.getValue())); } return new MapProvenance<>(outputMap); } } - private static class MapProvenanceIterator implements Iterator> { + private static class MapProvenanceIterator implements Iterator> { - private final Iterator> itr; + private final Iterator> itr; - public MapProvenanceIterator(Iterator> itr) { + public MapProvenanceIterator(Iterator> itr) { this.itr = itr; } @@ -149,8 +128,8 @@ public boolean hasNext() { @Override public Pair next() { - Map.Entry item = itr.next(); - return new Pair<>(item.getKey(),item.getValue()); + Map.Entry item = itr.next(); + return new Pair<>(item.getKey(), item.getValue()); } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java index 3d5cd196..9c3bc388 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java @@ -253,7 +253,7 @@ public static > List unwrap(ListProvenanc public static > Map unwrap(MapProvenance mapProvenance) { Map output = new HashMap<>(); - for (Map.Entry p : mapProvenance.getMap().entrySet()) { + for (Map.Entry p : mapProvenance.map().entrySet()) { output.put(p.getKey(),p.getValue().value()); } @@ -365,7 +365,7 @@ private static void formatProvenance(Provenance innerProv, StringBuilder builder switch (innerProv) { case PrimitiveProvenance primitiveProvenance -> builder.append(primitiveProvenance.value()); case ListProvenance listProv -> { - if (listProv.getList().isEmpty()) { + if (listProv.list().isEmpty()) { builder.append("List[]"); } else { builder.append("List[\n"); @@ -380,7 +380,7 @@ private static void formatProvenance(Provenance innerProv, StringBuilder builder } } case MapProvenance mapProv -> { - if (mapProv.getMap().isEmpty()) { + if (mapProv.map().isEmpty()) { builder.append("Map{}"); } else { builder.append("Map{\n"); @@ -437,7 +437,7 @@ private static Object innerConvertToMap(Provenance prov) { return String.valueOf(primitiveProvenance.value()); } case ListProvenance listProv -> { - if (listProv.getList().isEmpty()) { + if (listProv.list().isEmpty()) { return Collections.emptyList(); } else { List list = new ArrayList<>(); @@ -448,7 +448,7 @@ private static Object innerConvertToMap(Provenance prov) { } } case MapProvenance mapProv -> { - if (mapProv.getMap().isEmpty()) { + if (mapProv.map().isEmpty()) { return Collections.emptyMap(); } else { Map map = new HashMap<>(); From 7fc11799d278e31df1e83e72dca075efc2e7b0f7 Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Mon, 10 Feb 2025 23:08:45 -0500 Subject: [PATCH 7/8] Converting ObjectMarshalledProvenance and SimpleMarshalledProvenance into records. --- .../config/json/JsonProvenanceSerializer.java | 16 +-- .../ProtoProvenanceSerialization.java | 16 +-- .../mlrg/olcut/provenance/ProvenanceUtil.java | 10 +- .../io/ObjectMarshalledProvenance.java | 70 ++-------- .../io/SimpleMarshalledProvenance.java | 121 ++++-------------- .../io/XMLProvenanceSerialization.java | 20 +-- 6 files changed, 67 insertions(+), 186 deletions(-) diff --git a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java index 61ca5bff..844e03cd 100644 --- a/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java +++ b/olcut-config-json/src/main/java/com/oracle/labs/mlrg/olcut/config/json/JsonProvenanceSerializer.java @@ -72,20 +72,20 @@ public void serialize(MarshalledProvenance marshalledProvenance, JsonGenerator j jsonGenerator.writeEndObject(); } case ObjectMarshalledProvenance omp -> { - jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_NAME, omp.getName()); - jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_CLASS_NAME, omp.getObjectClassName()); - jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS, omp.getProvenanceClassName()); + jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_NAME, omp.objectName()); + jsonGenerator.writeStringField(JsonProvenanceModule.OBJECT_CLASS_NAME, omp.objectClassName()); + jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS, omp.provenanceClassName()); jsonGenerator.writeObjectFieldStart(JsonProvenanceModule.MAP); - for (Map.Entry e : omp.getMap().entrySet()) { + for (Map.Entry e : omp.map().entrySet()) { jsonGenerator.writeObjectField(e.getKey(), e.getValue()); } jsonGenerator.writeEndObject(); } case SimpleMarshalledProvenance smp -> { - jsonGenerator.writeStringField(JsonProvenanceModule.KEY, smp.getKey()); - jsonGenerator.writeStringField(JsonProvenanceModule.VALUE, smp.getValue()); - jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS, smp.getProvenanceClassName()); - jsonGenerator.writeStringField(JsonProvenanceModule.ADDITIONAL, smp.getAdditional()); + jsonGenerator.writeStringField(JsonProvenanceModule.KEY, smp.key()); + jsonGenerator.writeStringField(JsonProvenanceModule.VALUE, smp.value()); + jsonGenerator.writeStringField(JsonProvenanceModule.PROVENANCE_CLASS, smp.provenanceClassName()); + jsonGenerator.writeStringField(JsonProvenanceModule.ADDITIONAL, smp.additional()); jsonGenerator.writeBooleanField(JsonProvenanceModule.IS_REFERENCE, smp.isReference()); } default -> throw new IOException("Unexpected provenance class, found " + provClass.getName()); diff --git a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java index bc0a9753..835b7644 100644 --- a/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java +++ b/olcut-config-protobuf/src/main/java/com/oracle/labs/mlrg/olcut/config/protobuf/ProtoProvenanceSerialization.java @@ -267,11 +267,11 @@ private static void convertProvenance(RootProvenanceProto.Builder builder, Mutab ompBuilder.setIndex(counter.intValue()); counter.increment(); - ompBuilder.setObjectName(omp.getName()); - ompBuilder.setObjectClassName(omp.getObjectClassName()); - ompBuilder.setProvenanceClassName(omp.getProvenanceClassName()); + ompBuilder.setObjectName(omp.objectName()); + ompBuilder.setObjectClassName(omp.objectClassName()); + ompBuilder.setProvenanceClassName(omp.provenanceClassName()); - for (Map.Entry e : omp.getMap().entrySet()) { + for (Map.Entry e : omp.map().entrySet()) { int count = dispatchFMP(builder, counter, e.getValue()); ompBuilder.putValues(e.getKey(),count); } @@ -307,10 +307,10 @@ private static int encodeSMP(RootProvenanceProto.Builder builder, MutableLong co smpBuilder.setIndex(curIndex); counter.increment(); - smpBuilder.setKey(smp.getKey()); - smpBuilder.setValue(smp.getValue()); - smpBuilder.setAdditional(smp.getAdditional()); - smpBuilder.setProvenanceClassName(smp.getProvenanceClassName()); + smpBuilder.setKey(smp.key()); + smpBuilder.setValue(smp.value()); + smpBuilder.setAdditional(smp.additional()); + smpBuilder.setProvenanceClassName(smp.provenanceClassName()); smpBuilder.setIsReference(smp.isReference()); builder.addSmp(smpBuilder.build()); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java index 9c3bc388..56b6ce0a 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/ProvenanceUtil.java @@ -766,7 +766,7 @@ public static ObjectProvenance unmarshalProvenance(List marshalledObjects = new HashMap<>(); for (ObjectMarshalledProvenance o : marshalledProvenance) { - marshalledObjects.put(o.getName(),o); + marshalledObjects.put(o.objectName(),o); } return unmarshalProvenance(marshalledProvenance.getFirst(), unmarshalledObjects, marshalledObjects); @@ -782,7 +782,7 @@ public static ObjectProvenance unmarshalProvenance(List unmarshalledObjects, Map marshalledObjects) throws ProvenanceException { - String provenanceClassName = curProv.getProvenanceClassName(); + String provenanceClassName = curProv.provenanceClassName(); try { Class provenanceClass = Class.forName(provenanceClassName); @@ -791,8 +791,8 @@ private static ObjectProvenance unmarshalProvenance(ObjectMarshalledProvenance c } Map arguments = new HashMap<>(); - for (Map.Entry e : curProv.getMap().entrySet()) { - Provenance extractedProv = unmarshalFlat(curProv.getName(),e.getValue(),unmarshalledObjects,marshalledObjects); + for (Map.Entry e : curProv.map().entrySet()) { + Provenance extractedProv = unmarshalFlat(curProv.objectName(),e.getValue(),unmarshalledObjects,marshalledObjects); arguments.put(e.getKey(),extractedProv); } @@ -828,7 +828,7 @@ private static Provenance unmarshalFlat(String hostProvName, FlatMarshalledProve switch (fmp) { case SimpleMarshalledProvenance smp -> { if (smp.isReference()) { - String refName = smp.getValue(); + String refName = smp.value(); if (unmarshalledObjects.containsKey(refName)) { return unmarshalledObjects.get(refName); } else if (marshalledObjects.containsKey(refName)) { diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java index 37dfaa05..7120edde 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/ObjectMarshalledProvenance.java @@ -29,7 +29,6 @@ package com.oracle.labs.mlrg.olcut.provenance.io; import java.util.Map; -import java.util.Objects; /** * A marshalled provenance representing an @@ -37,22 +36,20 @@ *

* Contains the name of the object, the class name of the provenance's host object, * and the class name of the provenance object. + * @param objectName The name of the object in the provenance stream. + * @param map The object's fields. + * @param objectClassName The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.Provenancable} object. + * @param provenanceClassName The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.ObjectProvenance} subclass. */ -public final class ObjectMarshalledProvenance implements MarshalledProvenance { - - private final Map map; - - private final String objectName; - - private final String objectClassName; - - private final String provenanceClassName; +public record ObjectMarshalledProvenance(String objectName, Map map, + String objectClassName, String provenanceClassName) implements MarshalledProvenance { /** * Constructs an ObjectMarshalledProvenance. - * @param objectName The name of the object in the provenance stream. - * @param map The object's fields. - * @param objectClassName The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.Provenancable} object. + * + * @param objectName The name of the object in the provenance stream. + * @param map The object's fields. + * @param objectClassName The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.Provenancable} object. * @param provenanceClassName The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.ObjectProvenance} subclass. */ public ObjectMarshalledProvenance(String objectName, Map map, String objectClassName, String provenanceClassName) { @@ -62,38 +59,6 @@ public ObjectMarshalledProvenance(String objectName, Map getMap() { - return map; - } - - /** - * The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.Provenancable} object. - * @return The creator class of the provenance. - */ - public String getObjectClassName() { - return objectClassName; - } - - /** - * The class name of the {@link com.oracle.labs.mlrg.olcut.provenance.ObjectProvenance} subclass. - * @return The provenance class name. - */ - public String getProvenanceClassName() { - return provenanceClassName; - } - @Override public String toString() { return "ObjectMarshalledProvenance{" + @@ -103,19 +68,4 @@ public String toString() { ", provenanceClassName='" + provenanceClassName + '\'' + '}'; } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ObjectMarshalledProvenance that)) return false; - return map.equals(that.map) && - objectName.equals(that.objectName) && - objectClassName.equals(that.objectClassName) && - provenanceClassName.equals(that.provenanceClassName); - } - - @Override - public int hashCode() { - return Objects.hash(map, objectName, objectClassName, provenanceClassName); - } } diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java index 5f95791b..86325823 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/SimpleMarshalledProvenance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * * Licensed under the 2-clause BSD license. * @@ -64,18 +64,16 @@ * If the {@link PrimitiveProvenance} requires extra information beyond it's * key and value, this class must be updated to have a specific constructor * for that type. + *

+ * The canonical constructor is used for deserialization, code uses should use one of the more specific constructors. + * @param key The key. + * @param value The value of this provenance. + * @param provenanceClassName The class name of the provenance. + * @param isReference Is this object a reference to another provenance in the stream. + * @param additional Any additional information like hash type or enum class. */ -public final class SimpleMarshalledProvenance implements FlatMarshalledProvenance { - - private final String key; - - private final String value; - - private final String additional; - - private final String provenanceClassName; - - private final boolean isReference; +public record SimpleMarshalledProvenance(String key, String value, String provenanceClassName, boolean isReference, + String additional) implements FlatMarshalledProvenance { /** * Constructs a SimpleMarshalledProvenance from an enum provenance, @@ -117,22 +115,6 @@ public SimpleMarshalledProvenance(String key, String value, ObjectProvenance pro this(key, value, provenance.getClass().getName(), true, ""); } - /** - * Used for deserialisation. - * @param key The key. - * @param value The value of this provenance. - * @param provenanceClassName The class name of the provenance. - * @param isReference Is this object a reference to another provenance in the stream. - * @param additional Any additional information like hash type or enum class. - */ - public SimpleMarshalledProvenance(String key, String value, String provenanceClassName, boolean isReference, String additional) { - this.key = key; - this.value = value; - this.provenanceClassName = provenanceClassName; - this.isReference = isReference; - this.additional = additional; - } - @Override public String toString() { return "SimpleMarshalledProvenance{" + @@ -147,10 +129,11 @@ public String toString() { /** * Only unmarshalls the Provenance if it's a PrimitiveProvenance, * throws ProvenanceException if it stores a reference to an ObjectProvenance. + * * @param The type of the PrimitiveProvenance. * @return A PrimitiveProvenance instance. */ - @SuppressWarnings({"unchecked","rawtypes"})//Suppressing enum casting warnings. + @SuppressWarnings({"unchecked", "rawtypes"})//Suppressing enum casting warnings. public PrimitiveProvenance unmarshallPrimitive() { if (isReference) { throw new ProvenanceException("Attempted to unmarshall a reference via 'unmarshallPrimitive'"); @@ -160,39 +143,39 @@ public PrimitiveProvenance unmarshallPrimitive() { PrimitiveProvenance unmarshalled; if (provClass.equals(BooleanProvenance.class)) { - unmarshalled = new BooleanProvenance(key,Boolean.parseBoolean(value)); + unmarshalled = new BooleanProvenance(key, Boolean.parseBoolean(value)); } else if (provClass.equals(ByteProvenance.class)) { - unmarshalled = new ByteProvenance(key,Byte.parseByte(value)); + unmarshalled = new ByteProvenance(key, Byte.parseByte(value)); } else if (provClass.equals(CharProvenance.class)) { - unmarshalled = new CharProvenance(key,value.charAt(0)); + unmarshalled = new CharProvenance(key, value.charAt(0)); } else if (provClass.equals(DateProvenance.class)) { unmarshalled = new DateProvenance(key, LocalDate.parse(value)); } else if (provClass.equals(DateTimeProvenance.class)) { unmarshalled = new DateTimeProvenance(key, OffsetDateTime.parse(value)); } else if (provClass.equals(DoubleProvenance.class)) { - unmarshalled = new DoubleProvenance(key,Double.parseDouble(value)); + unmarshalled = new DoubleProvenance(key, Double.parseDouble(value)); } else if (provClass.equals(EnumProvenance.class)) { Class enumClass = (Class) Class.forName(additional); - Enum enumValue = Enum.valueOf(enumClass,value); - unmarshalled = new EnumProvenance<>(key,enumValue); + Enum enumValue = Enum.valueOf(enumClass, value); + unmarshalled = new EnumProvenance<>(key, enumValue); } else if (provClass.equals(FileProvenance.class)) { - unmarshalled = new FileProvenance(key,new File(value)); + unmarshalled = new FileProvenance(key, new File(value)); } else if (provClass.equals(FloatProvenance.class)) { - unmarshalled = new FloatProvenance(key,Float.parseFloat(value)); + unmarshalled = new FloatProvenance(key, Float.parseFloat(value)); } else if (provClass.equals(HashProvenance.class)) { - unmarshalled = new HashProvenance(HashType.valueOf(additional),key,value); + unmarshalled = new HashProvenance(HashType.valueOf(additional), key, value); } else if (provClass.equals(IntProvenance.class)) { - unmarshalled = new IntProvenance(key,Integer.parseInt(value)); + unmarshalled = new IntProvenance(key, Integer.parseInt(value)); } else if (provClass.equals(LongProvenance.class)) { - unmarshalled = new LongProvenance(key,Long.parseLong(value)); + unmarshalled = new LongProvenance(key, Long.parseLong(value)); } else if (provClass.equals(ShortProvenance.class)) { - unmarshalled = new ShortProvenance(key,Short.parseShort(value)); + unmarshalled = new ShortProvenance(key, Short.parseShort(value)); } else if (provClass.equals(StringProvenance.class)) { - unmarshalled = new StringProvenance(key,value); + unmarshalled = new StringProvenance(key, value); } else if (provClass.equals(TimeProvenance.class)) { unmarshalled = new TimeProvenance(key, OffsetTime.parse(value)); } else if (provClass.equals(URLProvenance.class)) { - unmarshalled = new URLProvenance(key,new URL(value)); + unmarshalled = new URLProvenance(key, new URL(value)); } else { throw new ProvenanceException("Unknown Provenance subclass, found " + provClass.getName()); } @@ -208,58 +191,6 @@ public PrimitiveProvenance unmarshallPrimitive() { } } - /** - * Is this a reference rather than a primitive type. - * @return true if it's a reference to an {@link ObjectMarshalledProvenance}. - */ - public boolean isReference() { - return isReference; - } - - /** - * The field name where this provenance was extracted. - * @return The field name. - */ - public String getKey() { - return key; - } - - /** - * The value of this provenance. - * @return the String representation of the value. - */ - public String getValue() { - return value; - } - - /** - * The name of the provenance class. - * @return The provenance class name. - */ - public String getProvenanceClassName() { - return provenanceClassName; - } - - /** - * Any additional information necessary beyond the key and value, - * e.g., the hash type. - * @return Any additional information necessary to encode the provenance. - */ - public String getAdditional() { - return additional; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SimpleMarshalledProvenance)) return false; - SimpleMarshalledProvenance that = (SimpleMarshalledProvenance) o; - return isReference == that.isReference && - key.equals(that.key) && - value.equals(that.value) && - provenanceClassName.equals(that.provenanceClassName); - } - @Override public int hashCode() { return Objects.hash(key, value, provenanceClassName); diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java index a6aabeac..91d18917 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/io/XMLProvenanceSerialization.java @@ -234,7 +234,7 @@ private void writeProvenance(XMLStreamWriter writer, List provMap = omp.getMap(); + Map provMap = omp.map(); if (prettyPrint) { writer.writeCharacters("\t"); } @@ -243,9 +243,9 @@ private void writeOMP(XMLStreamWriter writer, ObjectMarshalledProvenance omp) th } else { writer.writeEmptyElement(OBJECT_MARSHALLED_PROVENANCE); } - writer.writeAttribute(OBJECT_NAME, omp.getName()); - writer.writeAttribute(OBJECT_CLASS_NAME, omp.getObjectClassName()); - writer.writeAttribute(PROVENANCE_CLASS_NAME, omp.getProvenanceClassName()); + writer.writeAttribute(OBJECT_NAME, omp.objectName()); + writer.writeAttribute(OBJECT_CLASS_NAME, omp.objectClassName()); + writer.writeAttribute(PROVENANCE_CLASS_NAME, omp.provenanceClassName()); if (!provMap.isEmpty()) { if (prettyPrint) { writer.writeCharacters(System.lineSeparator()); @@ -278,10 +278,10 @@ private void writeSMP(XMLStreamWriter writer, SimpleMarshalledProvenance smp, in } } writer.writeEmptyElement(SIMPLE_MARSHALLED_PROVENANCE); - writer.writeAttribute(PROV_KEY, smp.getKey()); - writer.writeAttribute(PROV_VALUE, smp.getValue()); - writer.writeAttribute(PROV_ADDITIONAL, smp.getAdditional()); - writer.writeAttribute(PROVENANCE_CLASS_NAME, smp.getProvenanceClassName()); + writer.writeAttribute(PROV_KEY, smp.key()); + writer.writeAttribute(PROV_VALUE, smp.value()); + writer.writeAttribute(PROV_ADDITIONAL, smp.additional()); + writer.writeAttribute(PROVENANCE_CLASS_NAME, smp.provenanceClassName()); writer.writeAttribute(IS_REFERENCE, "" + smp.isReference()); if (prettyPrint) { writer.writeCharacters(System.lineSeparator()); @@ -492,11 +492,11 @@ public void endElement(String uri, String localName, String qName) if (curSMP != null) { if (provenanceChain.isEmpty()) { // Must be writing to the current ObjectMarshalledProvenance - ompProvMap.put(curSMP.getKey(),curSMP); + ompProvMap.put(curSMP.key(),curSMP); } else { ProvCollection pc = provenanceChain.peekLast(); if (pc.isMap()) { - pc.addProvenance(curSMP.getKey(),curSMP); + pc.addProvenance(curSMP.key(),curSMP); } else { pc.addProvenance(curSMP); } From 2135fe0b21c3a6efd181e3530ab730b4b4b67577 Mon Sep 17 00:00:00 2001 From: Adam Pocock Date: Sun, 1 Mar 2026 23:32:48 -0500 Subject: [PATCH 8/8] Suppress a warning when constructing an enum provenance which is checked elsewhere. --- .../provenance/impl/SkeletalConfiguredObjectProvenance.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java index ddc3e7dc..875db229 100644 --- a/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java +++ b/olcut-core/src/main/java/com/oracle/labs/mlrg/olcut/provenance/impl/SkeletalConfiguredObjectProvenance.java @@ -523,7 +523,9 @@ private static Optional convertPrimitive(FieldType ft, Class fiel if (o == null) { return Optional.empty(); } else { - return Optional.of(new EnumProvenance<>(fieldName, (Enum) o)); + @SuppressWarnings({"rawtypes","unchecked"}) + var e = new EnumProvenance<>(fieldName, (Enum) o); + return Optional.of(e); } case CONFIGURABLE: if (o == null) {