diff options
Diffstat (limited to 'utils/src/main/java/org/onap/policy')
34 files changed, 1717 insertions, 426 deletions
diff --git a/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java new file mode 100644 index 00000000..970cebfe --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineArgumentsHandler.java @@ -0,0 +1,273 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.cmd; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.lang3.StringUtils; +import org.onap.policy.common.utils.resources.ResourceUtils; + +/** + * Class for command line common processing. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +public class CommandLineArgumentsHandler { + private static final String FILE_MESSAGE_PREAMBLE = " file \""; + private static final int HELP_LINE_LENGTH = 120; + + private final Options options; + + private final String helpClassName; + private final String component; + + @Getter + @Setter + private String configurationFilePath = null; + + @Getter + @Setter + private String propertyFilePath = null; + + @Getter + private CommandLine commandLine = null; + + /** + * Construct the options with default values for the CLI editor. + */ + protected CommandLineArgumentsHandler(String helpClassName, String component) { + this.helpClassName = helpClassName; + this.component = component; + //@formatter:off + options = new Options(); + options.addOption(Option.builder("h") + .longOpt("help") + .desc("outputs the usage of this command") + .required(false) + .type(Boolean.class) + .build()); + options.addOption(Option.builder("v") + .longOpt("version") + .desc("outputs the version of " + this.component) + .required(false) + .type(Boolean.class) + .build()); + options.addOption(Option.builder("c") + .longOpt("config-file") + .desc(String.format("the full path to the configuration file to use, " + + "the configuration file must be a Json file containing the %s parameters", this.component)) + .hasArg().argName("CONFIG_FILE") + .required(false) + .type(String.class) + .build()); + //@formatter:on + } + + /** + * Construct the options for the CLI editor with extra options. + */ + public CommandLineArgumentsHandler(String helpClassName, String component, Option... customOptions) { + this(helpClassName, component); + if (customOptions != null) { + for (Option option : customOptions) { + options.addOption(option); + } + } + } + + /** + * Construct the options with brand-new options for the CLI editor. + */ + public CommandLineArgumentsHandler(String helpClassName, String component, Options options) { + this.options = options; + this.helpClassName = helpClassName; + this.component = component; + } + + /** + * Parse the command line options. + * + * @param args The command line arguments + * @return a string with a message for help and version, or null if there is no message + * @throws CommandLineException on command argument errors + */ + public String parse(final String[] args) throws CommandLineException { + // Clear all our arguments + setConfigurationFilePath(null); + setPropertyFilePath(null); + + try { + commandLine = new DefaultParser().parse(options, args); + } catch (final ParseException | NullPointerException e) { + throw new CommandLineException("invalid command line arguments specified", e); + } + + // Arguments left over after Commons CLI does its stuff + final String[] remainingArgs = removeEmptyValues(commandLine.getArgs()); + + if (remainingArgs.length > 0) { + throw new CommandLineException("too many command line arguments specified: " + Arrays.toString(args)); + } + + if (commandLine.hasOption('h')) { + return help(); + } + + if (commandLine.hasOption('v')) { + return version(); + } + + if (commandLine.hasOption('c')) { + setConfigurationFilePath(commandLine.getOptionValue('c')); + } + + if (commandLine.hasOption('p')) { + setPropertyFilePath(commandLine.getOptionValue('p')); + } + + return null; + } + + /** + * Validate the command line options. + * + * @throws CommandLineException on command argument validation errors + */ + public void validate() throws CommandLineException { + validateReadableFile(this.component + " configuration", configurationFilePath); + } + + /** + * Print version information for policy distribution. + * + * @return the version string + */ + public String version() { + return ResourceUtils.getResourceAsString("version.txt"); + } + + /** + * Print help information for policy distribution. + * + * @return the help string + */ + public String help() { + final var helpFormatter = new HelpFormatter(); + final var stringWriter = new StringWriter(); + final var printWriter = new PrintWriter(stringWriter); + final String cmdLineSyntax = this.helpClassName + " [options...]"; + + helpFormatter.printHelp(printWriter, HELP_LINE_LENGTH, cmdLineSyntax, "options", options, 0, 0, ""); + + return stringWriter.toString(); + } + + /** + * Gets the full expanded configuration file path. + * + * @return the configuration file path + */ + public String getFullConfigurationFilePath() { + return ResourceUtils.getFilePath4Resource(getConfigurationFilePath()); + } + + /** + * Check set configuration file path. + * + * @return true, if check set configuration file path + */ + public boolean checkSetConfigurationFilePath() { + return StringUtils.isNotBlank(getConfigurationFilePath()); + } + + /** + * Gets the full expanded property file path. + * + * @return the property file path + */ + public String getFullPropertyFilePath() { + return ResourceUtils.getFilePath4Resource(getPropertyFilePath()); + } + + /** + * Check set property file path. + * + * @return true, if check set property file path + */ + public boolean checkSetPropertyFilePath() { + return StringUtils.isNotBlank(getPropertyFilePath()); + } + + /** + * Validate readable file. + * + * @param fileTag the file tag + * @param fileName the file name + * @throws CommandLineException on the file name passed as a parameter + */ + protected void validateReadableFile(final String fileTag, final String fileName) throws CommandLineException { + if (StringUtils.isBlank(fileName)) { + throw new CommandLineException(fileTag + " file was not specified as an argument"); + } + + // The file name refers to a resource on the local file system + final var fileUrl = ResourceUtils.getUrl4Resource(fileName); + if (fileUrl == null) { + throw new CommandLineException(fileTag + FILE_MESSAGE_PREAMBLE + fileName + "\" does not exist"); + } + + try { + var path = Path.of(fileUrl.toURI()); + if (!Files.isRegularFile(path)) { + throw new CommandLineException(fileTag + FILE_MESSAGE_PREAMBLE + fileName + "\" is not a normal file"); + } + if (!Files.isReadable(path)) { + throw new CommandLineException(fileTag + FILE_MESSAGE_PREAMBLE + fileName + "\" is unreadable"); + } + } catch (URISyntaxException e) { + throw new CommandLineException("Error parsing " + fileUrl.toString(), e); + } + + } + + /** + * Checks if args has any null or empty value after parsing. + * + * @param args remaining args from CLI parse. + */ + private String[] removeEmptyValues(String[] args) { + return Arrays.stream(args).filter(StringUtils::isNotBlank).toArray(String[]::new); + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java new file mode 100644 index 00000000..9cdf3d37 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/cmd/CommandLineException.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.cmd; + +import java.io.Serial; + +/** + * Exception used for CommandLineArguments class. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +public class CommandLineException extends Exception { + + /** + * Generated serialVersionUID. + */ + @Serial + private static final long serialVersionUID = -1200607308084606425L; + + /** + * Instantiates a new exception with a message. + * + * @param message the message + */ + public CommandLineException(final String message) { + super(message); + } + + /** + * Instantiates a new exception with a message and a caused by exception. + * + * @param message the message + * @param exp the exception that caused this exception to be thrown + */ + public CommandLineException(final String message, final Exception exp) { + super(message, exp); + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java index bb51f2b9..3049a5c2 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java @@ -1,8 +1,8 @@ /* * ============LICENSE_START======================================================= - * ONAP PAP + * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,37 @@ import java.io.Writer; public interface Coder { /** + * Converts an object/POJO to an object of the given type. + * + * @param <T> desired type + * @param source source object + * @param clazz class of the desired object type + * @return the converted object + * @throws CoderException if an error occurs + */ + default <S, T> T convert(S source, Class<T> clazz) throws CoderException { + if (source == null) { + return null; + + } else if (clazz == source.getClass()) { + // same class - just cast it + return clazz.cast(source); + + } else if (clazz == String.class) { + // target is a string - just encode the source + return (clazz.cast(encode(source))); + + } else if (source.getClass() == String.class) { + // source is a string - just decode it + return decode(source.toString(), clazz); + + } else { + // do it the long way: encode to a string and then decode the string + return decode(encode(source), clazz); + } + } + + /** * Encodes an object into json. * * @param object object to be encoded @@ -41,6 +72,17 @@ public interface Coder { String encode(Object object) throws CoderException; /** + * Encodes an object into json, optionally making it "pretty". + * + * @param object object to be encoded + * @param pretty {@code true} if it should be encoded as "pretty" json, {@code false} + * otherwise + * @return a json string representing the object + * @throws CoderException if an error occurs + */ + String encode(Object object, boolean pretty) throws CoderException; + + /** * Encodes an object into json, writing to the given target. * * @param target target to which to write the encoded json diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java index 3036d353..daacf479 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,12 +55,12 @@ public class PropertyCoder { * @return a class T object */ public <T> T decode(String json, String keyProperty, Class<T> clazz) { - JsonElement jsonElement = GSON.fromJson(json, JsonElement.class); + var jsonElement = GSON.fromJson(json, JsonElement.class); return new MyDecoder(jsonElement, keyProperty).decrypt(jsonElement, clazz); } public <T> T decode(Reader reader, String keyProperty, Class<T> clazz) { - JsonElement jsonElement = GSON.fromJson(reader, JsonElement.class); + var jsonElement = GSON.fromJson(reader, JsonElement.class); return new MyDecoder(jsonElement, keyProperty).decrypt(jsonElement, clazz); } @@ -71,9 +71,9 @@ public class PropertyCoder { if (!jsonElement.isJsonObject()) { return; } - JsonObject jsonObject = jsonElement.getAsJsonObject(); + var jsonObject = jsonElement.getAsJsonObject(); // Use keyProperty from input to retrieve secretKey - String secretKey = jsonObject.get(keyProperty).getAsString(); + var secretKey = jsonObject.get(keyProperty).getAsString(); if (!StringUtils.isBlank(secretKey)) { crypto = new CryptoUtils(secretKey); } @@ -97,7 +97,7 @@ public class PropertyCoder { if (!jsonElement.getAsJsonPrimitive().isString()) { return jsonElement; } - String value = jsonElement.getAsString(); + var value = jsonElement.getAsString(); if (!value.startsWith("enc:")) { return jsonElement; } @@ -111,7 +111,7 @@ public class PropertyCoder { if (crypto == null) { return jsonArray; } - JsonArray newArray = new JsonArray(); + var newArray = new JsonArray(); for (JsonElement element: jsonArray) { newArray.add(decrypt(element)); } @@ -122,14 +122,14 @@ public class PropertyCoder { if (crypto == null) { return jsonObject; } - JsonObject newObject = new JsonObject(); + var newObject = new JsonObject(); Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet(); for (Map.Entry<String, JsonElement> entry : entrySet) { String key = entry.getKey(); - JsonElement jsonElement = decrypt(entry.getValue()); + var jsonElement = decrypt(entry.getValue()); newObject.add(key, jsonElement); } return newObject; } } -}
\ No newline at end of file +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java index e84a92f2..d6135afd 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java @@ -1,8 +1,8 @@ /* * ============LICENSE_START======================================================= - * ONAP PAP + * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,35 +38,101 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; import lombok.AccessLevel; -import lombok.Getter; +import lombok.AllArgsConstructor; import org.onap.policy.common.gson.DoubleConverter; import org.onap.policy.common.gson.GsonMessageBodyHandler; /** * JSON encoder and decoder using the "standard" mechanism, which is currently gson. */ +@AllArgsConstructor(access = AccessLevel.PROTECTED) public class StandardCoder implements Coder { /** * Gson object used to encode and decode messages. */ - @Getter(AccessLevel.PROTECTED) - private static final Gson GSON = GsonMessageBodyHandler.configBuilder( - new GsonBuilder().registerTypeAdapter(StandardCoderObject.class, new StandardTypeAdapter())) - .create(); + private static final Gson GSON_STD; + + /** + * Gson object used to encode messages in "pretty" format. + */ + private static final Gson GSON_STD_PRETTY; + + static { + GsonBuilder builder = GsonMessageBodyHandler.configBuilder( + new GsonBuilder().registerTypeAdapter(StandardCoderObject.class, new StandardTypeAdapter())); + + GSON_STD = builder.create(); + GSON_STD_PRETTY = builder.setPrettyPrinting().create(); + } + + /** + * Gson object used to encode and decode messages. + */ + protected final Gson gson; + + /** + * Gson object used to encode messages in "pretty" format. + */ + protected final Gson gsonPretty; /** * Constructs the object. */ public StandardCoder() { - super(); + this(GSON_STD, GSON_STD_PRETTY); + } + + @Override + public <S, T> T convert(S source, Class<T> clazz) throws CoderException { + if (source == null) { + return null; + + } else if (clazz == source.getClass()) { + // same class - just cast it + return clazz.cast(source); + + } else if (clazz == String.class) { + // target is a string - just encode the source + return (clazz.cast(encode(source))); + + } else if (source.getClass() == String.class) { + // source is a string - just decode it + return decode(source.toString(), clazz); + + } else { + /* + * Do it the long way: encode to a tree and then decode the tree. This entire + * method could have been left out and the default Coder.convert() used + * instead, but this should perform slightly better as it only uses a + * JsonElement as the intermediate data structure, while Coder.convert() goes + * all the way to a String as the intermediate data structure. + */ + try { + return fromJson(toJsonTree(source), clazz); + } catch (RuntimeException e) { + throw new CoderException(e); + } + } } @Override public String encode(Object object) throws CoderException { + return encode(object, false); + } + + @Override + public String encode(Object object, boolean pretty) throws CoderException { try { - return toJson(object); + if (pretty) { + return toPrettyJson(object); + + } else { + return toJson(object); + } } catch (RuntimeException e) { throw new CoderException(e); @@ -78,7 +144,7 @@ public class StandardCoder implements Coder { try { toJson(target, object); - } catch (RuntimeException | IOException e) { + } catch (RuntimeException e) { throw new CoderException(e); } } @@ -86,7 +152,7 @@ public class StandardCoder implements Coder { @Override public void encode(OutputStream target, Object object) throws CoderException { try { - Writer wtr = makeWriter(target); + var wtr = makeWriter(target); toJson(wtr, object); // flush, but don't close @@ -99,7 +165,7 @@ public class StandardCoder implements Coder { @Override public void encode(File target, Object object) throws CoderException { - try (Writer wtr = makeWriter(target)) { + try (var wtr = makeWriter(target)) { toJson(wtr, object); // no need to flush or close here @@ -141,7 +207,7 @@ public class StandardCoder implements Coder { @Override public <T> T decode(File source, Class<T> clazz) throws CoderException { - try (Reader input = makeReader(source)) { + try (var input = makeReader(source)) { return fromJson(input, clazz); } catch (RuntimeException | IOException e) { @@ -149,10 +215,20 @@ public class StandardCoder implements Coder { } } + /** + * Encodes the object as "pretty" json. + * + * @param object object to be encoded + * @return the encoded object + */ + protected String toPrettyJson(Object object) { + return gsonPretty.toJson(object); + } + @Override public StandardCoderObject toStandard(Object object) throws CoderException { try { - return new StandardCoderObject(GSON.toJsonTree(object)); + return new StandardCoderObject(gson.toJsonTree(object)); } catch (RuntimeException e) { throw new CoderException(e); @@ -162,7 +238,7 @@ public class StandardCoder implements Coder { @Override public <T> T fromStandard(StandardCoderObject sco, Class<T> clazz) throws CoderException { try { - return GSON.fromJson(sco.getData(), clazz); + return gson.fromJson(sco.getData(), clazz); } catch (RuntimeException e) { throw new CoderException(e); @@ -220,7 +296,7 @@ public class StandardCoder implements Coder { * @return a json element representing the object */ protected JsonElement toJsonTree(Object object) { - return GSON.toJsonTree(object); + return gson.toJsonTree(object); } /** @@ -230,7 +306,7 @@ public class StandardCoder implements Coder { * @return a json string representing the object */ protected String toJson(Object object) { - return GSON.toJson(object); + return gson.toJson(object); } /** @@ -238,10 +314,9 @@ public class StandardCoder implements Coder { * * @param target target to which to write the encoded json * @param object object to be encoded - * @throws IOException if an I/O error occurs */ - protected void toJson(Writer target, Object object) throws IOException { - GSON.toJson(object, object.getClass(), target); + protected void toJson(Writer target, Object object) { + gson.toJson(object, object.getClass(), target); } /** @@ -252,7 +327,7 @@ public class StandardCoder implements Coder { * @return the object represented by the given json element */ protected <T> T fromJson(JsonElement json, Class<T> clazz) { - return convertFromDouble(clazz, GSON.fromJson(json, clazz)); + return convertFromDouble(clazz, gson.fromJson(json, clazz)); } /** @@ -263,7 +338,7 @@ public class StandardCoder implements Coder { * @return the object represented by the given json string */ protected <T> T fromJson(String json, Class<T> clazz) { - return convertFromDouble(clazz, GSON.fromJson(json, clazz)); + return convertFromDouble(clazz, gson.fromJson(json, clazz)); } /** @@ -274,7 +349,7 @@ public class StandardCoder implements Coder { * @return the object represented by the given json string */ protected <T> T fromJson(Reader source, Class<T> clazz) { - return convertFromDouble(clazz, GSON.fromJson(source, clazz)); + return convertFromDouble(clazz, gson.fromJson(source, clazz)); } /** @@ -286,8 +361,8 @@ public class StandardCoder implements Coder { * @param value value to be converted * @return the converted value */ - private <T> T convertFromDouble(Class<T> clazz, T value) { - if (clazz != Object.class) { + protected <T> T convertFromDouble(Class<T> clazz, T value) { + if (clazz != Object.class && !Map.class.isAssignableFrom(clazz) && !List.class.isAssignableFrom(clazz)) { return value; } @@ -297,20 +372,14 @@ public class StandardCoder implements Coder { /** * Adapter for standard objects. */ - private static class StandardTypeAdapter extends TypeAdapter<StandardCoderObject> { + @AllArgsConstructor + protected static class StandardTypeAdapter extends TypeAdapter<StandardCoderObject> { /** * Used to read/write a JsonElement. */ private static TypeAdapter<JsonElement> elementAdapter = new Gson().getAdapter(JsonElement.class); - /** - * Constructs the object. - */ - public StandardTypeAdapter() { - super(); - } - @Override public void write(JsonWriter out, StandardCoderObject value) throws IOException { elementAdapter.write(out, value.getData()); diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderInstantAsMillis.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderInstantAsMillis.java new file mode 100644 index 00000000..27b239bb --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderInstantAsMillis.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.coder; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.time.Instant; +import org.onap.policy.common.gson.GsonMessageBodyHandler; +import org.onap.policy.common.gson.InstantAsMillisTypeAdapter; + +/** + * JSON encoder and decoder using the "standard" mechanism, but encodes Instant fields as + * Long milliseconds. + */ +public class StandardCoderInstantAsMillis extends StandardCoder { + + /** + * Gson object used to encode and decode messages. + */ + private static final Gson GSON_INSTANT; + + /** + * Gson object used to encode messages in "pretty" format. + */ + private static final Gson GSON_INSTANT_PRETTY; + + static { + GsonBuilder builder = GsonMessageBodyHandler + .configBuilder(new GsonBuilder().registerTypeAdapter(StandardCoderObject.class, + new StandardTypeAdapter())) + .registerTypeAdapter(Instant.class, new InstantAsMillisTypeAdapter()); + + GSON_INSTANT = builder.create(); + GSON_INSTANT_PRETTY = builder.setPrettyPrinting().create(); + } + + /** + * Constructs the object. + */ + public StandardCoderInstantAsMillis() { + super(GSON_INSTANT, GSON_INSTANT_PRETTY); + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderObject.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderObject.java index 60c5f4ef..55f7f9d7 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderObject.java +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoderObject.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,18 +21,29 @@ package org.onap.policy.common.utils.coder; import com.google.gson.JsonElement; +import java.io.Serializable; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; /** * Object type used by the {@link StandardCoder}. Different serialization tools have * different "standard objects". For instance, GSON uses {@link JsonElement}. This class * wraps that object so that it can be used without exposing the object, itself. */ -public class StandardCoderObject { +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class StandardCoderObject implements Serializable { + private static final long serialVersionUID = 1L; /** * Data wrapped by this. */ - private final JsonElement data; + /* + * this should not be transient, but since it isn't serializable, we're stuck with it + * until there's time to address the issue + */ + @Getter(AccessLevel.PROTECTED) + private final transient JsonElement data; /** * Constructs the object. @@ -42,52 +53,75 @@ public class StandardCoderObject { } /** - * Constructs the object. - * - * @param data data wrapped by this object. - */ - protected StandardCoderObject(JsonElement data) { - this.data = data; - } - - /** - * Gets the data wrapped by this. - * - * @return the data wrapped by this - */ - protected JsonElement getData() { - return data; - } - - /** * Gets a field's value from this object, traversing the object hierarchy. * - * @param fields field hierarchy + * @param fields field hierarchy. These may be strings, identifying fields within the + * object, or Integers, identifying an index within an array * @return the field value or {@code null} if the field does not exist or is not a * primitive */ - public String getString(String... fields) { - - /* - * This could be relatively easily modified to allow Integer arguments, as well, - * which would be used to specify indices within an array. - */ + public String getString(Object... fields) { JsonElement jel = data; - for (String field : fields) { + for (Object field : fields) { if (jel == null) { return null; } - if (jel.isJsonObject()) { - jel = jel.getAsJsonObject().get(field); + if (field instanceof String) { + jel = getFieldFromObject(jel, field.toString()); + + } else if (field instanceof Integer) { + jel = getItemFromArray(jel, (int) field); } else { - return null; + throw new IllegalArgumentException("subscript is not a string or integer: " + field); } } return (jel != null && jel.isJsonPrimitive() ? jel.getAsString() : null); } + + /** + * Gets an item from an object. + * + * @param element object from which to extract the item + * @param field name of the field from which to extract the item + * @return the item, or {@code null} if the element is not an object or if the field + * does not exist + */ + protected JsonElement getFieldFromObject(JsonElement element, String field) { + if (!element.isJsonObject()) { + return null; + } + + return element.getAsJsonObject().get(field); + } + + /** + * Gets an item from an array. + * + * @param element array from which to extract the item + * @param index index of the item to extract + * @return the item, or {@code null} if the element is not an array or if the index is + * out of bounds + */ + protected JsonElement getItemFromArray(JsonElement element, int index) { + if (index < 0) { + throw new IllegalArgumentException("subscript is invalid: " + index); + } + + if (!element.isJsonArray()) { + return null; + } + + var array = element.getAsJsonArray(); + + if (index >= array.size()) { + return null; + } + + return array.get(index); + } } diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java new file mode 100644 index 00000000..4deeba14 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java @@ -0,0 +1,119 @@ +/*-- + * ============LICENSE_START======================================================= + * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.coder; + +import com.worldturner.medeia.api.JsonSchemaVersion; +import com.worldturner.medeia.api.SchemaSource; +import com.worldturner.medeia.api.StringSchemaSource; +import com.worldturner.medeia.api.ValidationFailedException; +import com.worldturner.medeia.api.gson.MedeiaGsonApi; +import com.worldturner.medeia.schema.validation.SchemaValidator; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import lombok.NonNull; +import lombok.ToString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Extension to the StandardCoder to support streaming validation against a Draft-07 Json schema specification. + */ + +@ToString +public class StandardValCoder extends StandardCoder { + + // The medeia-validator library integrates better than + // other libraries considered with GSON, and therefore + // the StandardCoder. + + private static final Logger logger = LoggerFactory.getLogger(StandardValCoder.class); + + private final MedeiaGsonApi validatorApi = new MedeiaGsonApi(); + private final SchemaValidator validator; + + /** + * StandardCoder with validation. + */ + public StandardValCoder(@NonNull String jsonSchema, @NonNull String name) { + SchemaSource schemaSource = new StringSchemaSource(jsonSchema, JsonSchemaVersion.DRAFT07, null, name); + this.validator = validatorApi.loadSchema(schemaSource); + } + + @Override + protected String toPrettyJson(Object object) { + /* + * The validator strips off the "pretty" stuff (i.e., spaces), thus we have to validate and generate the pretty + * JSON in separate steps. + */ + gson.toJson(object, object.getClass(), validatorApi.createJsonWriter(validator, new StringWriter())); + + return super.toPrettyJson(object); + } + + @Override + protected String toJson(@NonNull Object object) { + var output = new StringWriter(); + toJson(output, object); + return output.toString(); + } + + @Override + protected void toJson(@NonNull Writer target, @NonNull Object object) { + gson.toJson(object, object.getClass(), validatorApi.createJsonWriter(validator, target)); + } + + @Override + protected <T> T fromJson(@NonNull Reader source, @NonNull Class<T> clazz) { + return convertFromDouble(clazz, gson.fromJson(validatorApi.createJsonReader(validator, source), clazz)); + } + + @Override + protected <T> T fromJson(String json, Class<T> clazz) { + var reader = new StringReader(json); + return convertFromDouble(clazz, gson.fromJson(validatorApi.createJsonReader(validator, reader), clazz)); + } + + /** + * Is the json conformant?. + */ + public boolean isConformant(@NonNull String json) { + try { + conformance(json); + } catch (CoderException e) { + logger.info("JSON is not conformant to schema", e); + return false; + } + return true; + } + + /** + * Check a json string for conformance against its schema definition. + */ + public void conformance(@NonNull String json) throws CoderException { + try { + validatorApi.parseAll(validatorApi.createJsonReader(validator, new StringReader(json))); + } catch (ValidationFailedException e) { + throw new CoderException(e); + } + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java index 36f15b96..d94ddca4 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,18 @@ public class StandardYamlCoder extends StandardCoder { * Constructs the object. */ public StandardYamlCoder() { - translator = new YamlJsonTranslator(getGSON()); + translator = new YamlJsonTranslator(gson) { + @Override + protected <T> T convertFromDouble(Class<T> clazz, T value) { + return StandardYamlCoder.this.convertFromDouble(clazz, value); + } + }; + } + + @Override + protected String toPrettyJson(Object object) { + // YAML is already "pretty" + return toJson(object); } @Override diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/YamlJsonTranslator.java b/utils/src/main/java/org/onap/policy/common/utils/coder/YamlJsonTranslator.java index 906c9fdd..077246bf 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/coder/YamlJsonTranslator.java +++ b/utils/src/main/java/org/onap/policy/common/utils/coder/YamlJsonTranslator.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ package org.onap.policy.common.utils.coder; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -31,9 +32,12 @@ import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; +import lombok.AllArgsConstructor; +import org.onap.policy.common.gson.InstantTypeAdapter; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.emitter.Emitter; @@ -50,7 +54,13 @@ import org.yaml.snakeyaml.serializer.Serializer; /** * YAML-JSON translator. The methods may throw either of the runtime exceptions, * YAMLException or JsonSyntaxException. + * <p/> + * Note: if the invoker wishes Double to be converted to Integer/Long when type + * Object.class is requested, then a Gson object must be used that will perform the + * translation. In addition, the {@link #convertFromDouble(Class, Object)} method should + * be overridden with an appropriate conversion method. */ +@AllArgsConstructor public class YamlJsonTranslator { /** @@ -62,16 +72,9 @@ public class YamlJsonTranslator { * Constructs the object. */ public YamlJsonTranslator() { - this(new Gson()); - } - - /** - * Constructs the object. - * - * @param gson the Gson object to be used to serialize and de-serialize - */ - public YamlJsonTranslator(Gson gson) { - this.gson = gson; + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(Instant.class, new InstantTypeAdapter()); + gson = builder.create(); } /** @@ -81,7 +84,7 @@ public class YamlJsonTranslator { * @return YAML representing the original object */ public String toYaml(Object object) { - StringWriter output = new StringWriter(); + var output = new StringWriter(); toYaml(output, object); return output.toString(); } @@ -93,8 +96,8 @@ public class YamlJsonTranslator { * @param object POJO to be translated */ public void toYaml(Writer target, Object object) { - DumperOptions dumper = new DumperOptions(); - Serializer serializer = new Serializer(new Emitter(target, dumper), new Resolver(), dumper, null); + var dumper = new DumperOptions(); + var serializer = new Serializer(new Emitter(target, dumper), new Resolver(), dumper, null); try { serializer.open(); @@ -135,7 +138,7 @@ public class YamlJsonTranslator { * @return a POJO representing the YAML read from the reader */ public <T> T fromYaml(Reader source, Class<T> clazz) { - Node node = new Yaml().compose(source); + var node = new Yaml().compose(source); return fromJson(makeJson(node), clazz); } @@ -147,7 +150,22 @@ public class YamlJsonTranslator { * @return a POJO representing the original element */ protected <T> T fromJson(JsonElement jel, Class<T> clazz) { - return gson.fromJson(jel, clazz); + return convertFromDouble(clazz, gson.fromJson(jel, clazz)); + } + + /** + * Converts a value from Double to Integer/Long, walking the value's contents if it's + * a List/Map. Only applies if the specified class refers to the Object class. + * Otherwise, it leaves the value unchanged. + * <p/> + * The default method simply returns the original value. + * + * @param clazz class of object to be decoded + * @param value value to be converted + * @return the converted value + */ + protected <T> T convertFromDouble(Class<T> clazz, T value) { + return value; } /** @@ -261,7 +279,7 @@ public class YamlJsonTranslator { protected JsonArray makeJsonArray(SequenceNode node) { List<Node> nodes = node.getValue(); - JsonArray array = new JsonArray(nodes.size()); + var array = new JsonArray(nodes.size()); nodes.forEach(subnode -> array.add(makeJson(subnode))); return array; @@ -274,10 +292,10 @@ public class YamlJsonTranslator { * @return a gson element corresponding to the node */ protected JsonObject makeJsonObject(MappingNode node) { - JsonObject obj = new JsonObject(); + var obj = new JsonObject(); for (NodeTuple tuple : node.getValue()) { - Node key = tuple.getKeyNode(); + var key = tuple.getKeyNode(); String skey = ((ScalarNode) key).getValue(); obj.add(skey, makeJson(tuple.getValueNode())); @@ -294,7 +312,7 @@ public class YamlJsonTranslator { */ protected JsonElement makeJsonPrim(ScalarNode node) { try { - Tag tag = node.getTag(); + var tag = node.getTag(); if (tag == Tag.INT) { return new JsonPrimitive(Long.valueOf(node.getValue())); diff --git a/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrCloser.java b/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrCloser.java index 3532002e..f1798516 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrCloser.java +++ b/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrCloser.java @@ -2,14 +2,15 @@ * ============LICENSE_START======================================================= * Common Utils * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,40 +21,26 @@ package org.onap.policy.common.utils.jpa; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; +import lombok.AllArgsConstructor; +import lombok.Getter; /** * Wrapper for an <i>EntityManager</i>, providing auto-close functionality. This is useful in * try-with-resources statements. */ +@AllArgsConstructor public class EntityMgrCloser implements AutoCloseable { /** * The wrapped manager. */ - private final EntityManager em; - - /** - * Construct an instance with the EntityManager. - * - * @param em manager to be auto-closed - */ - public EntityMgrCloser(EntityManager em) { - this.em = em; - } - - /** - * Gets the EntityManager wrapped within this object. - * - * @return the associated EntityManager - */ - public EntityManager getManager() { - return em; - } + @Getter + private final EntityManager manager; @Override public void close() { - em.close(); + manager.close(); } } diff --git a/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrFactoryCloser.java b/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrFactoryCloser.java index b046cc55..5f3a6ea8 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrFactoryCloser.java +++ b/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityMgrFactoryCloser.java @@ -2,14 +2,15 @@ * ============LICENSE_START======================================================= * Common Utils * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,40 +21,26 @@ package org.onap.policy.common.utils.jpa; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; +import lombok.AllArgsConstructor; +import lombok.Getter; /** * Wrapper for an <i>EntityManagerFactory</i>, providing auto-close functionality. This is useful in * try-with-resources statements. */ +@AllArgsConstructor public class EntityMgrFactoryCloser implements AutoCloseable { /** * The wrapped factory. */ - private final EntityManagerFactory emf; - - /** - * Construct an instance with the given EntityManagerFactory. - * - * @param emf manager to be auto-closed - */ - public EntityMgrFactoryCloser(EntityManagerFactory emf) { - this.emf = emf; - } - - /** - * Gets the EntityManagerFactory wrapped within this object. - * - * @return the associated EntityManagerFactory - */ - public EntityManagerFactory getFactory() { - return emf; - } + @Getter + private final EntityManagerFactory factory; @Override public void close() { - emf.close(); + factory.close(); } } diff --git a/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityTransCloser.java b/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityTransCloser.java index 3552a6fa..131e87a4 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityTransCloser.java +++ b/utils/src/main/java/org/onap/policy/common/utils/jpa/EntityTransCloser.java @@ -2,14 +2,15 @@ * ============LICENSE_START======================================================= * Common Utils * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +21,8 @@ package org.onap.policy.common.utils.jpa; -import javax.persistence.EntityTransaction; +import jakarta.persistence.EntityTransaction; +import lombok.Getter; /** * Wrapper for an <i>EntityTransaction</i> that is auto-rolled back when closed. This is useful in @@ -31,46 +33,37 @@ public class EntityTransCloser implements AutoCloseable { /** * Transaction to be rolled back. */ - private final EntityTransaction trans; + @Getter + private final EntityTransaction transaction; /** * Begins a transaction. - * + * * @param et transaction to wrap/begin */ public EntityTransCloser(EntityTransaction et) { - trans = et; - trans.begin(); - } - - /** - * Gets the wrapped transaction. - * - * @return the transaction - */ - public EntityTransaction getTransation() { - return trans; + transaction = et; + transaction.begin(); } /** * Commits the transaction. */ public void commit() { - trans.commit(); + transaction.commit(); } /** * Rolls back the transaction. */ public void rollback() { - trans.rollback(); + transaction.rollback(); } @Override public void close() { - if (trans.isActive()) { - trans.rollback(); + if (transaction.isActive()) { + transaction.rollback(); } } - } diff --git a/utils/src/main/java/org/onap/policy/common/utils/logging/LoggerMarkerFilter.java b/utils/src/main/java/org/onap/policy/common/utils/logging/LoggerMarkerFilter.java new file mode 100644 index 00000000..2c9830dc --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/logging/LoggerMarkerFilter.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All right reserved. + * Modifications Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ + +package org.onap.policy.common.utils.logging; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.filter.AbstractMatcherFilter; +import ch.qos.logback.core.spi.FilterReply; +import org.slf4j.Marker; + +public abstract class LoggerMarkerFilter extends AbstractMatcherFilter<ILoggingEvent> { + + protected final Marker marker; + + protected LoggerMarkerFilter(Marker marker) { + this.marker = marker; + } + + @Override + public FilterReply decide(ILoggingEvent event) { + + if (this.marker == null || !isStarted()) { + return FilterReply.DENY; + } + + if (event == null || event.getMarkerList() == null) { + return FilterReply.DENY; + } + + if (event.getMarkerList().stream().anyMatch(mk -> mk.equals(marker))) { + return FilterReply.ACCEPT; + } else { + return FilterReply.DENY; + } + } + + /** + * Metric Logger Marker Filter. + */ + public static class MetricLoggerMarkerFilter extends LoggerMarkerFilter { + + public MetricLoggerMarkerFilter() { + super(LoggerUtils.METRIC_LOG_MARKER); + } + + } + + /** + * Security Logger Marker Filter. + */ + public static class SecurityLoggerMarkerFilter extends LoggerMarkerFilter { + + public SecurityLoggerMarkerFilter() { + super(LoggerUtils.SECURITY_LOG_MARKER); + } + } + + /** + * Audit Logger Marker Filter. + */ + public static class AuditLoggerMarkerFilter extends LoggerMarkerFilter { + + public AuditLoggerMarkerFilter() { + super(LoggerUtils.AUDIT_LOG_MARKER); + } + } + + /** + * Transaction Logger Marker Filter. + */ + public static class TransactionLoggerMarkerFilter extends LoggerMarkerFilter { + + public TransactionLoggerMarkerFilter() { + super(LoggerUtils.TRANSACTION_LOG_MARKER); + } + } + +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/logging/LoggerUtils.java b/utils/src/main/java/org/onap/policy/common/utils/logging/LoggerUtils.java new file mode 100644 index 00000000..89575eb2 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/logging/LoggerUtils.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ + +package org.onap.policy.common.utils.logging; + +import ch.qos.logback.classic.LoggerContext; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class LoggerUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerUtils.class); + + /** + * ROOT logger. + */ + public static final String ROOT_LOGGER = "ROOT"; + /** + * Metric logger. + */ + public static final String METRIC_LOG_MARKER_NAME = "metric"; + /** + * Audit Log Marker Name. + */ + public static final String AUDIT_LOG_MARKER_NAME = "audit"; + /** + * Security Log Marker Name. + */ + public static final String SECURITY_LOG_MARKER_NAME = "security"; + /** + * Transaction Log Marker Name. + */ + public static final String TRANSACTION_LOG_MARKER_NAME = "transaction"; + /** + * Marks a logging record for metric. + */ + public static final Marker METRIC_LOG_MARKER = MarkerFactory.getMarker(METRIC_LOG_MARKER_NAME); + /** + * Marks a logging record for security. + */ + public static final Marker SECURITY_LOG_MARKER = MarkerFactory.getMarker(SECURITY_LOG_MARKER_NAME); + /** + * Marks a logging record for audit. + */ + public static final Marker AUDIT_LOG_MARKER = MarkerFactory.getMarker(AUDIT_LOG_MARKER_NAME); + /** + * Marks a logging record as an end-to-end transaction. + */ + public static final Marker TRANSACTION_LOG_MARKER = MarkerFactory.getMarker(TRANSACTION_LOG_MARKER_NAME); + + + /** + * Set the log level of a logger. + * + * @param loggerName logger name + * @param loggerLevel logger level + */ + public static String setLevel(String loggerName, String loggerLevel) { + if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { + throw new IllegalStateException("The SLF4J logger factory is not configured for logback"); + } + + final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + final var logger = context.getLogger(loggerName); + if (logger == null) { + throw new IllegalArgumentException("no logger " + loggerName); + } + + LOGGER.warn("setting {} logger to level {}", loggerName, loggerLevel); + + // use the current log level if the string provided cannot be converted to a valid Level. + + // NOSONAR: this method is currently used by the telemetry api (which should be authenticated). + // It is no more or no less dangerous than an admin changing the logback level on the fly. + // This is a controlled admin function that should not cause any risks when the system + // is configured properly. + logger.setLevel(ch.qos.logback.classic.Level.toLevel(loggerLevel, logger.getLevel())); // NOSONAR + + return logger.getLevel().toString(); + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/network/NetworkUtil.java b/utils/src/main/java/org/onap/policy/common/utils/network/NetworkUtil.java index 14362627..6698d7cf 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/network/NetworkUtil.java +++ b/utils/src/main/java/org/onap/policy/common/utils/network/NetworkUtil.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,16 +26,19 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; -import java.security.cert.X509Certificate; +import java.util.UUID; import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.net.util.TrustManagerUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Network Utilities. */ -public class NetworkUtil { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class NetworkUtil { public static final Logger logger = LoggerFactory.getLogger(NetworkUtil.class.getName()); @@ -48,33 +51,7 @@ public class NetworkUtil { /** * A trust manager that always trusts certificates. */ - // @formatter:off - private static final TrustManager[] ALWAYS_TRUST_MANAGER = new TrustManager[] { - new X509TrustManager() { - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - - @Override - public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, - final String authType) { - // always trust - } - - @Override - public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, - final String authType) { - // always trust - } - } - }; - // @formatter:on - - private NetworkUtil() { - // Empty constructor - } + private static final TrustManager[] ALWAYS_TRUST_MANAGER = { TrustManagerUtils.getAcceptAllTrustManager() }; /** * Allocates an available port on which a server may listen. @@ -105,7 +82,11 @@ public class NetworkUtil { * @throws IOException if a socket cannot be created */ public static int allocPort(InetSocketAddress hostAddr) throws IOException { - try (ServerSocket socket = new ServerSocket()) { + /* + * The socket is only used to find an unused address for a new server. As a + * result, it poses no security risk, thus the sonar issue can be ignored. + */ + try (ServerSocket socket = new ServerSocket()) { // NOSONAR socket.bind(hostAddr); return socket.getLocalPort(); @@ -132,9 +113,13 @@ public class NetworkUtil { */ public static boolean isTcpPortOpen(String host, int port, int retries, long interval) throws InterruptedException { - int retry = 0; + var retry = 0; while (retry < retries) { - try (Socket s = new Socket(host, port)) { + /* + * As with the server socket, this is only used to see if the port is open, + * thus the sonar issue can be ignored. + */ + try (Socket s = new Socket(host, port)) { // NOSONAR logger.debug("{}:{} connected - retries={} interval={}", host, port, retries, interval); return true; } catch (final IOException e) { @@ -186,4 +171,15 @@ public class NetworkUtil { return "127.0.0.1"; } + + /** + * Generates a globally unique name, typically for use in PDP messages, to uniquely + * identify a PDP (or PAP), regardless on what cluster it resides. + * + * @param prefix text to be prepended to the generated value + * @return a globally unique name + */ + public static String genUniqueName(String prefix) { + return prefix + "-" + UUID.randomUUID(); + } } diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/BeanConfigurator.java b/utils/src/main/java/org/onap/policy/common/utils/properties/BeanConfigurator.java index 2ef91911..f8c52091 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/properties/BeanConfigurator.java +++ b/utils/src/main/java/org/onap/policy/common/utils/properties/BeanConfigurator.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP - Common Modules * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package org.onap.policy.common.utils.properties; +import com.google.re2j.Pattern; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -45,6 +46,7 @@ import org.onap.policy.common.utils.properties.exception.PropertyMissingExceptio * <i>accept</i> includes the "empty" option. */ public class BeanConfigurator { + private static final Pattern COMMA_PAT = Pattern.compile(","); /** * The "empty" option that may appear within the {@link Property}'s <i>accept</i> @@ -414,7 +416,7 @@ public class BeanConfigurator { * @return {@code true} if the <i>accept</i> attribute includes "empty" */ protected boolean isEmptyOk(Property prop) { - for (String option : prop.accept().split(",")) { + for (String option : COMMA_PAT.split(prop.accept())) { if (ACCEPT_EMPTY.equals(option)) { return true; } @@ -495,7 +497,7 @@ public class BeanConfigurator { * @throws PropertyAccessException if a "get" method cannot be identified */ private Method getGetter(Field field, Property prop) throws PropertyAccessException { - String capnm = StringUtils.capitalize(field.getName()); + var capnm = StringUtils.capitalize(field.getName()); try { return getGetter(field, "get" + capnm); diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/PropertyObjectUtils.java b/utils/src/main/java/org/onap/policy/common/utils/properties/PropertyObjectUtils.java new file mode 100644 index 00000000..2b6e514f --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/properties/PropertyObjectUtils.java @@ -0,0 +1,242 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.properties; + +import com.google.re2j.Pattern; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utilities for generating POJOs from Properties. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class PropertyObjectUtils { + + public static final Logger logger = LoggerFactory.getLogger(PropertyObjectUtils.class); + private static final Pattern NAME_PAT = Pattern.compile("\\[(\\d{1,3})\\]$"); + private static final Pattern DOT_PAT = Pattern.compile("[.]"); + + /** + * Converts a set of properties to a Map. Supports json-path style property names with + * "." separating components, where components may have an optional subscript. + * + * @param properties properties to be converted + * @param prefix properties whose names begin with this prefix are included. The + * prefix is stripped from the name before adding the value to the map + * @return a hierarchical map representing the properties + */ + public static Map<String, Object> toObject(Properties properties, String prefix) { + String dottedPrefix = prefix + (prefix.isEmpty() || prefix.endsWith(".") ? "" : "."); + int pfxlen = dottedPrefix.length(); + + Map<String, Object> map = new LinkedHashMap<>(); + + for (String name : properties.stringPropertyNames()) { + if (name.startsWith(dottedPrefix)) { + String[] components = DOT_PAT.split(name.substring(pfxlen)); + setProperty(map, components, properties.getProperty(name)); + } + } + + return map; + } + + /** + * Sets a property within a hierarchical map. + * + * @param map map into which the value should be placed + * @param names property name components + * @param value value to be placed into the map + */ + private static void setProperty(Map<String, Object> map, String[] names, String value) { + Map<String, Object> node = map; + + final int lastComp = names.length - 1; + + // process all but the final component + for (var comp = 0; comp < lastComp; ++comp) { + node = getNode(node, names[comp]); + } + + // process the final component + String name = names[lastComp]; + var matcher = NAME_PAT.matcher(name); + + if (!matcher.find()) { + // no subscript + node.put(name, value); + return; + } + + // subscripted + List<Object> array = getArray(node, name.substring(0, matcher.start())); + var index = Integer.parseInt(matcher.group(1)); + expand(array, index); + array.set(index, value); + } + + /** + * Gets a node. + * + * @param map map from which to get the object + * @param name name of the element to get from the map, with an optional subscript + * @return a Map + */ + @SuppressWarnings("unchecked") + private static Map<String, Object> getNode(Map<String, Object> map, String name) { + var matcher = NAME_PAT.matcher(name); + + if (!matcher.find()) { + // no subscript + return getObject(map, name); + } + + // subscripted + List<Object> array = getArray(map, name.substring(0, matcher.start())); + var index = Integer.parseInt(matcher.group(1)); + expand(array, index); + + Object item = array.get(index); + if (item instanceof Map) { + return (Map<String, Object>) item; + + } else { + LinkedHashMap<String, Object> result = new LinkedHashMap<>(); + array.set(index, result); + return result; + } + } + + /** + * Ensures that an array's size is large enough to hold the specified element. + * + * @param array array to be expanded + * @param index index of the desired element + */ + private static void expand(List<Object> array, int index) { + while (array.size() <= index) { + array.add(null); + } + } + + /** + * Gets an object (i.e., Map) from a map. If the particular element is not a Map, then + * it is replaced with an empty Map. + * + * @param map map from which to get the object + * @param name name of the element to get from the map, without any subscript + * @return a Map + */ + private static Map<String, Object> getObject(Map<String, Object> map, String name) { + @SuppressWarnings("unchecked") + Map<String, Object> result = (Map<String, Object>) map.compute(name, (key, value) -> { + if (value instanceof Map) { + return value; + } else { + return new LinkedHashMap<>(); + } + }); + + return result; + } + + /** + * Gets an array from a map. If the particular element is not an array, then it is + * replaced with an empty array. + * + * @param map map from which to get the array + * @param name name of the element to get from the map, without any subscript + * @return an array + */ + private static List<Object> getArray(Map<String, Object> map, String name) { + @SuppressWarnings("unchecked") + List<Object> result = (List<Object>) map.compute(name, (key, value) -> { + if (value instanceof List) { + return value; + } else { + return new ArrayList<>(); + } + }); + + return result; + } + + /** + * Compresses lists contained within a generic object, removing all {@code null} + * items. + * + * @param object object to be compressed + * @return the original object, modified in place + */ + public static Object compressLists(Object object) { + if (object instanceof Map) { + @SuppressWarnings("unchecked") + Map<String, Object> asMap = (Map<String, Object>) object; + compressMapValues(asMap); + + } else if (object instanceof List) { + @SuppressWarnings("unchecked") + List<Object> asList = (List<Object>) object; + compressListItems(asList); + } + + // else: ignore anything else + + return object; + } + + /** + * Walks a hierarchical map and removes {@code null} items found in any Lists. + * + * @param map map whose lists are to be compressed + */ + private static void compressMapValues(Map<String, Object> map) { + for (Object value : map.values()) { + compressLists(value); + } + } + + /** + * Removes {@code null} items from the list. In addition, it walks the items within + * the list, compressing them, as well. + * + * @param list the list to be compressed + */ + private static void compressListItems(List<Object> list) { + Iterator<Object> iter = list.iterator(); + while (iter.hasNext()) { + Object item = iter.next(); + if (item == null) { + // null item - remove it + iter.remove(); + + } else { + compressLists(item); + } + } + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java b/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java index ec7157d3..2ea94959 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java +++ b/utils/src/main/java/org/onap/policy/common/utils/properties/SpecProperties.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018, 2020-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,10 +21,13 @@ package org.onap.policy.common.utils.properties; import java.util.Properties; +import lombok.AccessLevel; +import lombok.Getter; /** * Properties with an optional specialization (e.g., session name, controller name). */ +@Getter(AccessLevel.PROTECTED) public class SpecProperties extends Properties { private static final long serialVersionUID = 1L; @@ -89,7 +92,7 @@ public class SpecProperties extends Properties { return super.getProperty(key); } - String suffix = key.substring(prefix.length()); + var suffix = key.substring(prefix.length()); String val = super.getProperty(specPrefix + suffix); if (val != null) { @@ -99,14 +102,6 @@ public class SpecProperties extends Properties { return super.getProperty(key); } - protected String getPrefix() { - return prefix; - } - - protected String getSpecPrefix() { - return specPrefix; - } - @Override public final synchronized int hashCode() { throw new UnsupportedOperationException("SpecProperties cannot be hashed"); diff --git a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java index 44edd428..3c03f38d 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java +++ b/utils/src/main/java/org/onap/policy/common/utils/properties/exception/PropertyException.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * ONAP Policy Engine - Common Modules * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,9 +20,12 @@ package org.onap.policy.common.utils.properties.exception; +import lombok.Getter; + /** * Exception associated with a Property. */ +@Getter public class PropertyException extends Exception { private static final long serialVersionUID = 1L; @@ -38,7 +41,7 @@ public class PropertyException extends Exception { /** * Constructor. - * + * * @param propName name of the property causing the exception, or {@code null} * @param fieldName name of the field causing the exception, or {@code null} */ @@ -51,7 +54,7 @@ public class PropertyException extends Exception { /** * Constructor. - * + * * @param propnm name of the property causing the exception, or {@code null} * @param fieldName name of the field causing the exception, or {@code null} * @param message error message @@ -65,7 +68,7 @@ public class PropertyException extends Exception { /** * Constructor. - * + * * @param propnm name of the property causing the exception, or {@code null} * @param fieldName name of the field causing the exception, or {@code null} * @param cause cause of the exception @@ -79,7 +82,7 @@ public class PropertyException extends Exception { /** * Constructor. - * + * * @param propnm name of the property causing the exception, or {@code null} * @param fieldName name of the field causing the exception, or {@code null} * @param message error message @@ -93,28 +96,8 @@ public class PropertyException extends Exception { } /** - * Get the property name. - * - * @return name of the property for which the exception was thrown, or {@code null} if - * no name was provided - */ - public String getPropertyName() { - return propertyName; - } - - /** - * Get the field name. - * - * @return name of the field for which the exception was thrown, or {@code null} if no - * field was provided - */ - public String getFieldName() { - return fieldName; - } - - /** * Make the message. - * + * * @param propnm name of the property causing the exception, or {@code null} * @param fieldName name of the field causing the exception, or {@code null} * @param message error message, never {@code null} @@ -126,13 +109,13 @@ public class PropertyException extends Exception { /** * Make the message. - * + * * @param propnm name of the property causing the exception, or {@code null} * @param fieldName name of the field causing the exception, or {@code null} * @return an error message composed of the two items */ private static String makeMessage(String propnm, String fieldName) { - StringBuilder bldr = new StringBuilder(50); + var bldr = new StringBuilder(50); if (propnm == null) { bldr.append("property exception"); diff --git a/utils/src/main/java/org/onap/policy/common/utils/resources/DirectoryUtils.java b/utils/src/main/java/org/onap/policy/common/utils/resources/DirectoryUtils.java new file mode 100644 index 00000000..35a13138 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/resources/DirectoryUtils.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.resources; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utilities for manipulating directories. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class DirectoryUtils { + private static final Logger logger = LoggerFactory.getLogger(DirectoryUtils.class); + + /** + * Creates a directory file, only accessible by the owner. + * + * @param prefix file name prefix + * @return a new, temporary directory + * @throws IOException if an error occurs + */ + public static Path createTempDirectory(String prefix) throws IOException { + /* + * Disabling sonar, as the code below sets the permissions, just as sonar + * suggests it be fixed. + */ + var path = Files.createTempDirectory(prefix); // NOSONAR + logger.info("created temporary directory, {}", path); + + var file = path.toFile(); + + TextFileUtils.setDefaultPermissions(file); + + // ensure nothing has been written to it yet + FileUtils.cleanDirectory(file); + + return path; + } +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/resources/MessageConstants.java b/utils/src/main/java/org/onap/policy/common/utils/resources/MessageConstants.java new file mode 100644 index 00000000..ef46fdf5 --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/resources/MessageConstants.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Bell Canada. All rights reserved. + * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.resources; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * Common messages to be used by all components. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class MessageConstants { + + public static final String POLICY_API = "policy-api"; + public static final String POLICY_PAP = "policy-pap"; + public static final String POLICY_APEX_PDP = "policy-apex-pdp"; + public static final String POLICY_DROOLS_PDP = "policy-drools-pdp"; + public static final String POLICY_XACML_PDP = "policy-xacml-pdp"; + public static final String POLICY_DISTRIBUTION = "policy-distribution"; + public static final String POLICY_CLAMP = "policy-clamp"; + + public static final String START_SUCCESS_MSG = "Started %s service successfully."; + public static final String START_FAILURE_MSG = "Start of %s service failed."; +} diff --git a/utils/src/main/java/org/onap/policy/common/utils/resources/PrometheusUtils.java b/utils/src/main/java/org/onap/policy/common/utils/resources/PrometheusUtils.java new file mode 100644 index 00000000..bac65d4e --- /dev/null +++ b/utils/src/main/java/org/onap/policy/common/utils/resources/PrometheusUtils.java @@ -0,0 +1,107 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2022 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2022 Bell Canada. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.resources; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * Prometheus constants and utilities. + */ + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class PrometheusUtils { + + /** + * Policy Deployments Metric Name. + */ + public static final String POLICY_DEPLOYMENTS_METRIC = "policy_deployments"; + + /** + * Policy Deployments Metric Help Message. + */ + public static final String POLICY_DEPLOYMENT_HELP = "The total number of policy deployments."; + + /** + * Policy Execution Metric Name. + */ + public static final String POLICY_EXECUTION_METRIC = "policy_executions"; + + /** + * Policy Execution Metric Help Message. + */ + public static final String POLICY_EXECUTION_HELP = "The total number of TOSCA policy executions."; + + /** + * Policy Execution Latency in Seconds Metric Name. + * This metric name is not to be used as a counter. + */ + public static final String POLICY_EXECUTIONS_LATENCY_SECONDS_METRIC = "policy_executions_latency_seconds"; + + /** + * Policy Execution Latency in Seconds Metric Help message. + */ + public static final String POLICY_EXECUTIONS_LATENCY_SECONDS_HELP = + "The latency in seconds of TOSCA policy executions."; + + /** + * Metric label for arbitrary operations (eg. deploy, undeploy, execute). + */ + public static final String OPERATION_METRIC_LABEL = "operation"; + + /** + * Deploy operation value. + */ + public static final String DEPLOY_OPERATION = "deploy"; + + /** + * Undeploy operation value. + */ + public static final String UNDEPLOY_OPERATION = "undeploy"; + + /** + * Metric label for states (ie. PASSIVE, ACTIVE). + */ + public static final String STATE_METRIC_LABEL = "state"; + + /** + * Metric label for status of an operation (ie. SUCCESS or FAILURE). + */ + public static final String STATUS_METRIC_LABEL = "status"; + + /** + * Prometheus namespace values mapping to the supported PDP types. + */ + public enum PdpType { + PDPD("pdpd"), + PDPA("pdpa"), + PDPX("pdpx"); + + @Getter + private final String namespace; + + PdpType(String namespace) { + this.namespace = namespace; + } + } +}
\ No newline at end of file diff --git a/utils/src/main/java/org/onap/policy/common/utils/resources/ResourceUtils.java b/utils/src/main/java/org/onap/policy/common/utils/resources/ResourceUtils.java index 365efabe..3ee062f1 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/resources/ResourceUtils.java +++ b/utils/src/main/java/org/onap/policy/common/utils/resources/ResourceUtils.java @@ -1,7 +1,8 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2018 Ericsson. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation. + * Modifications Copyright (C) 2020, 2023 Nordix Foundation. + * Modifications Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,18 +22,22 @@ package org.onap.policy.common.utils.resources; -import java.io.ByteArrayOutputStream; +import com.google.re2j.Pattern; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Enumeration; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.jar.JarEntry; import java.util.jar.JarFile; - +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,25 +45,18 @@ import org.slf4j.LoggerFactory; * This is common utility class with static methods for handling Java resources on the class path. It is an abstract * class to prevent any direct instantiation and private constructor to prevent extending this class. */ -public abstract class ResourceUtils { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ResourceUtils { // Get a reference to the logger private static final Logger LOGGER = LoggerFactory.getLogger(ResourceUtils.class); - // The length of byte buffers used to read resources into strings - private static final int BYTE_BUFFER_LENGH = 1024; + private static final Pattern SLASH_PAT = Pattern.compile("/"); // Resource types private static final String FILE_PROTOCOL = "file"; private static final String JAR_PROTOCOL = "jar"; /** - * Private constructor used to prevent sub class instantiation. - */ - private ResourceUtils() { - // Prevent construction of this class - } - - /** * Method to resolve a resource; the local file system is checked first and then the class path is checked. * * @param resourceName The resource name @@ -66,7 +64,7 @@ public abstract class ResourceUtils { */ public static URL getUrl4Resource(final String resourceName) { // Check the local fine system first - final URL urlToResource = getLocalFile(resourceName); + final var urlToResource = getLocalFile(resourceName); // Check if this is a local file if (urlToResource != null) { @@ -86,25 +84,16 @@ public abstract class ResourceUtils { */ public static String getResourceAsString(final String resourceName) { // Get the resource as a stream, we'll convert it to a string then - final InputStream resourceStream = getResourceAsStream(resourceName); - if (resourceStream == null) { - return null; - } - - // Read the stream contents in to an output stream - final ByteArrayOutputStream resourceOutputStreamBuffer = new ByteArrayOutputStream(); - final byte[] resourceBuffer = new byte[BYTE_BUFFER_LENGH]; - int length; - try { - while ((length = resourceStream.read(resourceBuffer)) != -1) { - resourceOutputStreamBuffer.write(resourceBuffer, 0, length); + // Read the stream contents, closing when done + try (var resourceStream = getResourceAsStream(resourceName)) { + if (resourceStream == null) { + return null; } + return IOUtils.toString(resourceStream, StandardCharsets.UTF_8); } catch (final IOException e) { - LOGGER.debug("error reading resource stream \"{}\" : " + e.getMessage(), resourceName, e); + LOGGER.debug("error reading resource stream {}", resourceName, e); return null; } - - return resourceOutputStreamBuffer.toString(); } /** @@ -116,12 +105,12 @@ public abstract class ResourceUtils { */ public static InputStream getResourceAsStream(final String resourceName) { // Find a URL to the resource first - final URL urlToResource = getUrl4Resource(resourceName); + final var urlToResource = getUrl4Resource(resourceName); // Check if the resource exists if (urlToResource == null) { // No resource found - LOGGER.debug("cound not find resource \"{}\" : ", resourceName); + LOGGER.debug("could not find resource \"{}\" : ", resourceName); return null; } @@ -130,7 +119,7 @@ public abstract class ResourceUtils { return urlToResource.openStream(); } catch (final IOException e) { // Any of many IO exceptions such as the resource is a directory - LOGGER.debug("error attaching resource \"{}\" to stream : " + e.getMessage(), resourceName, e); + LOGGER.debug("error attaching resource {}", resourceName, e); return null; } } @@ -143,11 +132,11 @@ public abstract class ResourceUtils { */ public static URL getUrlResource(final String resourceName) { try { - final ClassLoader classLoader = ResourceUtils.class.getClassLoader(); + final var classLoader = ResourceUtils.class.getClassLoader(); - final String[] fileParts = resourceName.split("/"); + final String[] fileParts = SLASH_PAT.split(resourceName); // Read the resource - URL url = classLoader.getResource(resourceName); + var url = classLoader.getResource(resourceName); // Check if the resource is defined if (url != null) { @@ -164,7 +153,7 @@ public abstract class ResourceUtils { return url; } } catch (final Exception e) { - LOGGER.debug("error getting URL resource \"{}\" : " + e.getMessage(), e); + LOGGER.debug("error getting URL resource {}", resourceName, e); return null; } } @@ -178,8 +167,8 @@ public abstract class ResourceUtils { public static URL getLocalFile(final String resourceName) { try { // Input might already be in URL format - final URL ret = new URL(resourceName); - final File f = new File(ret.toURI()); + final var ret = new URL(resourceName); + final var f = new File(ret.toURI()); if (f.exists()) { return ret; } @@ -188,10 +177,10 @@ public abstract class ResourceUtils { } try { - final File f = new File(resourceName); + final var f = new File(resourceName); // Check if the file exists if (f.exists()) { - final URL urlret = f.toURI().toURL(); + final var urlret = f.toURI().toURL(); LOGGER.debug("resource \"{}\" was found on the local file system", f.toURI().toURL()); return urlret; } else { @@ -199,7 +188,7 @@ public abstract class ResourceUtils { return null; } } catch (final Exception e) { - LOGGER.debug("error finding resource \"{}\" : " + e.getMessage(), e); + LOGGER.debug("error finding resource {}", resourceName, e); return null; } } @@ -215,7 +204,7 @@ public abstract class ResourceUtils { return null; } - URL modelFileUrl = getUrl4Resource(resource); + var modelFileUrl = getUrl4Resource(resource); if (modelFileUrl != null) { return modelFileUrl.getPath(); } else { @@ -227,11 +216,11 @@ public abstract class ResourceUtils { * Read the list of entries in a resource directory. * * @param resourceDirectoryName the name of the resource directory - * @return the list of entries + * @return a set of entries */ public static Set<String> getDirectoryContents(final String resourceDirectoryName) { // Find the location of the resource, is it in a Jar or on the local file system? - URL directoryUrl = ResourceUtils.getUrl4Resource(resourceDirectoryName); + var directoryUrl = ResourceUtils.getUrl4Resource(resourceDirectoryName); if (directoryUrl == null) { LOGGER.debug("resource \"{}\" was not found", resourceDirectoryName); @@ -255,11 +244,11 @@ public abstract class ResourceUtils { * * @param localResourceDirectoryUrl the local resource file URL * @param resourceDirectoryName the name of the resource directory - * @return a list of the directory contents + * @return a set of the directory contents */ public static Set<String> getDirectoryContentsLocal(final URL localResourceDirectoryUrl, final String resourceDirectoryName) { - File localDirectory = new File(localResourceDirectoryUrl.getFile()); + var localDirectory = new File(localResourceDirectoryUrl.getFile()); if (!localDirectory.isDirectory()) { LOGGER.debug("resource \"{}\" is not a directory", resourceDirectoryName); @@ -267,7 +256,7 @@ public abstract class ResourceUtils { } Set<String> localDirectorySet = new TreeSet<>(); - for (File localDirectoryEntry : localDirectory.listFiles()) { + for (File localDirectoryEntry : Objects.requireNonNull(localDirectory.listFiles())) { if (localDirectoryEntry.isDirectory()) { localDirectorySet .add(resourceDirectoryName + File.separator + localDirectoryEntry.getName() + File.separator); @@ -284,23 +273,29 @@ public abstract class ResourceUtils { * * @param jarResourceDirectoryUrl the name of the resource directory in the jar * @param resourceDirectoryName the name of the resource directory - * @return a list of the directory contents + * @return a set of the directory contents */ public static Set<String> getDirectoryContentsJar(final URL jarResourceDirectoryUrl, final String resourceDirectoryName) { - File jarResourceDirectory = new File(jarResourceDirectoryUrl.getPath()); + String dirNameWithSlash = resourceDirectoryName + "/"; + int minLength = dirNameWithSlash.length() + 1; + var jarResourceDirectory = new File(jarResourceDirectoryUrl.getPath()); String jarFileName = jarResourceDirectory.getParent().replaceFirst("^file:", "").replaceFirst("!.*$", ""); Set<String> localDirectorySet = new TreeSet<>(); - try (JarFile jarFile = new JarFile(jarFileName)) { - Enumeration<JarEntry> entries = jarFile.entries(); + try (var jarFile = new JarFile(jarFileName)) { + Enumeration<JarEntry> entries = jarFile.entries(); // NOSONAR while (entries.hasMoreElements()) { - JarEntry je = entries.nextElement(); - - if (je.getName().matches("^" + resourceDirectoryName + "\\/.+")) { - localDirectorySet.add(je.getName()); + /* + * Ignore sonar issue, as the entries are not being expanded here. + */ + JarEntry je = entries.nextElement(); // NOSONAR + String jeName = je.getName(); + + if (jeName.length() >= minLength && jeName.startsWith(dirNameWithSlash)) { + localDirectorySet.add(jeName); } } } catch (IOException ioe) { diff --git a/utils/src/main/java/org/onap/policy/common/utils/resources/TextFileUtils.java b/utils/src/main/java/org/onap/policy/common/utils/resources/TextFileUtils.java index 01af7fd8..7701eae9 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/resources/TextFileUtils.java +++ b/utils/src/main/java/org/onap/policy/common/utils/resources/TextFileUtils.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2019 Nordix Foundation. + * Modifications Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +26,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The Class TextFileUtils is class that provides useful functions for handling text files. Functions to read and write @@ -33,13 +40,9 @@ import java.nio.file.Files; * * @author Liam Fallon (liam.fallon@est.tech) */ -public abstract class TextFileUtils { - private static final String UTF_8 = "UTF-8"; - private static final int READER_CHAR_BUFFER_SIZE_4096 = 4096; - - private TextFileUtils() { - // This class cannot be initialized - } +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class TextFileUtils { + private static final Logger logger = LoggerFactory.getLogger(TextFileUtils.class); /** * Method to return the contents of a text file as a string. @@ -49,8 +52,8 @@ public abstract class TextFileUtils { * @throws IOException on errors reading text from the file */ public static String getTextFileAsString(final String textFilePath) throws IOException { - final File textFile = new File(textFilePath); - return new String(Files.readAllBytes(textFile.toPath()), UTF_8); + final var textFile = new File(textFilePath); + return Files.readString(textFile.toPath()); } /** @@ -61,7 +64,7 @@ public abstract class TextFileUtils { * @throws IOException on errors reading text from the file */ public static void putStringAsTextFile(final String outString, final String textFilePath) throws IOException { - final File textFile = new File(textFilePath); + final var textFile = new File(textFilePath); if (!textFile.getParentFile().exists()) { textFile.getParentFile().mkdirs(); } @@ -77,7 +80,7 @@ public abstract class TextFileUtils { * @throws IOException on errors reading text from the file */ public static void putStringAsFile(final String outString, final File textFile) throws IOException { - Files.write(textFile.toPath(), outString.getBytes(UTF_8)); + Files.writeString(textFile.toPath(), outString); } /** @@ -88,7 +91,7 @@ public abstract class TextFileUtils { * @throws IOException on errors reading text from the file */ public static String getStreamAsString(final InputStream textStream) throws IOException { - return getReaderAsString(new InputStreamReader(textStream, UTF_8)); + return getReaderAsString(new InputStreamReader(textStream, StandardCharsets.UTF_8)); } /** @@ -99,16 +102,37 @@ public abstract class TextFileUtils { * @throws IOException on errors reading text from the file */ public static String getReaderAsString(final Reader textReader) throws IOException { - final StringBuilder builder = new StringBuilder(); - int charsRead = -1; - final char[] chars = new char[READER_CHAR_BUFFER_SIZE_4096]; - do { - charsRead = textReader.read(chars); - if (charsRead > 0) { - builder.append(chars, 0, charsRead); - } + return IOUtils.toString(textReader); + } + + /** + * Creates a temporary file, only accessible by the owner. + * + * @param prefix file name prefix + * @param suffix file name suffix + * @return a new, temporary file + * @throws IOException if an error occurs + */ + public static File createTempFile(String prefix, String suffix) throws IOException { + /* + * Disabling sonar, because setDefaultPermissions() will set the permissions of + * the file. + */ + var file = File.createTempFile(prefix, suffix); // NOSONAR + + setDefaultPermissions(file); + + return file; + } + + /** + * Sets permissions on a file or directory so that only the owner can access it. + * + * @param file file or directory on which permissions are to be set + */ + public static void setDefaultPermissions(File file) { + if (!file.setReadable(true, true) || !file.setWritable(true, true) || !file.setExecutable(true, true)) { + logger.warn("cannot set permissions for {}", file); } - while (charsRead > 0); - return builder.toString(); } } diff --git a/utils/src/main/java/org/onap/policy/common/utils/security/CryptoUtils.java b/utils/src/main/java/org/onap/policy/common/utils/security/CryptoUtils.java index 416c73a6..a974f1e5 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/security/CryptoUtils.java +++ b/utils/src/main/java/org/onap/policy/common/utils/security/CryptoUtils.java @@ -2,7 +2,8 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +21,12 @@ package org.onap.policy.common.utils.security; +import jakarta.xml.bind.DatatypeConverter; import java.nio.charset.StandardCharsets; import java.util.Random; import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.xml.bind.DatatypeConverter; import org.apache.commons.lang3.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +45,9 @@ public class CryptoUtils implements CryptoCoder { /** * Detailed definition of encryption algorithm. */ - private static final String ALGORITHM_DETAILS = ALGORITHM + "/CBC/PKCS5PADDING"; + private static final String ALGORITHM_DETAILS = ALGORITHM + "/GCM/NoPadding"; + + private static final int TAG_SIZE_IN_BITS = 128; private static final int IV_BLOCK_SIZE_IN_BITS = 128; @@ -62,14 +65,14 @@ public class CryptoUtils implements CryptoCoder { /** * Used to generate a random "iv". Strong randomness is not needed, as this is only - * used as a "salt". + * used as a "salt". (Thus sonar is disabled.) */ - private static final Random RANDOM = new Random(); + private static final Random RANDOM = new Random(); // NOSONAR /** * CryptoUtils - encryption tool constructor. * @param secretKeySpec - * AES supports 128, 192 or 256-bit long key size, it can be plain text or generated with key generator + * AES supports 128, 192 or 256-bit long key size, it can be plain text or generated with key generator */ public CryptoUtils(SecretKeySpec secretKeySpec) { this.secretKeySpec = secretKeySpec; @@ -87,7 +90,7 @@ public class CryptoUtils implements CryptoCoder { * <p>Final result is to put in properties file is: IV + Outcome of openssl command * * @param value - * The plain text string + * The plain text string * @return The encrypted String */ @Override @@ -98,13 +101,13 @@ public class CryptoUtils implements CryptoCoder { /** * Encrypt a value based on the Policy Encryption Key. * @param value - * The plain text string + * The plain text string * @param secretKey - * The secret key + * The secret key * @return The encrypted String */ public static String encrypt(String value, String secretKey) { - SecretKeySpec keySpec = readSecretKeySpec(secretKey); + var keySpec = readSecretKeySpec(secretKey); return encryptValue(value, keySpec); } @@ -117,10 +120,10 @@ public class CryptoUtils implements CryptoCoder { return value; } try { - Cipher cipher = Cipher.getInstance(ALGORITHM_DETAILS); - byte[] iv = new byte[IV_BLOCK_SIZE_IN_BYTES]; + var cipher = Cipher.getInstance(ALGORITHM_DETAILS); + var iv = new byte[IV_BLOCK_SIZE_IN_BYTES]; RANDOM.nextBytes(iv); - IvParameterSpec ivspec = new IvParameterSpec(iv); + var ivspec = new GCMParameterSpec(TAG_SIZE_IN_BITS, iv); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec); return "enc:" + DatatypeConverter.printBase64Binary( @@ -137,7 +140,7 @@ public class CryptoUtils implements CryptoCoder { * -K PrivateHexKey -iv 16BytesIVFromEncryptedString * * @param value - * The encrypted string that must be decrypted using the Policy Encryption Key + * The encrypted string that must be decrypted using the Policy Encryption Key * @return The String decrypted if string begin with 'enc:' */ @Override @@ -149,13 +152,13 @@ public class CryptoUtils implements CryptoCoder { * Decrypt a value based on the Policy Encryption Key if string begin with 'enc:'. * * @param value - * The encrypted string that must be decrypted using the Policy Encryption Key + * The encrypted string that must be decrypted using the Policy Encryption Key * @param secretKey - * The secret key + * The secret key * @return The String decrypted if string begin with 'enc:' */ public static String decrypt(String value, String secretKey) { - SecretKeySpec keySpec = readSecretKeySpec(secretKey); + var keySpec = readSecretKeySpec(secretKey); if (keySpec != null) { return decryptValue(value, keySpec); } else { @@ -171,11 +174,11 @@ public class CryptoUtils implements CryptoCoder { throw new IllegalArgumentException("Invalid size on input value"); } try { - String pureValue = value.substring(4); + var pureValue = value.substring(4); byte[] encryptedValue = DatatypeConverter.parseBase64Binary(pureValue); - Cipher cipher = Cipher.getInstance(ALGORITHM_DETAILS); - IvParameterSpec ivspec = new IvParameterSpec( + var cipher = Cipher.getInstance(ALGORITHM_DETAILS); + var ivspec = new GCMParameterSpec(TAG_SIZE_IN_BITS, ArrayUtils.subarray(encryptedValue, 0, IV_BLOCK_SIZE_IN_BYTES)); byte[] realData = ArrayUtils.subarray(encryptedValue, IV_BLOCK_SIZE_IN_BYTES, encryptedValue.length); @@ -225,10 +228,10 @@ public class CryptoUtils implements CryptoCoder { * Check if string is encrypted by verify if string prefix with 'enc:'. * * @param value - * The encrypted string or plain text value + * The encrypted string or plain text value * @return boolean value indicate if string prefix with enc: or not */ - public static Boolean isEncrypted(String value) { + public static boolean isEncrypted(String value) { return (value != null && value.startsWith("enc:")); } diff --git a/utils/src/main/java/org/onap/policy/common/utils/services/FeatureApiUtils.java b/utils/src/main/java/org/onap/policy/common/utils/services/FeatureApiUtils.java index e88361ea..042ee937 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/services/FeatureApiUtils.java +++ b/utils/src/main/java/org/onap/policy/common/utils/services/FeatureApiUtils.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,15 +23,14 @@ package org.onap.policy.common.utils.services; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Predicate; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; /** * Utilities for use with "feature APIs". */ -public class FeatureApiUtils { - - private FeatureApiUtils() { - // do nothing - } +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class FeatureApiUtils { /** * Applies a function on each feature provider, stopping as soon as one returns true. @@ -44,7 +43,7 @@ public class FeatureApiUtils { * otherwise */ public static <T> boolean apply(List<T> providers, Predicate<T> predicate, - BiConsumer<T,Exception> handleEx) { + BiConsumer<T, Exception> handleEx) { for (T feature : providers) { try { diff --git a/utils/src/main/java/org/onap/policy/common/utils/services/OrderedServiceImpl.java b/utils/src/main/java/org/onap/policy/common/utils/services/OrderedServiceImpl.java index bbd30220..998d6742 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/services/OrderedServiceImpl.java +++ b/utils/src/main/java/org/onap/policy/common/utils/services/OrderedServiceImpl.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * utils * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,18 +24,18 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.ServiceLoader; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is a template for building a sorted list of service instances, - * which are discovered and created using 'ServiceLoader'. + * which are discovered and created using 'ServiceLoader'. */ public class OrderedServiceImpl<T extends OrderedService> { // logger - private static Logger logger = LoggerFactory.getLogger(OrderedServiceImpl.class); + private static Logger logger = LoggerFactory.getLogger(OrderedServiceImpl.class); // sorted list of instances implementing the service private List<T> implementers = null; @@ -44,8 +44,7 @@ public class OrderedServiceImpl<T extends OrderedService> { private ServiceLoader<T> serviceLoader = null; // use this to ensure that we only use one unique instance of each class - @SuppressWarnings("rawtypes") - private static HashMap<Class,OrderedService> classToSingleton = new HashMap<>(); + private static Map<Class<?>, OrderedService> classToSingleton = new HashMap<>(); /** * Constructor - create the 'ServiceLoader' instance. @@ -60,7 +59,7 @@ public class OrderedServiceImpl<T extends OrderedService> { /** * Get List of implementers. - * + * * @return the sorted list of services implementing interface 'T' discovered * by 'ServiceLoader'. */ @@ -87,7 +86,7 @@ public class OrderedServiceImpl<T extends OrderedService> { // build a list of all of the current implementors List<T> tmp = new LinkedList<>(); for (T service : serviceLoader) { - tmp.add((T)getSingleton(service)); + tmp.add((T) getSingleton(service)); } // Sort the list according to sequence number, and then alphabetically diff --git a/utils/src/main/java/org/onap/policy/common/utils/services/Registry.java b/utils/src/main/java/org/onap/policy/common/utils/services/Registry.java index c3eabe8e..8765ba8b 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/services/Registry.java +++ b/utils/src/main/java/org/onap/policy/common/utils/services/Registry.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ package org.onap.policy.common.utils.services; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,6 +31,7 @@ import org.slf4j.LoggerFactory; * This is a simple object registry, similar in spirit to JNDI, but suitable for use in a * stand-alone JVM. */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class Registry { private static final Logger logger = LoggerFactory.getLogger(Registry.class); @@ -40,13 +43,6 @@ public class Registry { private Map<String, Object> name2object = new ConcurrentHashMap<>(); /** - * Constructs the object. - */ - private Registry() { - super(); - } - - /** * Registers an object. * * @param name name by which the object is known diff --git a/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java b/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java index 5c8c01df..08994912 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java +++ b/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,9 @@ package org.onap.policy.common.utils.services; import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicBoolean; +import lombok.AllArgsConstructor; +import lombok.Getter; import org.onap.policy.common.capabilities.Startable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,6 +40,7 @@ public class ServiceManager implements Startable { /** * Manager name. */ + @Getter private final String name; /** @@ -47,7 +51,7 @@ public class ServiceManager implements Startable { /** * {@code True} if the services are currently running, {@code false} otherwise. */ - private boolean running; + private final AtomicBoolean running = new AtomicBoolean(false); /** * Constructs the object, with a default name. @@ -58,16 +62,13 @@ public class ServiceManager implements Startable { /** * Constructs the object. + * * @param name the manager's name, used for logging purposes */ public ServiceManager(String name) { this.name = name; } - public String getName() { - return name; - } - /** * Adds a pair of service actions to the manager. * @@ -77,7 +78,7 @@ public class ServiceManager implements Startable { * @return this manager */ public synchronized ServiceManager addAction(String stepName, RunnableWithEx starter, RunnableWithEx stopper) { - if (running) { + if (isAlive()) { throw new IllegalStateException(name + " is already running; cannot add " + stepName); } @@ -94,7 +95,7 @@ public class ServiceManager implements Startable { * @return this manager */ public synchronized ServiceManager addService(String stepName, Startable service) { - if (running) { + if (isAlive()) { throw new IllegalStateException(name + " is already running; cannot add " + stepName); } @@ -103,13 +104,13 @@ public class ServiceManager implements Startable { } @Override - public synchronized boolean isAlive() { - return running; + public boolean isAlive() { + return running.get(); } @Override public synchronized boolean start() { - if (running) { + if (isAlive()) { throw new IllegalStateException(name + " is already running"); } @@ -134,7 +135,7 @@ public class ServiceManager implements Startable { if (ex == null) { logger.info("{} started", name); - running = true; + running.set(true); return true; } @@ -151,11 +152,11 @@ public class ServiceManager implements Startable { @Override public synchronized boolean stop() { - if (!running) { + if (!isAlive()) { throw new IllegalStateException(name + " is not running"); } - running = false; + running.set(false); rewind(items); return true; @@ -203,20 +204,20 @@ public class ServiceManager implements Startable { /** * Service information. */ + @AllArgsConstructor private static class Service { private String stepName; private RunnableWithEx starter; private RunnableWithEx stopper; - - public Service(String stepName, RunnableWithEx starter, RunnableWithEx stopper) { - this.stepName = stepName; - this.starter = starter; - this.stopper = stopper; - } } + /* + * Cannot use a plain Runnable, because it can't throw exceptions. Could use a + * Callable, instead, but then all the lambda expressions become rather messy, thus + * we'll stick with RunnableWithEx, and just disable the sonar warning. + */ @FunctionalInterface public static interface RunnableWithEx { - void run() throws Exception; + void run() throws Exception; // NOSONAR } } diff --git a/utils/src/main/java/org/onap/policy/common/utils/time/CurrentTime.java b/utils/src/main/java/org/onap/policy/common/utils/time/CurrentTime.java index 857b69b6..95f4d69a 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/time/CurrentTime.java +++ b/utils/src/main/java/org/onap/policy/common/utils/time/CurrentTime.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * Common Utils * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,24 +21,18 @@ package org.onap.policy.common.utils.time; import java.util.Date; +import lombok.NoArgsConstructor; /** * Methods to access the current time. Classes can use objects of this type to get current * time information, while allowing the objects to be overridden by junit tests. */ +@NoArgsConstructor public class CurrentTime { /** - * Constructor. - * - */ - public CurrentTime() { - super(); - } - - /** * Get the millisecond time. - * + * * @return the current time, in milliseconds */ public long getMillis() { @@ -47,7 +41,7 @@ public class CurrentTime { /** * Get the current date. - * + * * @return the current Date */ public Date getDate() { @@ -56,7 +50,7 @@ public class CurrentTime { /** * Sleeps for a period of time. - * + * * @param sleepMs amount of time to sleep, in milliseconds * @throws InterruptedException can be interrupted */ diff --git a/utils/src/main/java/org/onap/policy/common/utils/validation/Assertions.java b/utils/src/main/java/org/onap/policy/common/utils/validation/Assertions.java index 047989e7..8e474204 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/validation/Assertions.java +++ b/utils/src/main/java/org/onap/policy/common/utils/validation/Assertions.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2016-2018 Ericsson. All rights reserved. * Modifications Copyright (C) 2019 Nordix Foundation. - * Modifications Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ package org.onap.policy.common.utils.validation; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,17 +31,12 @@ import org.slf4j.LoggerFactory; * The Class Assertions is a static class that is used as a shorthand for assertions in the source code. * It throws runtime exceptions on assertion fails. */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class Assertions { // Logger for this class private static final Logger LOGGER = LoggerFactory.getLogger(Assertions.class); /** - * Private constructor used to prevent sub class instantiation. - */ - private Assertions() { - } - - /** * Gets the validation message for a string parameter. * * @param parameterName the string parameter name diff --git a/utils/src/main/java/org/onap/policy/common/utils/validation/ParameterValidationUtils.java b/utils/src/main/java/org/onap/policy/common/utils/validation/ParameterValidationUtils.java index f15d936b..0723242d 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/validation/ParameterValidationUtils.java +++ b/utils/src/main/java/org/onap/policy/common/utils/validation/ParameterValidationUtils.java @@ -1,7 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2018 Ericsson. All rights reserved. - * Modifications Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,17 +21,17 @@ package org.onap.policy.common.utils.validation; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + /** * Class to provide utility methods for common parameter validations. * * @author Ram Krishna Verma (ram.krishna.verma@ericsson.com) */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class ParameterValidationUtils { - private ParameterValidationUtils() { - - } - /** * Validates the given string input. * diff --git a/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java b/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java index 41ff832a..46e006bd 100644 --- a/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java +++ b/utils/src/main/java/org/onap/policy/common/utils/validation/Version.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP COMMON * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2019 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,7 @@ package org.onap.policy.common.utils.validation; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.google.re2j.Pattern; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; @@ -56,14 +55,13 @@ public class Version implements Comparable<Version> { * @param versionString the version string */ public Version(@NonNull final String versionString) { - Version newVersion = makeVersion("String", "constructor", versionString); + var newVersion = makeVersion("String", "constructor", versionString); if (newVersion != null) { this.major = newVersion.major; this.minor = newVersion.minor; this.patch = newVersion.patch; - } - else { + } else { this.major = 0; this.minor = 0; this.patch = 0; @@ -80,7 +78,7 @@ public class Version implements Comparable<Version> { * that does not match the major.minor.patch form) */ public static Version makeVersion(String type, String name, String versionText) { - Matcher matcher = VERSION_PAT.matcher(versionText); + var matcher = VERSION_PAT.matcher(versionText); if (!matcher.matches()) { logger.info("invalid version for {} {}: {}", type, name, versionText); return null; @@ -114,7 +112,7 @@ public class Version implements Comparable<Version> { @Override public int compareTo(Version other) { - int result = Integer.compare(major, other.major); + var result = Integer.compare(major, other.major); if (result != 0) { return result; } |