diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java index 675fea458..ff919cf54 100644 --- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java +++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java @@ -460,7 +460,7 @@ private String buildHelpFooter() { if (subCommands.isEmpty()) { retval = ""; } else { - StringBuilder builder = new StringBuilder(64); + StringBuilder builder = new StringBuilder(128); builder .append(System.lineSeparator()) .append("The following are available commands:") @@ -553,9 +553,9 @@ protected String buildHelpCliSyntax() { builder.append('['); } - builder.append('<'); - builder.append(argument.getName()); - builder.append('>'); + builder.append('<') + .append(argument.getName()) + .append('>'); if (argument.getNumber() > 1) { builder.append("..."); diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java index 7c07f90f8..854c2a1ba 100644 --- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java +++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java @@ -31,7 +31,7 @@ default List getExtraArguments() { default int requiredExtraArgumentsCount() { return (int) getExtraArguments().stream() - .filter(arg -> arg.isRequired()) + .filter(ExtraArgument::isRequired) .count(); } diff --git a/cli-processor/src/test/java/gov/nist/secauto/metaschema/cli/processor/ExitCodeTest.java b/cli-processor/src/test/java/gov/nist/secauto/metaschema/cli/processor/ExitCodeTest.java index 2c6e81656..988e7f93b 100644 --- a/cli-processor/src/test/java/gov/nist/secauto/metaschema/cli/processor/ExitCodeTest.java +++ b/cli-processor/src/test/java/gov/nist/secauto/metaschema/cli/processor/ExitCodeTest.java @@ -20,8 +20,10 @@ import java.util.List; /** + * Manages the exit code of a command line process. + *

* Logging solution based on - * https://stackoverflow.com/questions/24205093/how-to-create-a-custom-appender-in-log4j2 + * https://stackoverflow.com/questions/24205093/how-to-create-a-custom-appender-in-log4j2. */ class ExitCodeTest { private static MockedAppender mockedAppender; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java index b488b2c97..48112f5ce 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java @@ -11,7 +11,8 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import edu.umd.cs.findbugs.annotations.NonNull; @@ -26,15 +27,16 @@ public abstract class AbstractDataTypeProvider implements IDataTypeProvider { @NonNull private final List> library = new LinkedList<>(); @NonNull - protected final Lock instanceLock = new ReentrantLock(); + private final ReadWriteLock libraryLock = new ReentrantReadWriteLock(); @Override public List> getJavaTypeAdapters() { + Lock readLock = libraryLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return CollectionUtil.unmodifiableList(library); } finally { - instanceLock.unlock(); + readLock.unlock(); } } @@ -50,11 +52,12 @@ protected void registerDatatype(@NonNull IDataTypeAdapter adapter) { if (adapter.getNames().isEmpty()) { throw new IllegalArgumentException("The adapter has no name: " + adapter.getClass().getName()); } + Lock writeLock = libraryLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); library.add(adapter); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java index 47deda27e..006a30a4f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java @@ -31,7 +31,7 @@ public class MarkupXmlEventWriter extends AbstractMarkupWriter { @NonNull - protected final XMLEventFactory2 eventFactory; + private final XMLEventFactory2 eventFactory; /** * Construct a new event writer. @@ -78,7 +78,7 @@ protected List handleAttributes(@NonNull Map attribut attrs = CollectionUtil.emptyList(); } else { attrs = ObjectUtils.notNull(attributes.entrySet().stream() - .map((entry) -> eventFactory.createAttribute(entry.getKey(), entry.getValue())) + .map(entry -> eventFactory.createAttribute(entry.getKey(), entry.getValue())) .collect(Collectors.toList())); } return attrs; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java index a4a8d3945..76a8a950e 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java @@ -265,7 +265,6 @@ protected abstract void writeElementStart( @SuppressWarnings({ "unchecked", - "unused", "PMD.UnusedPrivateMethod" }) // while unused, keeping code for when inline HTML is supported private void writeHtml(Node node) throws E { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java index f21642782..b84950188 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java @@ -355,7 +355,7 @@ protected T toResultType(@NonNull ISequence sequence, @NonNull ResultType throw new InvalidTypeMetapathException(null, String.format("unsupported result type '%s'", resultType.name())); } - return (T) result; + return ObjectUtils.asNullableType(result); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java index fa2643a19..b70e28cec 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java @@ -8,10 +8,16 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.tree.ParseTree; +import org.eclipse.jdt.annotation.NotOwning; import java.io.PrintStream; +import edu.umd.cs.findbugs.annotations.NonNull; + public class ParseTreePrinter { + @SuppressWarnings("resource") + @NotOwning + @NonNull private final PrintStream outputStream; private boolean ignoringWrappers = true; @@ -21,7 +27,7 @@ public class ParseTreePrinter { * @param outputStream * the stream to print to */ - public ParseTreePrinter(PrintStream outputStream) { + public ParseTreePrinter(@NotOwning @NonNull PrintStream outputStream) { this.outputStream = outputStream; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java index 84548f09f..d2a42003f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java @@ -314,10 +314,8 @@ protected IExpression handleArrayConstructor(CurlyarrayconstructorContext ctx) { // https://www.w3.org/TR/xpath-31/#id-unary-lookup // =============================================== - @Override - protected IExpression handleUnarylookup(UnarylookupContext ctx) { - KeyspecifierContext specifier = ctx.keyspecifier(); - + @NonNull + private IKeySpecifier toKeySpecifier(@NonNull KeyspecifierContext specifier) { IKeySpecifier keySpecifier; if (specifier.parenthesizedexpr() != null) { keySpecifier = AbstractKeySpecifier.newParenthesizedExprKeySpecifier( @@ -333,7 +331,12 @@ protected IExpression handleUnarylookup(UnarylookupContext ctx) { } else { throw new UnsupportedOperationException("unknown key specifier"); } - return new UnaryLookup(keySpecifier); + return keySpecifier; + } + + @Override + protected IExpression handleUnarylookup(UnarylookupContext ctx) { + return new UnaryLookup(toKeySpecifier(ObjectUtils.requireNonNull(ctx.keyspecifier()))); } // ========================================================= @@ -448,9 +451,7 @@ protected Stream parseArgumentList(@NonNull ArgumentlistContext con retval = Stream.empty(); } else { retval = context.argument().stream() - .map(argument -> { - return argument.exprsingle().accept(this); - }); + .map(argument -> argument.exprsingle().accept(this)); } assert retval != null; @@ -540,24 +541,9 @@ protected IExpression handlePostfixexpr(PostfixexprContext context) { left, CollectionUtil.singletonList(parsePredicate((PredicateContext) tree))); } else if (tree instanceof LookupContext) { - KeyspecifierContext specifier = ((LookupContext) tree).keyspecifier(); - - IKeySpecifier keySpecifier; - if (specifier.parenthesizedexpr() != null) { - keySpecifier = AbstractKeySpecifier.newParenthesizedExprKeySpecifier( - ObjectUtils.requireNonNull(specifier.parenthesizedexpr().accept(this))); - } else if (specifier.NCName() != null) { - keySpecifier = AbstractKeySpecifier.newNameKeySpecifier( - ObjectUtils.requireNonNull(specifier.NCName().getText())); - } else if (specifier.IntegerLiteral() != null) { - keySpecifier = AbstractKeySpecifier.newIntegerLiteralKeySpecifier( - IIntegerItem.valueOf(ObjectUtils.requireNonNull(specifier.IntegerLiteral().getText()))); - } else if (specifier.STAR() != null) { - keySpecifier = AbstractKeySpecifier.newWildcardKeySpecifier(); - } else { - throw new UnsupportedOperationException("unknown key specifier"); - } - result = new PostfixLookup(left, keySpecifier); + result = new PostfixLookup( + left, + toKeySpecifier(ObjectUtils.notNull(((LookupContext) tree).keyspecifier()))); } else { result = visit(tree); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java index d6a61fe6a..6d1b54e89 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java @@ -53,6 +53,8 @@ public ISequence accept( /** * Check the provided items to determine if each item matches the wildcard. All * items that match are returned. + *

+ * This is an intermediate stream operation. * * @param * the item Java type @@ -61,7 +63,7 @@ public ISequence accept( * @return the matching items */ @NonNull - public Stream match(@NonNull Stream items) { + public Stream match(@SuppressWarnings("resource") @NonNull Stream items) { Stream nodes = items; if (matcher != null) { Predicate> test = matcher; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java index d342f4105..559d20169 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java @@ -10,7 +10,8 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Stream; import javax.xml.namespace.QName; @@ -25,7 +26,7 @@ public class FunctionLibrary implements IFunctionLibrary { @NonNull private final Map libraryByName = new HashMap<>(); // NOPMD - intentional @NonNull - private final Lock instanceLock = new ReentrantLock(); + private final ReadWriteLock instanceLock = new ReentrantReadWriteLock(); /** * Register the provided function signature. @@ -44,8 +45,9 @@ public final void registerFunction(@NonNull IFunction function) { private void registerFunctionByQName(@NonNull IFunction function) { QName qname = function.getQName(); IFunction duplicate; + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); NamedFunctionSet functions = libraryByQName.get(qname); if (functions == null) { functions = new NamedFunctionSet(); @@ -53,7 +55,7 @@ private void registerFunctionByQName(@NonNull IFunction function) { } duplicate = functions.addFunction(function); } finally { - instanceLock.unlock(); + writeLock.unlock(); } if (duplicate != null) { throw new IllegalArgumentException(String.format("Duplicate functions with same arity: %s shadows %s", @@ -63,8 +65,9 @@ private void registerFunctionByQName(@NonNull IFunction function) { private void registerFunctionByName(@NonNull IFunction function) { String name = function.getName(); + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); NamedFunctionSet functions = libraryByName.get(name); if (functions == null) { functions = new NamedFunctionSet(); @@ -73,31 +76,33 @@ private void registerFunctionByName(@NonNull IFunction function) { // replace duplicates functions.addFunction(function); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } @Override public Stream stream() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return ObjectUtils.notNull(libraryByQName.values().stream().flatMap(NamedFunctionSet::getFunctionsAsStream)); } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public IFunction getFunction(@NonNull String name, int arity) { IFunction retval = null; + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); NamedFunctionSet functions = libraryByName.get(name); if (functions != null) { retval = functions.getFunctionWithArity(arity); } } finally { - instanceLock.unlock(); + readLock.unlock(); } return retval; } @@ -105,14 +110,15 @@ public IFunction getFunction(@NonNull String name, int arity) { @Override public IFunction getFunction(@NonNull QName name, int arity) { IFunction retval = null; + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); NamedFunctionSet functions = libraryByQName.get(name); if (functions != null) { retval = functions.getFunctionWithArity(arity); } } finally { - instanceLock.unlock(); + readLock.unlock(); } return retval; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java index a8bdfdcc9..2316be9e1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java @@ -10,8 +10,6 @@ import java.util.ServiceLoader; import java.util.ServiceLoader.Provider; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Stream; import javax.xml.namespace.QName; @@ -20,13 +18,11 @@ import nl.talsmasoftware.lazy4j.Lazy; public final class FunctionService { - private static final Lazy INSTANCE = Lazy.lazy(() -> new FunctionService()); + private static final Lazy INSTANCE = Lazy.lazy(FunctionService::new); @NonNull private final ServiceLoader loader; @NonNull private final Lazy library; - @NonNull - private final Lock instanceLock = new ReentrantLock(); /** * Get the singleton instance of the function service. @@ -93,13 +89,7 @@ public Stream stream() { * if a matching function was not found */ public IFunction getFunction(@NonNull String name, int arity) { - IFunction retval; - try { - instanceLock.lock(); - retval = getLibrary().getFunction(name, arity); - } finally { - instanceLock.unlock(); - } + IFunction retval = getLibrary().getFunction(name, arity); if (retval == null) { throw new StaticMetapathException(StaticMetapathException.NO_FUNCTION_MATCH, @@ -122,13 +112,7 @@ public IFunction getFunction(@NonNull String name, int arity) { * if a matching function was not found */ public IFunction getFunction(@NonNull QName name, int arity) { - IFunction retval; - try { - instanceLock.lock(); - retval = getLibrary().getFunction(name, arity); - } finally { - instanceLock.unlock(); - } + IFunction retval = getLibrary().getFunction(name, arity); if (retval == null) { throw new StaticMetapathException(StaticMetapathException.NO_FUNCTION_MATCH, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java index 620cdbcaa..c954c3ae5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java @@ -23,7 +23,9 @@ import edu.umd.cs.findbugs.annotations.NonNull; public final class ArrayInsertBefore { + @NonNull private static final String NAME = "insert-before"; + // CPD-OFF @NonNull static final IFunction SIGNATURE = IFunction.builder() .name(NAME) @@ -50,6 +52,7 @@ public final class ArrayInsertBefore { .returnOne() .functionHandler(ArrayInsertBefore::execute) .build(); + // CPD-ON private ArrayInsertBefore() { // disable construction diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java index ab755d494..635d2a692 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java @@ -24,7 +24,9 @@ import edu.umd.cs.findbugs.annotations.NonNull; public final class ArrayPut { + @NonNull private static final String NAME = "put"; + // CPD-OFF @NonNull static final IFunction SIGNATURE = IFunction.builder() .name(NAME) @@ -51,6 +53,7 @@ public final class ArrayPut { .returnOne() .functionHandler(ArrayPut::execute) .build(); + // CPD-ON private ArrayPut() { // disable construction diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java index 8a4dc878c..fae76ef42 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java @@ -22,7 +22,7 @@ import gov.nist.secauto.metaschema.core.metapath.item.atomic.IPositiveIntegerItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; -@SuppressWarnings({ "removal", "deprecation" }) +@SuppressWarnings({ "removal" }) @AutoService(IFunctionLibrary.class) public class DefaultFunctionLibrary extends FunctionLibrary { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java index 7f02b25e8..d6c0218a7 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java @@ -107,7 +107,7 @@ public static IStringItem concat(@NonNull List items) @NonNull public static IStringItem concat(@NonNull Stream items) { return IStringItem.valueOf(ObjectUtils.notNull(items - .map(item -> (item == null ? "" : IStringItem.cast(item).asString())) + .map(item -> item == null ? "" : IStringItem.cast(item).asString()) .collect(Collectors.joining()))); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnContains.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnContains.java index e8e614f80..594060607 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnContains.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnContains.java @@ -20,8 +20,9 @@ import edu.umd.cs.findbugs.annotations.NonNull; public final class FnContains { + // CPD-OFF + @NonNull private static final String NAME = "contains"; - @NonNull static final IFunction SIGNATURE = IFunction.builder() .name(NAME) @@ -42,6 +43,7 @@ public final class FnContains { .returnOne() .functionHandler(FnContains::execute) .build(); + // CPD-ON @SuppressWarnings("unused") @NonNull diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnEndsWith.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnEndsWith.java index 24234fe3e..d380721ec 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnEndsWith.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnEndsWith.java @@ -20,6 +20,8 @@ import edu.umd.cs.findbugs.annotations.NonNull; public final class FnEndsWith { + // CPD-OFF + @NonNull private static final String NAME = "ends-with"; @NonNull static final IFunction SIGNATURE = IFunction.builder() @@ -41,6 +43,7 @@ public final class FnEndsWith { .returnOne() .functionHandler(FnEndsWith::execute) .build(); + // CPD-ON @SuppressWarnings("unused") @NonNull diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMatches.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMatches.java index 86def66bc..d0c2bda7c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMatches.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMatches.java @@ -30,7 +30,9 @@ * "https://www.w3.org/TR/xpath-functions-31/#func-matches">fn:matches. */ public final class FnMatches { + @NonNull private static final String NAME = "matches"; + // CPD-OFF @NonNull static final IFunction SIGNATURE_TWO_ARG = IFunction.builder() .name(NAME) @@ -79,6 +81,7 @@ public final class FnMatches { .returnOne() .functionHandler(FnMatches::executeThreeArg) .build(); + // CPD-ON @NonNull private static ISequence executeTwoArg( diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java index 4fff7a058..1385e69bd 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java @@ -20,6 +20,8 @@ import edu.umd.cs.findbugs.annotations.NonNull; public final class FnStartsWith { + // CPD-OFF + @NonNull private static final String NAME = "starts-with"; @NonNull static final IFunction SIGNATURE = IFunction.builder() @@ -41,6 +43,7 @@ public final class FnStartsWith { .returnOne() .functionHandler(FnStartsWith::execute) .build(); + // CPD-ON @SuppressWarnings("unused") @NonNull diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTokenize.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTokenize.java index abe9285c1..89fd2710c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTokenize.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTokenize.java @@ -32,6 +32,8 @@ * "https://www.w3.org/TR/xpath-functions-31/#func-tokenize">fn:tokenize. */ public final class FnTokenize { + // CPD-OFF + @NonNull private static final String NAME = "tokenize"; @NonNull static final IFunction SIGNATURE_ONE_ARG = IFunction.builder() @@ -97,13 +99,15 @@ public final class FnTokenize { .returnZeroOrMore() .functionHandler(FnTokenize::executeThreeArg) .build(); + // CPD-ON + @SuppressWarnings({ "PMD.UnusedFormalParameter", "unused" }) @NonNull private static ISequence executeOneArg( - @SuppressWarnings("unused") @NonNull IFunction function, + @NonNull IFunction function, @NonNull List> arguments, - @SuppressWarnings("unused") @NonNull DynamicContext dynamicContext, - @SuppressWarnings("unused") IItem focus) { + @NonNull DynamicContext dynamicContext, + IItem focus) { IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); return input == null @@ -113,24 +117,26 @@ private static ISequence executeOneArg( .map(IStringItem::valueOf))); } + @SuppressWarnings({ "PMD.UnusedFormalParameter", "unused" }) @NonNull private static ISequence executeTwoArg( - @SuppressWarnings("unused") @NonNull IFunction function, + @NonNull IFunction function, @NonNull List> arguments, - @SuppressWarnings("unused") @NonNull DynamicContext dynamicContext, - @SuppressWarnings("unused") IItem focus) { + @NonNull DynamicContext dynamicContext, + IItem focus) { IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); IStringItem pattern = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true))); return execute(input, pattern, IStringItem.valueOf("")); } + @SuppressWarnings({ "PMD.UnusedFormalParameter", "unused" }) @NonNull private static ISequence executeThreeArg( - @SuppressWarnings("unused") @NonNull IFunction function, + @NonNull IFunction function, @NonNull List> arguments, - @SuppressWarnings("unused") @NonNull DynamicContext dynamicContext, - @SuppressWarnings("unused") IItem focus) { + @NonNull DynamicContext dynamicContext, + IItem focus) { IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); IStringItem pattern = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true))); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java index 789484f6c..2c92e0e41 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java @@ -87,12 +87,11 @@ private enum Duplicates { USE_FIRST("use-first", (key, v1, v2) -> v1), USE_LAST("use-last", (key, v1, v2) -> v2), USE_ANY("use-any", (key, v1, v2) -> RANDOM.nextBoolean() ? v1 : v2), - @SuppressWarnings("null") + @SuppressWarnings("checkstyle:Indentation") COMBINE( "combine", - (key, v1, v2) -> Stream.concat( - v1.asSequence().stream(), - v2.asSequence().stream()).collect(ISequence.toSequence())); + (key, v1, v2) -> Stream.concat(v1.asSequence().stream(), v2.asSequence().stream()) + .collect(ISequence.toSequence())); private static final Map BY_NAME; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java index 33e2e14ce..20bcf6d3b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java @@ -48,8 +48,8 @@ public abstract class AbstractMapItem /** * Get an immutable map item that is empty. * - * @param - * the item Java type + * @param + * the Java type of the collection value * @return the empty map item */ diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/DefaultItemWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/DefaultItemWriter.java index 321ee4942..83c6a7ac8 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/DefaultItemWriter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/DefaultItemWriter.java @@ -12,6 +12,8 @@ import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import org.eclipse.jdt.annotation.Owning; + import java.io.PrintWriter; import edu.umd.cs.findbugs.annotations.NonNull; @@ -21,6 +23,7 @@ */ public class DefaultItemWriter implements IItemWriter { + @Owning @NonNull private final PrintWriter writer; @NonNull @@ -121,6 +124,11 @@ protected void writeCollectionValue(@NonNull ICollectionValue value) { } } + @Override + public void close() throws Exception { + writer.close(); + } + private final class Visitor implements IItemVisitor { @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItemWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItemWriter.java index d96146500..54a416a3b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItemWriter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItemWriter.java @@ -13,7 +13,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public interface IItemWriter { +public interface IItemWriter extends AutoCloseable { /** * Write the provided sequence instance. * diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java index 065b3fae8..7b922704d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java @@ -12,7 +12,6 @@ import gov.nist.secauto.metaschema.core.metapath.function.IArgument; import gov.nist.secauto.metaschema.core.metapath.function.IFunction; import gov.nist.secauto.metaschema.core.metapath.function.ISequenceType; -import gov.nist.secauto.metaschema.core.metapath.impl.AbstractArrayItem; import gov.nist.secauto.metaschema.core.metapath.impl.AbstractMapItem; import gov.nist.secauto.metaschema.core.metapath.impl.MapItemN; import gov.nist.secauto.metaschema.core.metapath.item.IItem; @@ -50,12 +49,12 @@ static IMapItem empty() { @Override default QName getQName() { - return AbstractArrayItem.QNAME; + return AbstractMapItem.QNAME; } @Override default Set getProperties() { - return AbstractArrayItem.PROPERTIES; + return AbstractMapItem.PROPERTIES; } @Override @@ -75,7 +74,7 @@ default boolean isFocusDepenent() { @Override default List getArguments() { - return AbstractArrayItem.ARGUMENTS; + return AbstractMapItem.ARGUMENTS; } @Override @@ -90,7 +89,7 @@ default boolean isArityUnbounded() { @Override default ISequenceType getResult() { - return AbstractArrayItem.RESULT; + return AbstractMapItem.RESULT; } @Override @@ -721,7 +720,8 @@ IMapItem ofEntries(Map.Entry... entries) { } /** - * Returns an unmodifiable {@link Entry} containing the given key and value. + * Returns an unmodifiable {@link java.util.Map.Entry} containing the given key + * and value. * * @param * the value's type @@ -739,7 +739,8 @@ static Map.Entry entry(@NonNull IAnyAto } /** - * Returns an unmodifiable {@link Entry} containing the given key and value. + * Returns an unmodifiable {@link java.util.Map.Entry} containing the given key + * and value. * * @param * the value's type diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionNodeItem.java index 44b8a6715..b71d5da5f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionNodeItem.java @@ -15,7 +15,7 @@ * @param * the type of the instance that could be created from the definition */ -interface IFeatureOrhpanedDefinitionNodeItem +public interface IFeatureOrhpanedDefinitionNodeItem extends IDefinitionNodeItem { @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractModule.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractModule.java index 3035b1165..429cf8a1c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractModule.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractModule.java @@ -130,7 +130,7 @@ public A getExportedRootAssemblyDefinitionByName(QName name) { @SuppressWarnings({ "unused", "PMD.UnusedPrivateMethod" }) // used by lambda private static DEF handleShadowedDefinitions( - @SuppressWarnings("unused") @NonNull QName key, + @NonNull QName key, @NonNull DEF oldDef, @NonNull DEF newDef) { if (!oldDef.equals(newDef) && LOGGER.isInfoEnabled()) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java index 14ca3b307..0ac063366 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java @@ -248,7 +248,7 @@ protected String newMatchDatatypeViolationMessage( @NonNull protected String newExpectViolationMessage( @NonNull IExpectConstraint constraint, - @SuppressWarnings("unused") @NonNull INodeItem node, + @NonNull INodeItem node, @NonNull INodeItem target, @NonNull DynamicContext dynamicContext) { String message; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyConstraintSet.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyConstraintSet.java index 5aad04a9a..e1db8ac0b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyConstraintSet.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyConstraintSet.java @@ -7,6 +7,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.concurrent.locks.Lock; import edu.umd.cs.findbugs.annotations.NonNull; @@ -27,65 +28,70 @@ public class AssemblyConstraintSet @Override public List getIndexConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return indexConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public List getUniqueConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return uniqueConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public List getHasCardinalityConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return cardinalityConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public final void addConstraint(@NonNull IIndexConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); getConstraints().add(constraint); indexConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } @Override public final void addConstraint(@NonNull IUniqueConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); getConstraints().add(constraint); uniqueConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } @Override public final void addConstraint(@NonNull ICardinalityConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); getConstraints().add(constraint); cardinalityConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } - } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ValueConstraintSet.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ValueConstraintSet.java index 4e6a94880..ff57c416d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ValueConstraintSet.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ValueConstraintSet.java @@ -10,7 +10,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.xml.namespace.QName; @@ -31,7 +32,7 @@ public class ValueConstraintSet implements IValueConstrained { // NOPMD - intent @NonNull private final List expectConstraints = new LinkedList<>(); @NonNull - protected final Lock instanceLock = new ReentrantLock(); + protected final ReadWriteLock instanceLock = new ReentrantReadWriteLock(); @Override public Map getLetExpressions() { @@ -45,95 +46,104 @@ public ILet addLetExpression(ILet let) { @Override public List getConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return constraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public List getAllowedValuesConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return allowedValuesConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public List getMatchesConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return matchesConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public List getIndexHasKeyConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return indexHasKeyConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public List getExpectConstraints() { + Lock readLock = instanceLock.readLock(); try { - instanceLock.lock(); + readLock.lock(); return expectConstraints; } finally { - instanceLock.unlock(); + readLock.unlock(); } } @Override public final void addConstraint(@NonNull IAllowedValuesConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); constraints.add(constraint); allowedValuesConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } @Override public final void addConstraint(@NonNull IMatchesConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); constraints.add(constraint); matchesConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } @Override public final void addConstraint(@NonNull IIndexHasKeyConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); constraints.add(constraint); indexHasKeyConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } @Override public final void addConstraint(@NonNull IExpectConstraint constraint) { + Lock writeLock = instanceLock.writeLock(); try { - instanceLock.lock(); + writeLock.lock(); constraints.add(constraint); expectConstraints.add(constraint); } finally { - instanceLock.unlock(); + writeLock.unlock(); } } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ExternalConstraintsModulePostProcessor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ExternalConstraintsModulePostProcessor.java index 86eb66bc6..942530299 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ExternalConstraintsModulePostProcessor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ExternalConstraintsModulePostProcessor.java @@ -17,6 +17,14 @@ public class ExternalConstraintsModulePostProcessor extends gov.nist.secauto.metaschema.core.model.constraint.ExternalConstraintsModulePostProcessor { + /** + * This implementation has been moved to + * {@link gov.nist.secauto.metaschema.core.model.constraint.ExternalConstraintsModulePostProcessor}, + * which should be used instead. + * + * @param additionalConstraintSets + * constraints to configure + */ public ExternalConstraintsModulePostProcessor(@NonNull Collection additionalConstraintSets) { super(additionalConstraintSets); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/util/AutoCloser.java b/core/src/main/java/gov/nist/secauto/metaschema/core/util/AutoCloser.java index 1e9501360..2fe4f35e2 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/util/AutoCloser.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/util/AutoCloser.java @@ -5,6 +5,12 @@ package gov.nist.secauto.metaschema.core.util; +import org.eclipse.jdt.annotation.Owning; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -17,7 +23,7 @@ * the exception type that may be thrown if an error occurs when * closing the resource */ -public class AutoCloser implements AutoCloseable { +public final class AutoCloser implements AutoCloseable { @NonNull private final T resource; @NonNull @@ -37,6 +43,7 @@ public class AutoCloser implements AutoCloseable { * the lambda to use as a callback on close * @return the resource wrapped in an {@link AutoCloseable} */ + @Owning @NonNull public static AutoCloser autoClose( @NonNull T resource, @@ -53,7 +60,7 @@ public static AutoCloser autoClose( * @param lambda * the lambda to use as a callback on close */ - public AutoCloser(@NonNull T resource, @NonNull Closer lambda) { + private AutoCloser(@NonNull T resource, @NonNull Closer lambda) { this.resource = resource; this.closeLambda = lambda; } @@ -87,4 +94,34 @@ public interface Closer { @SuppressFBWarnings("THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION") void close(@NonNull T object) throws E; } + + /** + * Wraps the provided output stream to prevent the wrapped stream from being + * closed. + *

+ * This is useful for protecting standard streams. i.e. {@link System#out}, + * {@link System#err}. + * + * @param out + * the stream to wrap + * @return the new wrapped stream + */ + @Owning + @NonNull + public static OutputStream preventClose(OutputStream out) { + return new ClosePreventingOutputStream(out); + } + + private static class ClosePreventingOutputStream + extends FilterOutputStream { + + public ClosePreventingOutputStream(OutputStream out) { + super(out); + } + + @Override + public void close() throws IOException { + // do nothing + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/util/MermaidErDiagramGenerator.java b/core/src/main/java/gov/nist/secauto/metaschema/core/util/MermaidErDiagramGenerator.java index 6519e12cd..b81229175 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/util/MermaidErDiagramGenerator.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/util/MermaidErDiagramGenerator.java @@ -88,12 +88,13 @@ public static void generate(@NonNull IModule module, @NonNull PrintWriter writer private static final class MermaidNodeVistor implements IDiagramNodeVisitor { @NonNull private final DiagramNodeModelVisitor nodeVisitor; + @SuppressWarnings("resource") @NonNull private final PrintWriter writer; private MermaidNodeVistor( @NonNull DiagramNodeModelVisitor nodeVisitor, - @NonNull PrintWriter writer) { + @NotOwning @NonNull PrintWriter writer) { this.nodeVisitor = nodeVisitor; this.writer = writer; } @@ -142,7 +143,6 @@ public void visit(DefaultDiagramNode.ChoiceGroupEdge edge) { "ChoiceGroup: " + edge.getInstance().getEffectiveDisciminatorValue() + ": " + instance.getEffectiveName()); } - @SuppressWarnings("resource") private void writeRelationship( @NonNull IDiagramNode left, @NonNull IDiagramNode right, diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index baa726659..aed00870f 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -9,6 +9,13 @@ import gov.nist.secauto.metaschema.core.metapath.function.IFunctionLibrary; import gov.nist.secauto.metaschema.core.metapath.function.library.DefaultFunctionLibrary; +/** + * @provides IDataTypeProvider for core built-in data types + * @provides IFunctionLibrary for core built-in Metapath functions + * @uses IDataTypeProvider to discover data types implementing {@link IDataTypeAdapter} + * @uses IFunctionLibrary to discover collections of Metapath functions implementing + * {@link IFunction} + */ module gov.nist.secauto.metaschema.core { // requirements requires java.base; diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapterTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapterTest.java index 8463e0b8a..367d1aa40 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapterTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapterTest.java @@ -9,11 +9,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -21,26 +19,19 @@ class BooleanAdapterTest { private static final String TEST_JSON = "{ \"some-boolean\" : true }"; - private BooleanAdapter adapter; - private JsonParser parser; - - @BeforeEach - void initParser() throws JsonParseException, IOException { // NOPMD - adapter = new BooleanAdapter(); - JsonFactory factory = new JsonFactory(); - parser = factory.createParser(TEST_JSON); - } - @Test void testParse() throws IOException { - // skip to the value - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - - Boolean obj = adapter.parse(parser); - assertAll( - () -> assertTrue(obj, "object is not true"), - () -> assertTrue(JsonToken.END_OBJECT.equals(parser.currentToken()), "token is not at end object")); + JsonFactory factory = new JsonFactory(); + try (JsonParser parser = factory.createParser(TEST_JSON)) { + // skip to the value + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + + Boolean obj = new BooleanAdapter().parse(parser); + assertAll( + () -> assertTrue(obj, "object is not true"), + () -> assertTrue(JsonToken.END_OBJECT.equals(parser.currentToken()), "token is not at end object")); + } } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessorTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessorTest.java index 01bda57a4..b10ddfea0 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessorTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessorTest.java @@ -10,7 +10,6 @@ import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IModule; import gov.nist.secauto.metaschema.core.model.MetaschemaException; -import gov.nist.secauto.metaschema.core.model.xml.ExternalConstraintsModulePostProcessor; import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader; import gov.nist.secauto.metaschema.core.model.xml.XmlMetaConstraintLoader; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -28,10 +27,12 @@ class ExternalConstraintsModulePostProcessorTest { @Test void test() throws MetaschemaException, IOException { - IModule module = new ModuleLoader().load(Paths.get("src/test/resources/content/issue184-metaschema.xml")); + IModule module = new ModuleLoader().load(ObjectUtils.notNull( + Paths.get("src/test/resources/content/issue184-metaschema.xml"))); List constraints - = new XmlMetaConstraintLoader().load(Paths.get("src/test/resources/content/issue184-constraints.xml")); + = new XmlMetaConstraintLoader().load(ObjectUtils.notNull( + Paths.get("src/test/resources/content/issue184-constraints.xml"))); new ExternalConstraintsModulePostProcessor(constraints).processModule(module); diff --git a/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java b/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java index 45e0c5234..51ff594c3 100644 --- a/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java +++ b/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java @@ -55,6 +55,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +@SuppressWarnings("PMD.CouplingBetweenObjects") public final class SarifValidationHandler { private enum Kind { NOT_APPLICABLE("notApplicable"), @@ -100,13 +101,13 @@ public String getLabel() { public static final String SARIF_NS = "https://docs.oasis-open.org/sarif/sarif/v2.1.0"; @NonNull public static final IAttributable.Key SARIF_HELP_URL_KEY - = IAttributable.key("help-url", SarifValidationHandler.SARIF_NS); + = IAttributable.key("help-url", SARIF_NS); @NonNull public static final IAttributable.Key SARIF_HELP_TEXT_KEY - = IAttributable.key("help-text", SarifValidationHandler.SARIF_NS); + = IAttributable.key("help-text", SARIF_NS); @NonNull public static final IAttributable.Key SARIF_HELP_MARKDOWN_KEY - = IAttributable.key("help-markdown", SarifValidationHandler.SARIF_NS); + = IAttributable.key("help-markdown", SARIF_NS); @NonNull private final URI source; @@ -114,10 +115,13 @@ public String getLabel() { private final IVersionInfo toolVersion; private final AtomicInteger artifactIndex = new AtomicInteger(-1); private final AtomicInteger ruleIndex = new AtomicInteger(-1); + + @SuppressWarnings("PMD.UseConcurrentHashMap") @NonNull private final Map artifacts = new LinkedHashMap<>(); @NonNull private final List rules = new LinkedList<>(); + @SuppressWarnings("PMD.UseConcurrentHashMap") @NonNull private final Map constraintRules = new LinkedHashMap<>(); @NonNull @@ -137,7 +141,8 @@ public SarifValidationHandler( this.toolVersion = toolVersion; } - public URI getSource() { + @NonNull + private URI getSource() { return source; } @@ -164,14 +169,6 @@ public void addFinding(@NonNull IValidationFinding finding) { } } - public URI relativize(@NonNull URI output, @NonNull URI artifact) throws IOException { - try { - return UriUtils.relativize(output, artifact, true); - } catch (URISyntaxException ex) { - throw new IOException(ex); - } - } - private ConstraintRuleRecord getRuleRecord(@NonNull IConstraint constraint) { ConstraintRuleRecord retval = constraintRules.get(constraint); if (retval == null) { @@ -222,7 +219,7 @@ public void write(@NonNull Path outputFile) throws IOException { Artifact artifact = new Artifact(); - artifact.setLocation(getArtifactRecord(source).generateArtifactLocation(output)); + artifact.setLocation(getArtifactRecord(getSource()).generateArtifactLocation(output)); run.addArtifact(artifact); @@ -230,11 +227,11 @@ public void write(@NonNull Path outputFile) throws IOException { result.generateResults(output).forEach(run::addResult); } + IVersionInfo toolVersion = getToolVersion(); if (!rules.isEmpty() || toolVersion != null) { Tool tool = new Tool(); ToolComponent driver = new ToolComponent(); - IVersionInfo toolVersion = getToolVersion(); if (toolVersion != null) { driver.setName(toolVersion.getName()); driver.setVersion(toolVersion.getVersion()); @@ -428,7 +425,7 @@ public List generateResults(@NonNull URI output) throws IOException { assert constraint != null; ConstraintRuleRecord rule = getRuleRecord(constraint); - Result result = new Result(); + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") Result result = new Result(); String id = constraint.getId(); if (id != null) { @@ -579,7 +576,13 @@ public int getIndex() { public ArtifactLocation generateArtifactLocation(@NonNull URI baseUri) throws IOException { ArtifactLocation location = new ArtifactLocation(); - location.setUri(relativize(baseUri, getUri())); + + try { + location.setUri(UriUtils.relativize(baseUri, getUri(), true)); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + location.setIndex(BigInteger.valueOf(getIndex())); return location; } diff --git a/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java b/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java index be0a88a9b..9dce9a8d1 100644 --- a/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java +++ b/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java @@ -14,6 +14,7 @@ import gov.nist.secauto.metaschema.core.model.constraint.IConstraint; import gov.nist.secauto.metaschema.core.model.validation.IValidationFinding; import gov.nist.secauto.metaschema.core.util.IVersionInfo; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import org.jmock.Expectations; import org.jmock.junit5.JUnit5Mockery; @@ -46,11 +47,11 @@ class SarifValidationHandlerTest { void testValid() throws IOException { IVersionInfo versionInfo = context.mock(IVersionInfo.class); - IConstraint constraintA = context.mock(IConstraint.class, "constraintA"); - INodeItem node = context.mock(INodeItem.class); + IConstraint constraintA = ObjectUtils.notNull(context.mock(IConstraint.class, "constraintA")); + INodeItem node = ObjectUtils.notNull(context.mock(INodeItem.class)); IResourceLocation location = context.mock(IResourceLocation.class); - Path sourceFile = Paths.get(".", "source.json").toAbsolutePath(); + Path sourceFile = ObjectUtils.requireNonNull(Paths.get(".", "source.json").toAbsolutePath()); Set helpUrls = Set.of("https://example.com/test"); Set helpMarkdown = Set.of("**help text**"); @@ -101,14 +102,14 @@ void testValid() throws IOException { }); SarifValidationHandler handler - = new SarifValidationHandler(sourceFile.toUri(), versionInfo); + = new SarifValidationHandler(ObjectUtils.notNull(sourceFile.toUri()), versionInfo); handler.addFinding(ConstraintValidationFinding.builder(constraintA, node) .kind(IValidationFinding.Kind.FAIL) .build()); // no need to cleanup this file, since it is created in the target directory - Path sarifFile = Paths.get("target/test.sarif"); + Path sarifFile = ObjectUtils.requireNonNull(Paths.get("target/test.sarif")); handler.write(sarifFile); Path sarifSchema = Paths.get("modules/sarif/sarif-schema-2.1.0.json"); @@ -121,19 +122,15 @@ void testValid() throws IOException { Validator.Result result = new ValidatorFactory().withDialect(new Dialects.Draft2020Dialect()).validate(schemaNode, instanceNode); - if (!result.isValid()) { - StringJoiner sj = new StringJoiner("\n"); - for (dev.harrel.jsonschema.Error finding : result.getErrors()) { - sj.add(String.format("[%s]%s %s for schema '%s'", - finding.getInstanceLocation(), - finding.getKeyword() == null ? "" : " " + finding.getKeyword() + ":", - finding.getError(), - finding.getSchemaLocation())); - } - assertTrue(result.isValid(), () -> "SARIF output failed schema validation. Errors:\n" + sj.toString()); - } else { - assertTrue(result.isValid()); + StringJoiner sj = new StringJoiner("\n"); + for (dev.harrel.jsonschema.Error finding : result.getErrors()) { + sj.add(String.format("[%s]%s %s for schema '%s'", + finding.getInstanceLocation(), + finding.getKeyword() == null ? "" : " " + finding.getKeyword() + ":", + finding.getError(), + finding.getSchemaLocation())); } + assertTrue(result.isValid(), () -> "SARIF output failed schema validation. Errors:\n" + sj.toString()); } } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/DefaultBindingContext.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/DefaultBindingContext.java index 87e9b05bb..b5df3d6ad 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/DefaultBindingContext.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/DefaultBindingContext.java @@ -42,6 +42,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import nl.talsmasoftware.lazy4j.Lazy; /** * The implementation of a {@link IBindingContext} provided by this library. @@ -57,8 +58,9 @@ *

* This class is synchronized and is thread-safe. */ +@SuppressWarnings("PMD.CouplingBetweenObjects") public class DefaultBindingContext implements IBindingContext { - private static DefaultBindingContext singleton; + private static Lazy singleton = Lazy.lazy(DefaultBindingContext::new); @NonNull private final IModuleLoaderStrategy moduleLoaderStrategy; @NonNull @@ -73,12 +75,7 @@ public class DefaultBindingContext implements IBindingContext { */ @NonNull public static DefaultBindingContext instance() { - synchronized (DefaultBindingContext.class) { - if (singleton == null) { - singleton = new DefaultBindingContext(); - } - } - return ObjectUtils.notNull(singleton); + return ObjectUtils.notNull(singleton.get()); } /** diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/PostProcessingModuleLoaderStrategy.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/PostProcessingModuleLoaderStrategy.java index 7d55410f8..0449042dc 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/PostProcessingModuleLoaderStrategy.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/PostProcessingModuleLoaderStrategy.java @@ -15,6 +15,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import edu.umd.cs.findbugs.annotations.NonNull; @@ -23,6 +25,7 @@ class PostProcessingModuleLoaderStrategy @NonNull private final List modulePostProcessors; private final Set resolvedModules = new HashSet<>(); + private final Lock resolvedModulesLock = new ReentrantLock(); protected PostProcessingModuleLoaderStrategy( @NonNull IBindingContext bindingContext, @@ -42,12 +45,16 @@ public IBoundDefinitionModelComplex getBoundDefinitionForClass(@NonNull Class, IBoundModule> modulesByClass = new ConcurrentHashMap<>(); + private final Lock modulesLock = new ReentrantLock(); @NonNull private final Map, IBoundDefinitionModelComplex> definitionsByClass = new ConcurrentHashMap<>(); + private final Lock definitionsLock = new ReentrantLock(); protected SimpleModuleLoaderStrategy(@NonNull IBindingContext bindingContext) { this.bindingContext = bindingContext; @@ -41,12 +45,15 @@ private IBindingContext getBindingContext() { @Override public IBoundModule loadModule(@NonNull Class clazz) { IBoundModule retval; - synchronized (this) { + try { + modulesLock.lock(); retval = modulesByClass.get(clazz); if (retval == null) { retval = AbstractBoundModule.createInstance(clazz, getBindingContext()); modulesByClass.put(clazz, retval); } + } finally { + modulesLock.unlock(); } return ObjectUtils.notNull(retval); } @@ -54,7 +61,8 @@ public IBoundModule loadModule(@NonNull Class clazz) { @Override public IBoundDefinitionModelComplex getBoundDefinitionForClass(@NonNull Class clazz) { IBoundDefinitionModelComplex retval; - synchronized (this) { + try { + definitionsLock.lock(); retval = definitionsByClass.get(clazz); if (retval == null) { retval = newBoundDefinition(clazz); @@ -62,6 +70,8 @@ public IBoundDefinitionModelComplex getBoundDefinitionForClass(@NonNull Class implements ITypeInfo { @NonNull private final PARENT parentDefinition; - private String propertyName; - private String fieldName; + private final Lazy propertyName; + private final Lazy fieldName; protected AbstractTypeInfo(@NonNull PARENT parentDefinition) { this.parentDefinition = parentDefinition; + this.propertyName = Lazy.lazy(() -> { + String baseName = ClassUtils.toPropertyName(getBaseName()); + IDefinitionTypeInfo parent = getParentTypeInfo(); + + // first check if a property already exists with the same name + return parent.getTypeResolver().getPropertyName(parent, baseName); + }); + this.fieldName = Lazy.lazy(() -> "_" + ClassUtils.toVariableName(getPropertyName())); } @Override @@ -35,16 +44,7 @@ public PARENT getParentTypeInfo() { @Override @NonNull public String getPropertyName() { - synchronized (this) { - if (this.propertyName == null) { - String name = ClassUtils.toPropertyName(getBaseName()); - IDefinitionTypeInfo parent = getParentTypeInfo(); - - // first check if a property already exists with the same name - this.propertyName = parent.getTypeResolver().getPropertyName(parent, name); - } - return ObjectUtils.notNull(this.propertyName); - } + return ObjectUtils.notNull(propertyName.get()); } /** @@ -55,11 +55,6 @@ public String getPropertyName() { @Override @NonNull public final String getJavaFieldName() { - synchronized (this) { - if (this.fieldName == null) { - this.fieldName = "_" + ClassUtils.toVariableName(getPropertyName()); - } - return ObjectUtils.notNull(this.fieldName); - } + return ObjectUtils.notNull(fieldName.get()); } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/typeinfo/DefaultTypeResolver.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/typeinfo/DefaultTypeResolver.java index 8f0702923..24e702936 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/typeinfo/DefaultTypeResolver.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/typeinfo/DefaultTypeResolver.java @@ -35,20 +35,27 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import edu.umd.cs.findbugs.annotations.NonNull; +@SuppressWarnings("PMD.CouplingBetweenObjects") class DefaultTypeResolver implements ITypeResolver { private static final Logger LOGGER = LogManager.getLogger(DefaultTypeResolver.class); private final Map> packageToClassNamesMap = new ConcurrentHashMap<>(); + private final Lock classNameLock = new ReentrantLock(); + private final Map definitionToTypeMap = new ConcurrentHashMap<>(); private final Map moduleToTypeMap = new ConcurrentHashMap<>(); private final Map assemblyDefinitionToTypeInfoMap = new ConcurrentHashMap<>(); private final Map fieldDefinitionToTypeInfoMap = new ConcurrentHashMap<>(); + + private final Lock propertyNameLock = new ReentrantLock(); private final Map> typeInfoToPropertyNameMap = new ConcurrentHashMap<>(); @NonNull @@ -186,27 +193,47 @@ public ClassName getClassName(IModule module) { String className = getBindingConfiguration().getClassName(mod); String classNameBase = className; int index = 1; - while (isClassNameClash(packageName, className)) { - className = classNameBase + Integer.toString(index); + try { + classNameLock.lock(); + while (isClassNameClash(packageName, className)) { + className = classNameBase + Integer.toString(index); + } + addClassName(packageName, className); + } finally { + classNameLock.unlock(); } - addClassName(packageName, className); return ClassName.get(packageName, className); })); } @NonNull protected Set getClassNamesFor(@NonNull String packageOrTypeName) { - return ObjectUtils.notNull(packageToClassNamesMap.computeIfAbsent( - packageOrTypeName, - pkg -> Collections.synchronizedSet(new LinkedHashSet<>()))); + try { + classNameLock.lock(); + return ObjectUtils.notNull(packageToClassNamesMap.computeIfAbsent( + packageOrTypeName, + pkg -> Collections.synchronizedSet(new LinkedHashSet<>()))); + } finally { + classNameLock.unlock(); + } } protected boolean isClassNameClash(@NonNull String packageOrTypeName, @NonNull String className) { - return getClassNamesFor(packageOrTypeName).contains(className); + try { + classNameLock.lock(); + return getClassNamesFor(packageOrTypeName).contains(className); + } finally { + classNameLock.unlock(); + } } protected boolean addClassName(@NonNull String packageOrTypeName, @NonNull String className) { - return getClassNamesFor(packageOrTypeName).add(className); + try { + classNameLock.lock(); + return getClassNamesFor(packageOrTypeName).add(className); + } finally { + classNameLock.unlock(); + } } private String generateClassName( @@ -214,9 +241,10 @@ private String generateClassName( @NonNull String suggestedClassName, @NonNull IModelDefinition definition) { @NonNull String retval = suggestedClassName; - Set classNames = getClassNamesFor(packageOrTypeName); - synchronized (classNames) { - boolean clash = false; + boolean clash = false; + try { + classNameLock.lock(); + Set classNames = getClassNamesFor(packageOrTypeName); if (classNames.contains(suggestedClassName)) { clash = true; // first try to append the metaschema's short name @@ -230,15 +258,17 @@ private String generateClassName( retval = classNameBase + Integer.toString(index++); } classNames.add(retval); + } finally { + classNameLock.unlock(); + } - if (clash && LOGGER.isWarnEnabled()) { - LOGGER.warn(String.format( - "Class name '%s', based on '%s' in '%s', clashes with another bound class. Using '%s' instead.", - suggestedClassName, - definition.getName(), - definition.getContainingModule().getLocation(), - retval)); - } + if (clash && LOGGER.isWarnEnabled()) { + LOGGER.warn(String.format( + "Class name '%s', based on '%s' in '%s', clashes with another bound class. Using '%s' instead.", + suggestedClassName, + definition.getName(), + definition.getContainingModule().getLocation(), + retval)); } return retval; } @@ -269,11 +299,10 @@ public String getPackageName(@NonNull IModule module) { @Override @NonNull public String getPropertyName(IDefinitionTypeInfo parent, String name) { - synchronized (typeInfoToPropertyNameMap) { - Set propertyNames = typeInfoToPropertyNameMap.get(parent); - if (propertyNames == null) { - propertyNames = new HashSet<>(); - } + + try { + propertyNameLock.lock(); + Set propertyNames = typeInfoToPropertyNameMap.computeIfAbsent(parent, key -> new HashSet<>()); String retval = name; int index = 0; @@ -283,6 +312,8 @@ public String getPropertyName(IDefinitionTypeInfo parent, String name) { } propertyNames.add(retval); return retval; + } finally { + propertyNameLock.unlock(); } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/AbstractDeserializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/AbstractDeserializer.java index 29e29dbdb..f33f711a6 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/AbstractDeserializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/AbstractDeserializer.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.Reader; import java.net.URI; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import edu.umd.cs.findbugs.annotations.NonNull; @@ -35,6 +37,7 @@ public abstract class AbstractDeserializer implements IDeserializer { private IConstraintValidationHandler constraintValidationHandler; + private final Lock handlerLock = new ReentrantLock(); /** * Construct a new deserializer. @@ -56,18 +59,24 @@ protected AbstractDeserializer(@NonNull IBoundDefinitionModelAssembly definition @Override @NonNull public IConstraintValidationHandler getConstraintValidationHandler() { - synchronized (this) { + try { + handlerLock.lock(); if (constraintValidationHandler == null) { constraintValidationHandler = new LoggingConstraintValidationHandler(); } return ObjectUtils.notNull(constraintValidationHandler); + } finally { + handlerLock.unlock(); } } @Override public void setConstraintValidationHandler(@NonNull IConstraintValidationHandler constraintValidationHandler) { - synchronized (this) { + try { + handlerLock.lock(); this.constraintValidationHandler = constraintValidationHandler; + } finally { + handlerLock.unlock(); } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/ModelDetector.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/ModelDetector.java index 5546bbafa..411e7f762 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/ModelDetector.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/ModelDetector.java @@ -229,6 +229,7 @@ public InputStream getDataStream() { return ObjectUtils.requireNonNull(dataStream, "data stream already closed"); } + @SuppressWarnings("PMD.NullAssignment") @Override public void close() throws IOException { this.dataStream.close(); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonDeserializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonDeserializer.java index 86edc99ab..4dd1a7cb0 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonDeserializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonDeserializer.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.JsonParser; import gov.nist.secauto.metaschema.core.configuration.IConfiguration; +import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory; import gov.nist.secauto.metaschema.core.model.IBoundObject; @@ -22,10 +23,11 @@ import java.net.URI; import edu.umd.cs.findbugs.annotations.NonNull; +import nl.talsmasoftware.lazy4j.Lazy; public class DefaultJsonDeserializer extends AbstractDeserializer { - private JsonFactory jsonFactory; + private Lazy factory; /** * Construct a new JSON deserializer that will parse the bound class identified @@ -37,6 +39,17 @@ public class DefaultJsonDeserializer */ public DefaultJsonDeserializer(@NonNull IBoundDefinitionModelAssembly definition) { super(definition); + resetFactory(); + } + + protected final void resetFactory() { + this.factory = Lazy.lazy(this::newFactoryInstance); + } + + @Override + protected void configurationChanged(IMutableConfiguration> config) { + super.configurationChanged(config); + resetFactory(); } /** @@ -48,7 +61,7 @@ public DefaultJsonDeserializer(@NonNull IBoundDefinitionModelAssembly definition * @return the factory */ @NonNull - protected JsonFactory newJsonFactoryInstance() { + protected JsonFactory newFactoryInstance() { return JsonFactoryFactory.instance(); } @@ -59,13 +72,7 @@ protected JsonFactory newJsonFactoryInstance() { */ @NonNull protected JsonFactory getJsonFactory() { - synchronized (this) { - if (jsonFactory == null) { - jsonFactory = newJsonFactoryInstance(); - } - assert jsonFactory != null; - return jsonFactory; - } + return ObjectUtils.notNull(factory.get()); } /** @@ -96,7 +103,9 @@ protected INodeItem deserializeToNodeItemInternal(@NonNull Reader reader, @NonNu if (definition.isRoot() && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) { // now parse the root property - CLASS value = ObjectUtils.requireNonNull(parser.readObjectRoot(definition, definition.getRootJsonName())); + CLASS value = ObjectUtils.requireNonNull(parser.readObjectRoot( + definition, + ObjectUtils.notNull(definition.getRootJsonName()))); retval = INodeItemFactory.instance().newDocumentNodeItem(definition, documentUri, value); } else { @@ -121,7 +130,9 @@ public CLASS deserializeToValueInternal(@NonNull Reader reader, @NonNull URI doc && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) { // now parse the root property - retval = ObjectUtils.requireNonNull(parser.readObjectRoot(definition, definition.getRootJsonName())); + retval = ObjectUtils.requireNonNull(parser.readObjectRoot( + definition, + ObjectUtils.notNull(definition.getRootJsonName()))); } else { // read the top-level definition retval = ObjectUtils.asType(ObjectUtils.requireNonNull( diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonSerializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonSerializer.java index fcf4a327b..5982e8c1e 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonSerializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonSerializer.java @@ -20,10 +20,11 @@ import java.io.Writer; import edu.umd.cs.findbugs.annotations.NonNull; +import nl.talsmasoftware.lazy4j.Lazy; public class DefaultJsonSerializer extends AbstractSerializer { - private JsonFactory jsonFactory; + private Lazy factory; /** * Construct a new Module binding-based deserializer that reads JSON-based @@ -35,6 +36,17 @@ public class DefaultJsonSerializer */ public DefaultJsonSerializer(@NonNull IBoundDefinitionModelAssembly definition) { super(definition); + resetFactory(); + } + + protected final void resetFactory() { + this.factory = Lazy.lazy(this::newFactoryInstance); + } + + @Override + protected void configurationChanged(IMutableConfiguration> config) { + super.configurationChanged(config); + resetFactory(); } /** @@ -46,27 +58,13 @@ public DefaultJsonSerializer(@NonNull IBoundDefinitionModelAssembly definition) * @return the factory */ @NonNull - protected JsonFactory getJsonFactoryInstance() { + protected JsonFactory newFactoryInstance() { return JsonFactoryFactory.instance(); } - @SuppressWarnings("PMD.NullAssignment") - @Override - protected void configurationChanged(IMutableConfiguration> config) { - synchronized (this) { - jsonFactory = null; - } - } - @NonNull private JsonFactory getJsonFactory() { - synchronized (this) { - if (jsonFactory == null) { - jsonFactory = getJsonFactoryInstance(); - } - assert jsonFactory != null; - return jsonFactory; - } + return ObjectUtils.notNull(factory.get()); } @SuppressWarnings("resource") diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonReader.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonReader.java index 935a00c6a..00e2fb9f0 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonReader.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonReader.java @@ -39,6 +39,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.eclipse.jdt.annotation.NotOwning; import java.io.IOException; import java.util.Collection; @@ -103,6 +104,7 @@ public MetaschemaJsonReader( } @SuppressWarnings("resource") + @NotOwning @Override public JsonParser getReader() { return ObjectUtils.notNull(parserStack.peek()); @@ -230,7 +232,7 @@ private Object readInstance( return instance.readItem(parent, this); } - @NonNull + @Nullable private Object readModelInstance( @NonNull IBoundInstanceModel instance, @NonNull IBoundObject parent) throws IOException { @@ -245,6 +247,7 @@ private Object readFieldValue( return instance.readItem(parent, this); } + @Nullable private Object readObjectProperty( @NonNull IBoundObject parent, @NonNull IBoundProperty property) throws IOException { @@ -405,7 +408,7 @@ private IBoundObject readComplexDefinitionObject( ? bodyHandler : new JsonKeyBodyHandler(jsonKey, bodyHandler); - JsonLocation location = getReader().currentLocation(); + @SuppressWarnings("resource") JsonLocation location = getReader().currentLocation(); // construct the item IBoundObject item = definition.newInstance( @@ -546,7 +549,9 @@ public void accept( parser.nextToken(); Object value = readObjectProperty(parent, property); - property.setValue(parent, value); + if (value != null) { + property.setValue(parent, value); + } // mark handled remainingInstances.remove(propertyName); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonWriter.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonWriter.java index 6ac5b5a32..225bd0234 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonWriter.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonWriter.java @@ -35,6 +35,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; +@SuppressWarnings("PMD.CouplingBetweenObjects") public class MetaschemaJsonWriter implements IJsonWritingContext, IItemWriteHandler { @NonNull private final JsonGenerator generator; @@ -96,6 +97,7 @@ private void writeModelInstance( } } + @SuppressWarnings("PMD.NullAssignment") private void writeFieldValue(@NonNull IBoundFieldValue fieldValue, @NonNull Object parentItem) throws IOException { Object item = fieldValue.getValue(parentItem); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlDeserializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlDeserializer.java index d57ee54ea..a49ae4763 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlDeserializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlDeserializer.java @@ -7,6 +7,7 @@ import com.ctc.wstx.stax.WstxInputFactory; +import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration; import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory; import gov.nist.secauto.metaschema.core.model.IBoundObject; @@ -31,10 +32,11 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import nl.talsmasoftware.lazy4j.Lazy; public class DefaultXmlDeserializer extends AbstractDeserializer { - private XMLInputFactory2 xmlInputFactory; + private Lazy factory; @NonNull private final IBoundDefinitionModelAssembly rootDefinition; @@ -55,59 +57,65 @@ public DefaultXmlDeserializer(@NonNull IBoundDefinitionModelAssembly definition) throw new UnsupportedOperationException( String.format("The assembly '%s' is not a root assembly.", definition.getBoundClass().getName())); } + resetFactory(); + } + + protected final void resetFactory() { + this.factory = Lazy.lazy(this::newFactoryInstance); + } + + @Override + protected void configurationChanged(IMutableConfiguration> config) { + super.configurationChanged(config); + resetFactory(); } /** - * Get the XML input factory instance used to create XML parser instances. + * Get a JSON factory instance. *

- * Uses a built-in default if a user specified factory is not provided. + * This method can be used by sub-classes to create a customized factory + * instance. * - * @return the factory instance - * @see #setXMLInputFactory(XMLInputFactory2) + * @return the factory */ @NonNull - private XMLInputFactory2 getXMLInputFactory() { - - synchronized (this) { - if (xmlInputFactory == null) { - xmlInputFactory = (XMLInputFactory2) XMLInputFactory.newInstance(); - assert xmlInputFactory instanceof WstxInputFactory; - xmlInputFactory.configureForXmlConformance(); - xmlInputFactory.setProperty(XMLInputFactory.IS_COALESCING, false); - xmlInputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, true); - // xmlInputFactory.configureForSpeed(); - - if (isFeatureEnabled(DeserializationFeature.DESERIALIZE_XML_ALLOW_ENTITY_RESOLUTION)) { - xmlInputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true); - xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true); - xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, true); - xmlInputFactory.setProperty(XMLInputFactory.RESOLVER, - (XMLResolver) (publicID, systemID, baseURI, namespace) -> { - URI base = URI.create(baseURI); - URI resource = base.resolve(systemID); - try { - return resource.toURL().openStream(); - } catch (IOException ex) { - throw new XMLStreamException(ex); - } - }); - } - } - return ObjectUtils.notNull(xmlInputFactory); + protected XMLInputFactory2 newFactoryInstance() { + XMLInputFactory2 retval = (XMLInputFactory2) XMLInputFactory.newInstance(); + assert retval instanceof WstxInputFactory; + retval.configureForXmlConformance(); + retval.setProperty(XMLInputFactory.IS_COALESCING, false); + retval.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, true); + // xmlInputFactory.configureForSpeed(); + + if (isFeatureEnabled(DeserializationFeature.DESERIALIZE_XML_ALLOW_ENTITY_RESOLUTION)) { + retval.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true); + retval.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true); + retval.setProperty(XMLInputFactory.SUPPORT_DTD, true); + retval.setProperty(XMLInputFactory.RESOLVER, + (XMLResolver) (publicID, systemID, baseURI, namespace) -> { + URI base = URI.create(baseURI); + URI resource = base.resolve(systemID); + try { + return resource.toURL().openStream(); + } catch (IOException ex) { + throw new XMLStreamException(ex); + } + }); } + return retval; } /** - * Provide a XML input factory instance that will be used to create XML parser - * instances. + * Get the XML input factory instance used to create XML parser instances. + *

+ * Uses a built-in default if a user specified factory is not provided. * - * @param factory - * the factory instance + * @return the factory instance + * @see #setXMLInputFactory(XMLInputFactory2) */ - protected void setXMLInputFactory(@NonNull XMLInputFactory2 factory) { - synchronized (this) { - this.xmlInputFactory = factory; - } + @NonNull + private XMLInputFactory2 getXMLInputFactory() { + return ObjectUtils.notNull(factory.get()); } @NonNull @@ -129,7 +137,7 @@ protected final IDocumentNodeItem deserializeToNodeItemInternal(Reader reader, U @Override public final CLASS deserializeToValueInternal(Reader reader, URI documentUri) throws IOException { // doesn't auto close the underlying reader - try (AutoCloser closer = new AutoCloser<>( + try (AutoCloser closer = AutoCloser.autoClose( newXMLEventReader2(documentUri, reader), XMLEventReader::close)) { return parseXmlInternal(closer.getResource()); } catch (XMLStreamException ex) { diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlProblemHandler.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlProblemHandler.java index 11d0a7bbc..d2dcbc6d5 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlProblemHandler.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlProblemHandler.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.model.IBoundObject; import gov.nist.secauto.metaschema.core.model.util.XmlEventUtil; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.databind.io.AbstractProblemHandler; import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex; @@ -51,7 +52,7 @@ public boolean handleUnknownAttribute( if (LOGGER.isWarnEnabled() && !IGNORED_QNAMES.contains(qname)) { LOGGER.atWarn().log("Skipping unrecognized attribute '{}'{}.", qname, - XmlEventUtil.generateLocationMessage(attribute.getLocation())); + XmlEventUtil.generateLocationMessage(ObjectUtils.notNull(attribute.getLocation()))); } // always ignore return true; diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlSerializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlSerializer.java index 824807707..34a7372a7 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlSerializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlSerializer.java @@ -8,6 +8,7 @@ import com.ctc.wstx.api.WstxOutputProperties; import com.ctc.wstx.stax.WstxOutputFactory; +import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration; import gov.nist.secauto.metaschema.core.model.IBoundObject; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.databind.io.AbstractSerializer; @@ -24,10 +25,11 @@ import javax.xml.stream.XMLStreamException; import edu.umd.cs.findbugs.annotations.NonNull; +import nl.talsmasoftware.lazy4j.Lazy; public class DefaultXmlSerializer extends AbstractSerializer { - private XMLOutputFactory2 xmlOutputFactory; + private Lazy factory; /** * Construct a new XML serializer based on the top-level assembly indicated by @@ -39,40 +41,46 @@ public class DefaultXmlSerializer */ public DefaultXmlSerializer(@NonNull IBoundDefinitionModelAssembly definition) { super(definition); + resetFactory(); + } + + protected final void resetFactory() { + this.factory = Lazy.lazy(this::newFactoryInstance); + } + + @Override + protected void configurationChanged(IMutableConfiguration> config) { + super.configurationChanged(config); + resetFactory(); } /** - * Get the configured XML output factory used to create {@link XMLStreamWriter2} - * instances. + * Get a JSON factory instance. + *

+ * This method can be used by sub-classes to create a customized factory + * instance. * * @return the factory */ @NonNull - protected final XMLOutputFactory2 getXMLOutputFactory() { - synchronized (this) { - if (xmlOutputFactory == null) { - xmlOutputFactory = (XMLOutputFactory2) XMLOutputFactory.newInstance(); - assert xmlOutputFactory instanceof WstxOutputFactory; - xmlOutputFactory.configureForSpeed(); - xmlOutputFactory.setProperty(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true); - xmlOutputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); - } - assert xmlOutputFactory != null; - return xmlOutputFactory; - } + protected XMLOutputFactory2 newFactoryInstance() { + XMLOutputFactory2 retval = (XMLOutputFactory2) XMLOutputFactory.newInstance(); + assert retval instanceof WstxOutputFactory; + retval.configureForSpeed(); + retval.setProperty(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true); + retval.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); + return retval; } /** - * Override the default {@link XMLOutputFactory2} instance with a custom - * factory. + * Get the configured XML output factory used to create {@link XMLStreamWriter2} + * instances. * - * @param xmlOutputFactory - * the new factory + * @return the factory */ - protected void setXMLOutputFactory(@NonNull XMLOutputFactory2 xmlOutputFactory) { - synchronized (this) { - this.xmlOutputFactory = xmlOutputFactory; - } + @NonNull + protected final XMLOutputFactory2 getXMLOutputFactory() { + return ObjectUtils.notNull(factory.get()); } /** diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlDeserializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlDeserializer.java index f410040d6..0578ae677 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlDeserializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlDeserializer.java @@ -37,7 +37,7 @@ public DefaultYamlDeserializer(@NonNull IBoundDefinitionModelAssembly definition * @return the factory */ @Override - protected YAMLFactory newJsonFactoryInstance() { + protected YAMLFactory newFactoryInstance() { return YamlFactoryFactory.newParserFactoryInstance(getConfiguration()); } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlSerializer.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlSerializer.java index 8babf0813..84e9ee35b 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlSerializer.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/io/yaml/DefaultYamlSerializer.java @@ -30,7 +30,7 @@ public DefaultYamlSerializer(@NonNull IBoundDefinitionModelAssembly definition) } @Override - protected JsonFactory getJsonFactoryInstance() { + protected JsonFactory newFactoryInstance() { return YamlFactoryFactory.newGeneratorFactoryInstance(getConfiguration()); } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/IBoundDefinitionModelFieldComplex.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/IBoundDefinitionModelFieldComplex.java index 8845a1642..0c482ddd6 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/IBoundDefinitionModelFieldComplex.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/IBoundDefinitionModelFieldComplex.java @@ -89,6 +89,7 @@ default IDataTypeAdapter getJavaTypeAdapter() { return getFieldValue().getJavaTypeAdapter(); } + @SuppressWarnings("PMD.NullAssignment") @Override @NonNull default Map> getJsonProperties(@Nullable Predicate flagFilter) { diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/ModelUtil.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/ModelUtil.java index ac2d5830e..0d3bbd559 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/ModelUtil.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/ModelUtil.java @@ -12,7 +12,6 @@ import gov.nist.secauto.metaschema.core.model.IBoundObject; import gov.nist.secauto.metaschema.core.model.IMetaschemaData; import gov.nist.secauto.metaschema.core.model.IModule; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.databind.IBindingContext; import gov.nist.secauto.metaschema.databind.model.IGroupAs; import gov.nist.secauto.metaschema.databind.model.impl.DefaultGroupAs; @@ -171,6 +170,8 @@ public static MarkupMultiline resolveToMarkupMultiline(@NonNull String value) { * @param bindingContext * the Metaschema binding context used to lookup the data type adapter * @return the data type adapter + * @throws IllegalArgumentException + * if the provided adapter is not registered with the binding context */ @NonNull public static IDataTypeAdapter getDataTypeAdapter( @@ -180,7 +181,10 @@ public static IDataTypeAdapter getDataTypeAdapter( if (NullJavaTypeAdapter.class.equals(adapterClass)) { retval = MetaschemaDataTypeProvider.DEFAULT_DATA_TYPE; } else { - retval = ObjectUtils.requireNonNull(bindingContext.getJavaTypeAdapterInstance(adapterClass)); + retval = bindingContext.getJavaTypeAdapterInstance(adapterClass); + if (retval == null) { + throw new IllegalArgumentException("Unable to get type adapter instance for class: " + adapterClass.getName()); + } } return retval; } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/binding/metaschema/MetaschemaModelModule.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/binding/metaschema/MetaschemaModelModule.java index 11c9356e0..e97d247c8 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/binding/metaschema/MetaschemaModelModule.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/binding/metaschema/MetaschemaModelModule.java @@ -85,7 +85,7 @@ public final class MetaschemaModelModule private static final Map NAMESPACE_BINDINGS; static { - Map bindings = new LinkedHashMap<>(); + @SuppressWarnings("PMD.UseConcurrentHashMap") Map bindings = new LinkedHashMap<>(); NAMESPACE_BINDINGS = bindings; } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java index ebe6c3b92..56d58ce49 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java @@ -37,9 +37,6 @@ import gov.nist.secauto.metaschema.databind.model.annotations.NullJavaTypeAdapter; import gov.nist.secauto.metaschema.databind.model.annotations.Property; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; @@ -52,8 +49,6 @@ import edu.umd.cs.findbugs.annotations.Nullable; final class ConstraintFactory { - private static final Logger LOGGER = LogManager.getLogger(ConstraintFactory.class); - private ConstraintFactory() { // disable } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/info/IModelInstanceCollectionInfo.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/info/IModelInstanceCollectionInfo.java index e5271e407..668974bdc 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/info/IModelInstanceCollectionInfo.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/info/IModelInstanceCollectionInfo.java @@ -152,11 +152,12 @@ default Collection getItemsFromParentInstance(@NonNull Object pa * * @param handler * the item parsing handler - * @return the item collection object + * @return the item collection object or {@code null} if the instance is not + * defined * @throws IOException * if there was an error when reading the data */ - @NonNull + @Nullable Object readItems(@NonNull IModelInstanceReadHandler handler) throws IOException; void writeItems( diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoader.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoader.java index 4f606ddb2..7d7d1c228 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoader.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoader.java @@ -27,14 +27,13 @@ import java.util.stream.Collectors; import edu.umd.cs.findbugs.annotations.NonNull; +import nl.talsmasoftware.lazy4j.Lazy; public class BindingModuleLoader extends AbstractModuleLoader implements IMutableConfiguration> { - @NonNull - private final IBindingContext bindingContext; - private IBoundLoader loader; + private final Lazy loader; /** * Construct a new Metaschema loader. @@ -60,7 +59,7 @@ public BindingModuleLoader( @NonNull IBindingContext bindingContext, @NonNull List modulePostProcessors) { super(modulePostProcessors); - this.bindingContext = bindingContext; + this.loader = Lazy.lazy(bindingContext::newBoundLoader); } @Override @@ -91,12 +90,7 @@ protected METASCHEMA parseModule(URI resource) throws IOException { } protected IBoundLoader getLoader() { - synchronized (this) { - if (this.loader == null) { - this.loader = bindingContext.newBoundLoader(); - } - return this.loader; - } + return ObjectUtils.notNull(loader.get()); } @Override diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/AssemblyModelContainerSupport.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/AssemblyModelContainerSupport.java index e5c153f24..c995d6170 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/AssemblyModelContainerSupport.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/AssemblyModelContainerSupport.java @@ -123,6 +123,8 @@ protected AssemblyModelContainerSupport( IBoundInstanceModelChoiceGroup instance = ObjectUtils.requireNonNull( modelInstance.getDefinition().getChoiceGroupInstanceByName("instances")); for (Object obj : ObjectUtils.notNull(model.getInstances())) { + assert obj != null; + IBoundInstanceModelGroupedAssembly objInstance = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/BindingModule.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/BindingModule.java index 7e564d5f2..d3216d784 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/BindingModule.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/BindingModule.java @@ -40,6 +40,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import nl.talsmasoftware.lazy4j.Lazy; +@SuppressWarnings("PMD.CouplingBetweenObjects") public class BindingModule extends AbstractModule< IBindingMetaschemaModule, @@ -120,7 +121,7 @@ public IModuleNodeItem getModuleNodeItem() { @Override public final StaticContext getModuleStaticContext() { - return staticContext.get(); + return ObjectUtils.notNull(staticContext.get()); } @Override @@ -269,6 +270,7 @@ private final class Definitions { @NonNull private final Map rootAssemblyDefinitions; + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") private Definitions( @NonNull URI resource, @NonNull IBoundDefinitionModelAssembly rootDefinition, @@ -288,6 +290,8 @@ private Definitions( rootDefinition.getChoiceGroupInstanceByName("definitions")); for (Object obj : binding.getDefinitions()) { + assert obj != null : "Object was null"; + IBoundInstanceModelGroupedAssembly objInstance = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceGroupModelContainerSupport.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceGroupModelContainerSupport.java index 1d69410ee..7db650a97 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceGroupModelContainerSupport.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceGroupModelContainerSupport.java @@ -99,6 +99,8 @@ public ChoiceGroupModelContainerSupport( IBoundInstanceModelChoiceGroup instance = ObjectUtils.requireNonNull( bindingInstance.getDefinition().getChoiceGroupInstanceByName("choices")); for (Object obj : ObjectUtils.notNull(binding.getChoices())) { + assert obj != null; + IBoundInstanceModelGroupedAssembly objInstance = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceModelContainerSupport.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceModelContainerSupport.java index 70d24b816..ed3baa834 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceModelContainerSupport.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceModelContainerSupport.java @@ -100,6 +100,7 @@ public ChoiceModelContainerSupport( IBoundInstanceModelChoiceGroup instance = ObjectUtils.requireNonNull( bindingInstance.getDefinition().getChoiceGroupInstanceByName("choices")); for (Object obj : ObjectUtils.notNull(binding.getChoices())) { + assert obj != null; IBoundInstanceModelGroupedAssembly objInstance = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/FlagContainerSupport.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/FlagContainerSupport.java index d23c9ad2e..a32a49981 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/FlagContainerSupport.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/FlagContainerSupport.java @@ -50,6 +50,7 @@ public static IContainerFlagSupport newFlagContainer( IBoundInstanceModelChoiceGroup instance = ObjectUtils.requireNonNull( bindingInstance.getDefinition().getChoiceGroupInstanceByName("flags")); for (Object obj : flags) { + assert obj != null; IBoundInstanceModelGroupedAssembly objInstance = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj); diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/AbstractMetaschemaTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/AbstractMetaschemaTest.java index 1dc143345..7ca5eb90c 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/AbstractMetaschemaTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/AbstractMetaschemaTest.java @@ -32,6 +32,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +@SuppressWarnings("PMD.AbstractClassWithoutAbstractMethod") abstract class AbstractMetaschemaTest { private static final BindingModuleLoader LOADER = new BindingModuleLoader(new DefaultBindingContext()); diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/BasicMetaschemaTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/BasicMetaschemaTest.java index c85fc8cca..2e71ce94b 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/BasicMetaschemaTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/BasicMetaschemaTest.java @@ -5,7 +5,10 @@ package gov.nist.secauto.metaschema.databind.codegen; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -27,7 +30,6 @@ import gov.nist.secauto.metaschema.databind.model.metaschema.BindingModuleLoader; import gov.nist.secauto.metaschema.databind.model.metaschema.IBindingMetaschemaModule; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.platform.commons.util.ReflectionUtils; @@ -99,53 +101,53 @@ void testFieldsWithFlagMetaschema() ObjectUtils.notNull(generationDir), obj -> { try { - Assertions.assertEquals("test", reflectMethod(obj, "getId")); + assertEquals("test", reflectMethod(obj, "getId")); Object field1 = ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexField1"), obj); - Assertions.assertNotNull(field1); - Assertions.assertEquals("complex-field1", reflectMethod(field1, "getId")); - Assertions.assertEquals("test-string", reflectMethod(field1, "getValue")); + assertNotNull(field1); + assertEquals("complex-field1", reflectMethod(field1, "getId")); + assertEquals("test-string", reflectMethod(field1, "getValue")); @SuppressWarnings("unchecked") List field2s = (List) ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexFields2"), obj); - Assertions.assertNotNull(field2s); - Assertions.assertEquals(1, field2s.size()); + assertNotNull(field2s); + assertEquals(1, field2s.size()); Object field2 = field2s.get(0); - Assertions.assertEquals("complex-field2-1", reflectMethod(field2, "getId")); - Assertions.assertEquals("test-string2", reflectMethod(field2, "getValue")); + assertEquals("complex-field2-1", reflectMethod(field2, "getId")); + assertEquals("test-string2", reflectMethod(field2, "getValue")); @SuppressWarnings("unchecked") List field3s = (List) ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexFields3"), obj); - Assertions.assertEquals(2, field3s.size()); - Assertions.assertAll("ComplexFields4 item", () -> { + assertEquals(2, field3s.size()); + assertAll("ComplexFields4 item", () -> { Object item = field3s.get(0); assertEquals("complex-field3-1", reflectMethod(item, "getId2")); assertEquals("test-string3", reflectMethod(item, "getValue")); }); - Assertions.assertAll("ComplexFields4 item", () -> { + assertAll("ComplexFields4 item", () -> { Object item = field3s.get(1); assertEquals("complex-field3-2", reflectMethod(item, "getId2")); assertEquals("test-string4", reflectMethod(item, "getValue")); }); - Assertions.assertAll("ComplexFields4", () -> { + assertAll("ComplexFields4", () -> { @SuppressWarnings("unchecked") Map collection = (Map) ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexFields4"), obj); - Assertions.assertNotNull(collection); - Assertions.assertEquals(2, collection.size()); + assertNotNull(collection, "ComplexFields4 collection is null"); + assertEquals(2, collection.size(), "ComplexFields4 collection is not size 2"); Set> entries = collection.entrySet(); Iterator> iter = entries.iterator(); - Assertions.assertAll("ComplexFields4 item", () -> { + assertAll("ComplexFields4 item", () -> { Map.Entry entry = iter.next(); assertEquals("complex-field4-1", entry.getKey()); assertEquals("complex-field4-1", reflectMethod(entry.getValue(), "getId2")); assertEquals("test-string5", reflectMethod(entry.getValue(), "getValue")); }); - Assertions.assertAll("ComplexFields4 item", () -> { + assertAll("ComplexFields4 item", () -> { Map.Entry entry = iter.next(); assertEquals("complex-field4-2", entry.getKey()); assertEquals("complex-field4-2", reflectMethod(entry.getValue(), "getId2")); @@ -153,7 +155,7 @@ void testFieldsWithFlagMetaschema() }); }); } catch (NoSuchMethodException | SecurityException e) { - Assertions.fail(e); + fail(e); } }); } @@ -167,9 +169,9 @@ void testAssemblyMetaschema() ObjectUtils.notNull(generationDir), obj -> { try { - Assertions.assertEquals("test", reflectMethod(obj, "getId")); + assertEquals("test", reflectMethod(obj, "getId")); } catch (NoSuchMethodException | SecurityException e) { - Assertions.fail(e); + fail(e); } }); } @@ -240,8 +242,8 @@ void codegenTest() throws MetaschemaException, IOException { { BindingConstraintLoader constraintLoader = new BindingConstraintLoader(new DefaultBindingContext()); - constraints = constraintLoader.load( - Paths.get("../core/metaschema/schema/metaschema/metaschema-module-constraints.xml")); + constraints = constraintLoader.load(ObjectUtils.notNull( + Paths.get("../core/metaschema/schema/metaschema/metaschema-module-constraints.xml"))); } IBindingContext bindingContext = new DefaultBindingContext( @@ -249,9 +251,10 @@ void codegenTest() throws MetaschemaException, IOException { BindingModuleLoader loader = new BindingModuleLoader(bindingContext); IBindingMetaschemaModule module - = loader.load(Paths.get("../core/metaschema/schema/metaschema/metaschema-module-metaschema.xml")); + = loader.load(ObjectUtils.notNull( + Paths.get("../core/metaschema/schema/metaschema/metaschema-module-metaschema.xml"))); - Path compilePath = Paths.get("target/compile"); + Path compilePath = ObjectUtils.notNull(Paths.get("target/compile")); Files.createDirectories(compilePath); ClassLoader classLoader = ModuleCompilerHelper.newClassLoader( @@ -270,7 +273,8 @@ void codegenTest() throws MetaschemaException, IOException { .forEachOrdered(clazz -> { IBoundModule boundModule = bindingContext.registerModule(ObjectUtils.notNull(clazz)); // force the binding matchers to load - boundModule.getRootAssemblyDefinitions(); + assertFalse(boundModule.getRootAssemblyDefinitions().isEmpty()); }); + } } diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/GenerationTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/GenerationTest.java index 388e6aa7a..a30879dbd 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/GenerationTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/GenerationTest.java @@ -30,7 +30,9 @@ void testOscalBindingModuleLoader() throws MetaschemaException, IOException { loader.set(DeserializationFeature.DESERIALIZE_XML_ALLOW_ENTITY_RESOLUTION, true); IBindingMetaschemaModule module = loader.load(ObjectUtils.notNull(URI.create( "https://raw.githubusercontent.com/usnistgov/OSCAL/main/src/metaschema/oscal_complete_metaschema.xml"))); - IBindingContext context = IBindingContext.instance().registerModule(module, Paths.get("target/oscal-classes")); + IBindingContext context = IBindingContext.instance().registerModule( + module, + ObjectUtils.notNull(Paths.get("target/oscal-classes"))); assertAll( () -> assertNotNull(module), () -> assertNotNull(context)); diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/io/json/JsonParserTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/io/json/JsonParserTest.java index 214a4f3d8..5a3e72b16 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/io/json/JsonParserTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/io/json/JsonParserTest.java @@ -10,6 +10,7 @@ import gov.nist.secauto.metaschema.core.model.IMetaschemaModule; import gov.nist.secauto.metaschema.core.model.MetaschemaException; import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.databind.IBindingContext; import gov.nist.secauto.metaschema.databind.io.DeserializationFeature; import gov.nist.secauto.metaschema.databind.io.IBoundLoader; @@ -26,14 +27,18 @@ class JsonParserTest void testIssue308Regression() throws IOException, MetaschemaException { ModuleLoader moduleLoader = new ModuleLoader(); IMetaschemaModule module - = moduleLoader.load(Paths.get("src/test/resources/metaschema/308-choice-regression/metaschema.xml")); + = moduleLoader.load(ObjectUtils.notNull( + Paths.get("src/test/resources/metaschema/308-choice-regression/metaschema.xml"))); IBindingContext context = IBindingContext.instance(); - context.registerModule(module, Paths.get("target/generated-test-sources/308-choice-regression")); + context.registerModule( + module, + ObjectUtils.notNull(Paths.get("target/generated-test-sources/308-choice-regression"))); IBoundLoader loader = context.newBoundLoader(); loader.enableFeature(DeserializationFeature.DESERIALIZE_VALIDATE_CONSTRAINTS); - Object obj = loader.load(Paths.get("src/test/resources/metaschema/308-choice-regression/example.json")); + Object obj = loader.load(ObjectUtils.notNull( + Paths.get("src/test/resources/metaschema/308-choice-regression/example.json"))); assertNotNull(obj); } } diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/DefaultFieldPropertyTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/DefaultFieldPropertyTest.java index cb0f99ce6..4cd7fd797 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/DefaultFieldPropertyTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/DefaultFieldPropertyTest.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.core.JsonParser; import gov.nist.secauto.metaschema.core.model.IModule; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.databind.IBindingContext; import gov.nist.secauto.metaschema.databind.io.json.MetaschemaJsonReader; import gov.nist.secauto.metaschema.databind.model.test.MultiFieldAssembly; @@ -56,7 +57,9 @@ void testJsonReadFlag() MetaschemaJsonReader parser = new MetaschemaJsonReader(jsonParser); - SimpleAssembly obj = parser.readObjectRoot(classBinding, classBinding.getRootJsonName()); + SimpleAssembly obj = parser.readObjectRoot( + classBinding, + ObjectUtils.requireNonNull(classBinding.getRootJsonName())); assert obj != null; assertAll( diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoaderTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoaderTest.java index 237e0ab59..482f9a07e 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoaderTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingModuleLoaderTest.java @@ -6,6 +6,7 @@ package gov.nist.secauto.metaschema.databind.model.metaschema; import gov.nist.secauto.metaschema.core.model.MetaschemaException; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.databind.DefaultBindingContext; import org.junit.jupiter.api.Test; @@ -20,6 +21,7 @@ void test() throws MetaschemaException, IOException { BindingModuleLoader loader = new BindingModuleLoader(new DefaultBindingContext()); loader.allowEntityResolution(); - loader.load(Paths.get("src/test/resources/test-content/legacy-metaschema-data-types-module.xml")); + loader.load(ObjectUtils.notNull( + Paths.get("src/test/resources/test-content/legacy-metaschema-data-types-module.xml"))); } } diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/test/util/CloseDetectingInputStream.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/test/util/CloseDetectingInputStream.java index 0bfbd73b4..d963647cb 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/test/util/CloseDetectingInputStream.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/test/util/CloseDetectingInputStream.java @@ -5,6 +5,8 @@ package gov.nist.secauto.metaschema.databind.test.util; +import org.eclipse.jdt.annotation.NotOwning; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -14,6 +16,8 @@ public class CloseDetectingInputStream extends InputStream { + @SuppressWarnings("resource") + @NotOwning private final InputStream delegate; private boolean closed; @@ -24,7 +28,7 @@ public class CloseDetectingInputStream * @param delegate * the underlying input stream */ - public CloseDetectingInputStream(@NonNull InputStream delegate) { + public CloseDetectingInputStream(@NotOwning @NonNull InputStream delegate) { this.delegate = delegate; } @@ -84,20 +88,14 @@ public void close() throws IOException { closed = true; } - @SuppressWarnings("sync-override") @Override public void mark(int readlimit) { - synchronized (delegate) { - delegate.mark(readlimit); - } + delegate.mark(readlimit); } - @SuppressWarnings("sync-override") @Override public void reset() throws IOException { - synchronized (delegate) { - delegate.reset(); - } + delegate.reset(); } @Override @@ -124,5 +122,4 @@ public boolean equals(Object obj) { public String toString() { return delegate.toString(); } - } diff --git a/databind/src/test/java/gov/nist/secauto/metaschema/databind/testing/model/ModelTest.java b/databind/src/test/java/gov/nist/secauto/metaschema/databind/testing/model/ModelTest.java index 09c64f2e0..a3c893fef 100644 --- a/databind/src/test/java/gov/nist/secauto/metaschema/databind/testing/model/ModelTest.java +++ b/databind/src/test/java/gov/nist/secauto/metaschema/databind/testing/model/ModelTest.java @@ -429,9 +429,9 @@ void parseJsonMinimal() throws IOException { IBindingContext context = new DefaultBindingContext(); String json = new StringBuilder() - .append("{") + .append('{') .append(" \"root-assembly-with-fields\": { }") - .append("}") + .append('}') .toString(); try (InputStream is = new ByteArrayInputStream(json.getBytes())) { diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java index 83d20006b..2f72f8991 100644 --- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java +++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java @@ -12,7 +12,6 @@ import gov.nist.secauto.metaschema.core.MetaschemaJavaVersion; import gov.nist.secauto.metaschema.core.model.MetaschemaVersion; import gov.nist.secauto.metaschema.core.util.IVersionInfo; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.LinkedHashMap; import java.util.Map; @@ -42,13 +41,10 @@ public static void main(String[] args) { public static ExitStatus runCli(String... args) { System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); - @SuppressWarnings("serial") Map versions = ObjectUtils.notNull( - new LinkedHashMap<>() { - { - put(CLIProcessor.COMMAND_VERSION, new MetaschemaJavaVersion()); - put("http://csrc.nist.gov/ns/oscal/metaschema/1.0", new MetaschemaVersion()); - } - }); + Map versions = new LinkedHashMap<>(); + versions.put(CLIProcessor.COMMAND_VERSION, new MetaschemaJavaVersion()); + versions.put("http://csrc.nist.gov/ns/oscal/metaschema/1.0", new MetaschemaVersion()); + CLIProcessor processor = new CLIProcessor("metaschema-cli", versions); MetaschemaCommands.COMMANDS.forEach(processor::addCommandHandler); diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java index dc9f616c3..927b915bc 100644 --- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java +++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java @@ -15,6 +15,7 @@ import gov.nist.secauto.metaschema.cli.processor.command.DefaultExtraArgument; import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument; import gov.nist.secauto.metaschema.core.model.MetaschemaException; +import gov.nist.secauto.metaschema.core.util.AutoCloser; import gov.nist.secauto.metaschema.core.util.CustomCollectors; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.core.util.UriUtils; @@ -44,6 +45,9 @@ import edu.umd.cs.findbugs.annotations.NonNull; +/** + * Used by implementing classes to declare a content conversion command. + */ public abstract class AbstractConvertSubcommand extends AbstractTerminalCommand { private static final Logger LOGGER = LogManager.getLogger(AbstractConvertSubcommand.class); @@ -111,6 +115,10 @@ public void validateOptions(CallingContext callingContext, CommandLine cmdLine) } } + /** + * Used by implementing classes to provide for execution of a conversion + * command. + */ protected abstract static class AbstractConversionCommandExecutor extends AbstractCommandExecutor { @@ -211,8 +219,10 @@ public ExitStatus execute() { if (destination == null) { // write to STDOUT - OutputStreamWriter writer = new OutputStreamWriter(System.out, StandardCharsets.UTF_8); - handleConversion(source, toFormat, writer, loader); + try (OutputStreamWriter writer + = new OutputStreamWriter(AutoCloser.preventClose(System.out), StandardCharsets.UTF_8)) { + handleConversion(source, toFormat, writer, loader); + } } else { try (Writer writer = Files.newBufferedWriter( destination, diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java index 1bfc8039e..975a15917 100644 --- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java +++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java @@ -149,7 +149,7 @@ public void validateOptions(CallingContext callingContext, CommandLine cmdLine) String.format("Invalid '%s' argument. The format must be one of: %s.", OptionUtils.toArgument(AS_OPTION), Arrays.asList(Format.values()).stream() - .map(format -> format.name()) + .map(Enum::name) .collect(CustomCollectors.joiningWithOxfordComma("and")))); newEx.addSuppressed(ex); throw newEx; @@ -246,7 +246,7 @@ public ExitStatus execute() { return ExitCode.IO_ERROR .exitMessage("Invalid '--as' argument. The format must be one of: " + Arrays.stream(Format.values()) - .map(format -> format.name()) + .map(Enum::name) .collect(CustomCollectors.joiningWithOxfordComma("or"))) .withThrowable(ex); } @@ -263,7 +263,7 @@ public ExitStatus execute() { return ExitCode.IO_ERROR.exitMessage( "Source file has unrecognizable format. Use '--as' to specify the format. The format must be one of: " + Arrays.stream(Format.values()) - .map(format -> format.name()) + .map(Enum::name) .collect(CustomCollectors.joiningWithOxfordComma("or"))); } } @@ -317,7 +317,7 @@ public ExitStatus execute() { return ExitCode.IO_ERROR.exit().withThrowable(ex); } } else if (validationResult != null && !validationResult.getFindings().isEmpty()) { - LOGGER.info("Validation identified the following issues:", source); + LOGGER.info("Validation identified the following issues:"); LoggingValidationHandler.instance().handleValidationResults(validationResult); } diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java index 12f579bc4..fb57651cb 100644 --- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java +++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java @@ -114,7 +114,7 @@ public void validateOptions(CallingContext callingContext, CommandLine cmdLine) String.format("Invalid '%s' argument. The format must be one of: %s.", OptionUtils.toArgument(AS_OPTION), Arrays.asList(Format.values()).stream() - .map(format -> format.name()) + .map(Enum::name) .collect(CustomCollectors.joiningWithOxfordComma("and")))); newEx.setOption(AS_OPTION); newEx.addSuppressed(ex); diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java index 690c6cc59..9f66bd9b4 100644 --- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java +++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java @@ -58,7 +58,7 @@ public static IModule handleModule( @NonNull URI cwd, @NonNull Collection constraintSets) throws URISyntaxException, IOException, MetaschemaException { String moduleName - = ObjectUtils.requireNonNull(commandLine.getOptionValue(MetaschemaCommands.METASCHEMA_OPTION)); + = ObjectUtils.requireNonNull(commandLine.getOptionValue(METASCHEMA_OPTION)); URI moduleUri = UriUtils.toUri(moduleName, cwd); return handleModule(moduleUri, constraintSets); } diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java index dbf5048c3..003b8ccc1 100644 --- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java +++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java @@ -126,8 +126,8 @@ protected ExitStatus executeCommand( @NonNull CommandLine cmdLine) { URI cwd = ObjectUtils.notNull(Paths.get("").toAbsolutePath().toUri()); - IModule module; - INodeItem item; + IModule module = null; + INodeItem item = null; if (cmdLine.hasOption(METASCHEMA_OPTION)) { try { String moduleName @@ -161,9 +161,10 @@ protected ExitStatus executeCommand( IBoundLoader loader = bindingContext.newBoundLoader(); + String content = ObjectUtils.requireNonNull(cmdLine.getOptionValue(CONTENT_OPTION)); URI contentResource; try { - contentResource = MetaschemaCommands.handleResource(cmdLine.getOptionValue(CONTENT_OPTION), cwd); + contentResource = MetaschemaCommands.handleResource(content, cwd); } catch (IOException ex) { return ExitCode.INVALID_ARGUMENTS .exitMessage("Unable to resolve content location. " + ex.getMessage()) @@ -181,37 +182,40 @@ protected ExitStatus executeCommand( item = INodeItemFactory.instance().newModuleNodeItem(module); } } else if (cmdLine.hasOption(CONTENT_OPTION)) { + // content provided, but no module; require module return ExitCode.INVALID_ARGUMENTS.exitMessage( String.format("Must use '%s' to specify the Metaschema module.", CONTENT_OPTION.getArgName())); - } else { - module = null; - item = null; } - String expression = cmdLine.getOptionValue(EXPRESSION_OPTION); - StaticContext.Builder builder = StaticContext.builder(); if (module != null) { builder.defaultModelNamespace(module.getXmlNamespace()); } StaticContext staticContext = builder.build(); + String expression = cmdLine.getOptionValue(EXPRESSION_OPTION); + if (expression == null) { + return ExitCode.INVALID_ARGUMENTS.exitMessage( + String.format("Must use '%s' to specify the Metapath expression.", EXPRESSION_OPTION.getArgName())); + } + try { // Parse and compile the Metapath expression MetapathExpression compiledMetapath = MetapathExpression.compile(expression, staticContext); ISequence sequence = compiledMetapath.evaluate(item, new DynamicContext(staticContext)); - Writer stringWriter = new StringWriter(); - try (PrintWriter writer = new PrintWriter(stringWriter)) { - IItemWriter itemWriter = new DefaultItemWriter(writer); - itemWriter.writeSequence(sequence); - } + try (Writer stringWriter = new StringWriter()) { + try (PrintWriter writer = new PrintWriter(stringWriter)) { + try (IItemWriter itemWriter = new DefaultItemWriter(writer)) { + itemWriter.writeSequence(sequence); + } + } - // Print the result - if (LOGGER.isInfoEnabled()) { - LOGGER.info(stringWriter.toString()); + // Print the result + if (LOGGER.isInfoEnabled()) { + LOGGER.info(stringWriter.toString()); + } } - return ExitCode.OK.exit(); } catch (Exception ex) { return ExitCode.PROCESSING_ERROR.exit().withThrowable(ex); diff --git a/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java b/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java index e784ac333..9eff54293 100644 --- a/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java +++ b/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java @@ -39,7 +39,6 @@ public abstract class AbstractMetaschemaMojo extends AbstractMojo { - private static final String SYSTEM_FILE_ENCODING_PROPERTY = "file.encoding"; private static final String[] DEFAULT_INCLUDES = { "**/*.xml" }; /** diff --git a/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/GenerateSourcesMojo.java b/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/GenerateSourcesMojo.java index ce3305b74..11ea8151f 100644 --- a/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/GenerateSourcesMojo.java +++ b/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/GenerateSourcesMojo.java @@ -126,13 +126,13 @@ public void execute() throws MojoExecutionException { getLog().debug(String.format("Source file generation is configured to be skipped. Skipping.")); } generate = false; - } else if (!staleFile.exists()) { + } else if (staleFile.exists()) { + generate = isGenerationRequired(); + } else { if (getLog().isInfoEnabled()) { getLog().info(String.format("Stale file '%s' doesn't exist! Generating source files.", staleFile.getPath())); } generate = true; - } else { - generate = isGenerationRequired(); } if (generate) { diff --git a/metaschema-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml b/metaschema-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml index 5c074f725..4f2c8d2b2 100644 --- a/metaschema-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml +++ b/metaschema-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml @@ -14,5 +14,18 @@ + + + + generate-schemas + + + + + true + true + + + diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java index b9e115f62..2b24dad91 100644 --- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java +++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java @@ -167,7 +167,7 @@ protected void deleteCollectionOnExit(@NonNull Path path) { Runtime.getRuntime().addShutdownHook(new Thread( // NOPMD - this is not a webapp () -> { try { - Files.walkFileTree(path, new SimpleFileVisitor() { + Files.walkFileTree(path, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); @@ -256,6 +256,7 @@ protected void generateSchema( * * @return the options */ + @SuppressWarnings("PMD.MethodReturnsInternalArray") protected OpenOption[] getWriteOpenOptions() { return OPEN_OPTIONS_TRUNCATE; } @@ -297,8 +298,6 @@ private DynamicContainer generateScenario( }); Lazy lazySchema = Lazy.lazy(() -> { - Path schemaPath; - String schemaExtension; Format requiredContentFormat = getRequiredContentFormat(); switch (requiredContentFormat) { @@ -314,6 +313,7 @@ private DynamicContainer generateScenario( } // determine what file to use for the schema + Path schemaPath; try { schemaPath = Files.createTempFile(scenarioGenerationPath.get(), "", "-schema" + schemaExtension); } catch (IOException ex) { @@ -366,21 +366,18 @@ private DynamicContainer generateScenario( } }); - Stream contentTests; - { - contentTests = scenario.getValidationCaseList().stream() - .flatMap(contentCase -> { - assert contentCase != null; - DynamicTest test - = generateValidationCase( - contentCase, - lazyDynamicBindingContext, - lazyContentValidator, - collectionUri, - ObjectUtils.notNull(scenarioGenerationPath)); - return test == null ? Stream.empty() : Stream.of(test); - }).sequential(); - } + Stream contentTests = scenario.getValidationCaseList().stream() + .flatMap(contentCase -> { + assert contentCase != null; + DynamicTest test + = generateValidationCase( + contentCase, + lazyDynamicBindingContext, + lazyContentValidator, + collectionUri, + ObjectUtils.notNull(scenarioGenerationPath)); + return test == null ? Stream.empty() : Stream.of(test); + }).sequential(); return DynamicContainer.dynamicContainer( scenario.getName(), diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java index ea58fb9f1..3a4acc8f9 100644 --- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java +++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java @@ -20,7 +20,7 @@ private GenerationResultType() { */ public static void encodeGenerationResultType(Boolean obj, org.apache.xmlbeans.SimpleValue target) { if (obj != null) { - if (obj.booleanValue()) { + if (obj) { target.setStringValue("SUCCESS"); } else { target.setStringValue("FAILURE"); diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java index fd111546c..d4bf1cce0 100644 --- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java +++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java @@ -20,7 +20,7 @@ private ValidationResultType() { */ public static void encodeValidationResultType(Boolean obj, org.apache.xmlbeans.SimpleValue target) { if (obj != null) { - if (obj.booleanValue()) { + if (obj) { target.setStringValue("VALID"); } else { target.setStringValue("INVALID"); diff --git a/pom.xml b/pom.xml index 42567e1d9..118b1e514 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ dev.metaschema oss-parent - 4 + 5-SNAPSHOT dev.metaschema.java @@ -584,7 +584,7 @@ *.xmlbeans:*.xmlbeans.*:*.antlr false - true + false @@ -600,8 +600,7 @@ ${project.build.sourceDirectory} - - ${project.build.testSourceDirectory} + ${project.build.testSourceDirectory} @@ -681,41 +680,19 @@ true true - sarif + + + + pmd-analyze + + pmd + + + net.sourceforge.pmd.renderers.SarifRenderer - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - - org.apache.maven.plugins - - - maven-toolchains-plugin - - - [3.1.0,) - - - toolchain - - - - - - - - - - diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/FlagInstanceFilter.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/FlagInstanceFilter.java index 670f16aac..2ac53b7a3 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/FlagInstanceFilter.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/FlagInstanceFilter.java @@ -61,7 +61,7 @@ public static Collection filterFlags( @NonNull private static Predicate filterFlag(@NonNull IFlagInstance flagToFilter) { - return flag -> flag != flagToFilter; + return flag -> !flagToFilter.equals(flag); } @NonNull diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/ModuleIndex.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/ModuleIndex.java index 95f9ec869..b19d1c56a 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/ModuleIndex.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/ModuleIndex.java @@ -19,10 +19,6 @@ import gov.nist.secauto.metaschema.core.model.INamedModelInstanceGrouped; import gov.nist.secauto.metaschema.core.model.ModelWalker; import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import gov.nist.secauto.metaschema.databind.codegen.JavaGenerator; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.util.Collection; import java.util.HashSet; @@ -34,8 +30,6 @@ import edu.umd.cs.findbugs.annotations.NonNull; public class ModuleIndex { - private static final Logger LOGGER = LogManager.getLogger(JavaGenerator.class); - private final Map index = new LinkedHashMap<>();// new ConcurrentHashMap<>(); @NonNull diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/AbstractDatatypeManager.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/AbstractDatatypeManager.java index 3287c90b9..6912991bc 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/AbstractDatatypeManager.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/AbstractDatatypeManager.java @@ -8,11 +8,11 @@ import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import edu.umd.cs.findbugs.annotations.NonNull; @@ -48,7 +48,7 @@ public abstract class AbstractDatatypeManager implements IDatatypeManager { } @NonNull - private final Map, String> datatypeToTypeMap = new HashMap<>(); // NOPMD - intentional + private final Map, String> datatypeToTypeMap = new ConcurrentHashMap<>(); // NOPMD - intentional @SuppressWarnings("null") @NonNull @@ -65,13 +65,8 @@ public Set getUsedTypes() { @Override @NonNull public String getTypeNameForDatatype(@NonNull IDataTypeAdapter datatype) { - synchronized (this) { - String name = datatypeToTypeMap.get(datatype); - if (name == null) { - name = getDatatypeTranslationMap().get(datatype.getPreferredName().getLocalPart()); - datatypeToTypeMap.put(datatype, name); - } - return name; - } + return datatypeToTypeMap.computeIfAbsent( + datatype, + key -> getDatatypeTranslationMap().get(key.getPreferredName().getLocalPart())); } } diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/CompositeDatatypeProvider.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/CompositeDatatypeProvider.java index e6dfacff2..5f84881ac 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/CompositeDatatypeProvider.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/datatype/CompositeDatatypeProvider.java @@ -40,7 +40,10 @@ protected List getProxiedProviders() { public Map getDatatypes() { return ObjectUtils.notNull(proxiedProviders.stream() .flatMap(provider -> provider.getDatatypes().values().stream()) - .collect(Collectors.toMap(content -> content.getTypeName(), Function.identity(), (e1, e2) -> e2, + .collect(Collectors.toMap( + IDatatypeContent::getTypeName, + Function.identity(), + (e1, e2) -> e2, LinkedHashMap::new))); } diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/IDefineableJsonSchema.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/IDefineableJsonSchema.java index 12359b5e3..321f19215 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/IDefineableJsonSchema.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/IDefineableJsonSchema.java @@ -131,6 +131,7 @@ default void generateDefinition(@NonNull IJsonGenerationState state, @NonNull Ob generateInlineSchema(definitionObj, state); } + @SuppressWarnings("PMD.ShortClassName") interface IKey extends Comparable { Comparator KEY_COMPARATOR = Comparator .comparing(key -> key.getDefinition().getContainingModule().getShortName()) @@ -139,11 +140,13 @@ interface IKey extends Comparable { .thenComparing(IKey::getDiscriminatorProperty, Comparator.nullsFirst(Comparator.naturalOrder())) .thenComparing(IKey::getDiscriminatorValue, Comparator.nullsFirst(Comparator.naturalOrder())); + @SuppressWarnings("PMD.ShortMethodName") @NonNull static IKey of(@NonNull IDefinition definition) { return new SimpleKey(definition); } + @SuppressWarnings("PMD.ShortMethodName") @NonNull static IKey of( @NonNull IDefinition definition, diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/JsonSchemaGenerator.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/JsonSchemaGenerator.java index efa9d1051..177bb6e15 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/JsonSchemaGenerator.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/JsonSchemaGenerator.java @@ -17,6 +17,7 @@ import gov.nist.secauto.metaschema.core.model.IModule; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.schemagen.AbstractSchemaGenerator; +import gov.nist.secauto.metaschema.schemagen.ModuleIndex.DefinitionEntry; import gov.nist.secauto.metaschema.schemagen.SchemaGenerationException; import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature; import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema.IKey; @@ -92,7 +93,7 @@ protected void generateSchema(JsonGenerationState state) { } List rootAssemblyDefinitions = state.getMetaschemaIndex().getDefinitions().stream() - .map(entry -> entry.getDefinition()) + .map(DefinitionEntry::getDefinition) .filter( definition -> definition instanceof IAssemblyDefinition && ((IAssemblyDefinition) definition).isRoot()) .map(definition -> (IAssemblyDefinition) definition) diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractDefinitionJsonSchema.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractDefinitionJsonSchema.java index c8d89213d..712fa42c1 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractDefinitionJsonSchema.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractDefinitionJsonSchema.java @@ -105,6 +105,7 @@ public int hashCode() { return Objects.hash(definition, null, null, null); } + @SuppressWarnings("PMD.OnlyOneReturn") @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractModelDefinitionJsonSchema.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractModelDefinitionJsonSchema.java index 34bb57159..f2d55d404 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractModelDefinitionJsonSchema.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/AbstractModelDefinitionJsonSchema.java @@ -60,7 +60,7 @@ protected AbstractModelDefinitionJsonSchema( jsonKeyFlagName, definition.getName())); } - flagStream = flagStream.filter(instance -> instance != jsonKeyFlag); + flagStream = flagStream.filter(instance -> !jsonKeyFlag.equals(instance)); } this.flagProperties = ObjectUtils.notNull(flagStream @@ -169,6 +169,7 @@ public int hashCode() { return Objects.hash(definition, jsonKeyFlagName, discriminatorProperty, discriminatorValue); } + @SuppressWarnings("PMD.OnlyOneReturn") @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/JsonGenerationState.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/JsonGenerationState.java index e71d562ce..788d7baa6 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/JsonGenerationState.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/JsonGenerationState.java @@ -20,6 +20,7 @@ import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.schemagen.AbstractGenerationState; +import gov.nist.secauto.metaschema.schemagen.ModuleIndex.DefinitionEntry; import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature; import gov.nist.secauto.metaschema.schemagen.json.IDataTypeJsonSchema; import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema.IKey; @@ -101,7 +102,7 @@ private IDefinitionJsonSchema getDefinitionSchema( @NonNull IKey key, @NonNull IJsonGenerationState state) { synchronized (schemaDefinitions) { - return schemaDefinitions.computeIfAbsent(key, (k) -> { + return schemaDefinitions.computeIfAbsent(key, k -> { IDefinitionJsonSchema retval = newJsonSchema( k.getDefinition(), k.getJsonKeyFlagName(), @@ -175,8 +176,8 @@ public ObjectNode generateDefinitions() { @NonNull Map> gatheredDefinitions = new HashMap<>(); getMetaschemaIndex().getDefinitions().stream() - .filter(entry -> entry.isRoot()) - .map(entry -> entry.getDefinition()) + .filter(DefinitionEntry::isRoot) + .map(DefinitionEntry::getDefinition) .forEachOrdered(def -> { IDefinitionJsonSchema definitionSchema = getSchema(IKey.of(def)); assert definitionSchema != null; @@ -247,6 +248,7 @@ public void writeField(String fieldName, ObjectNode obj) throws IOException { writer.writeTree(obj); } + @SuppressWarnings("resource") @Override public void flushWriter() throws IOException { getWriter().flush(); diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/MetadataUtils.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/MetadataUtils.java index b402c2349..a3248f502 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/MetadataUtils.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/MetadataUtils.java @@ -27,6 +27,7 @@ import java.math.BigInteger; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; public final class MetadataUtils { private MetadataUtils() { @@ -72,7 +73,7 @@ public static void generateDefault(IValuedInstance instance, ObjectNode obj) { } } - private static JsonNode toJsonValue(Object defaultValue, IDataTypeAdapter adapter) { + private static JsonNode toJsonValue(@Nullable Object defaultValue, @NonNull IDataTypeAdapter adapter) { JsonNode retval = null; switch (adapter.getJsonRawType()) { case BOOLEAN: @@ -100,14 +101,14 @@ private static JsonNode toJsonValue(Object defaultValue, IDataTypeAdapter ada case ARRAY: case OBJECT: case NULL: - throw new UnsupportedOperationException("Invalid type: " + defaultValue.getClass()); + throw new UnsupportedOperationException("Invalid type: " + adapter.getClass()); case STRING: default: // use default conversion break; } - if (retval == null) { + if (retval == null && defaultValue != null) { retval = TextNode.valueOf(adapter.asString(defaultValue)); } return retval; diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/AbstractCollectionBuilder.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/AbstractCollectionBuilder.java index b30fd60a0..5ab9fe02e 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/AbstractCollectionBuilder.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/AbstractCollectionBuilder.java @@ -17,6 +17,7 @@ import gov.nist.secauto.metaschema.core.model.INamedModelInstanceAbsolute; import gov.nist.secauto.metaschema.core.model.INamedModelInstanceGrouped; import gov.nist.secauto.metaschema.core.util.CollectionUtil; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.schemagen.json.IDataTypeJsonSchema; import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema.IKey; import gov.nist.secauto.metaschema.schemagen.json.IDefinitionJsonSchema; @@ -108,6 +109,7 @@ protected void buildInternal( } } + @SuppressWarnings("PMD.ShortClassName") private abstract static class Type implements IModelInstanceBuilder.IType { @NonNull private final T namedModelInstance; @@ -188,7 +190,7 @@ public IDefinitionJsonSchema getJsonSchema(IJsonGenerationStat public void build( @NonNull ArrayNode anyOf, @NonNull IJsonGenerationState state) { - build(anyOf.addObject(), state); + build(ObjectUtils.notNull(anyOf.addObject()), state); } @Override diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/KeyedObjectBuilder.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/KeyedObjectBuilder.java index 84dd9076a..a86477815 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/KeyedObjectBuilder.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/json/impl/builder/KeyedObjectBuilder.java @@ -54,11 +54,11 @@ public void build( if (!types.isEmpty()) { ObjectNode patternProperties = ObjectUtils.notNull(object.putObject("patternProperties")); - ObjectNode wildcard = patternProperties.putObject("^.*$"); + ObjectNode wildcard = ObjectUtils.notNull(patternProperties.putObject("^.*$")); if (types.size() == 1) { types.iterator().next().build(wildcard, state); } else { - ArrayNode oneOf = wildcard.putArray("anyOf"); + ArrayNode oneOf = ObjectUtils.notNull(wildcard.putArray("anyOf")); for (IType type : types) { type.build(oneOf, state); } diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlDatatypeProvider.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlDatatypeProvider.java index 7b740a6b3..d95c1e908 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlDatatypeProvider.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlDatatypeProvider.java @@ -9,6 +9,7 @@ import gov.nist.secauto.metaschema.schemagen.datatype.IDatatypeProvider; import org.codehaus.stax2.XMLStreamWriter2; +import org.eclipse.jdt.annotation.Owning; import org.jdom2.Element; import org.jdom2.JDOMException; @@ -28,6 +29,8 @@ public abstract class AbstractXmlDatatypeProvider implements IDatatypeProvider { private Map datatypes; + @Owning + @NonNull protected abstract InputStream getSchemaResource(); private void initSchema() { diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlMarkupDatatypeProvider.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlMarkupDatatypeProvider.java index e00b8acfb..eb847965d 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlMarkupDatatypeProvider.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/AbstractXmlMarkupDatatypeProvider.java @@ -10,6 +10,7 @@ import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.metaschema.schemagen.datatype.IDatatypeContent; +import org.eclipse.jdt.annotation.Owning; import org.jdom2.Element; import java.io.InputStream; @@ -22,6 +23,8 @@ public abstract class AbstractXmlMarkupDatatypeProvider extends AbstractXmlDatatypeProvider { + @SuppressWarnings("null") + @Owning @Override protected InputStream getSchemaResource() { return IModule.class.getResourceAsStream(getSchemaResourcePath()); diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlCoreDatatypeProvider.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlCoreDatatypeProvider.java index 99043d1ea..05755130b 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlCoreDatatypeProvider.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlCoreDatatypeProvider.java @@ -44,22 +44,23 @@ protected List queryElements(JDom2XmlSchemaLoader loader) { private static List analyzeDependencies(@NonNull Element element) { XPathExpression xpath = XPathFactory.instance().compile(".//@base", Filters.attribute()); return ObjectUtils.notNull(xpath.evaluate(element).stream() - .map(attr -> attr.getValue()) + .map(Attribute::getValue) .filter(type -> !type.startsWith("xs:")) .distinct() .collect(Collectors.toList())); } @Override - protected @NonNull Map handleResults( + @NonNull + protected Map handleResults( @NonNull List items) { return ObjectUtils.notNull(items.stream() - .map(element -> { - return (IDatatypeContent) new JDom2DatatypeContent( - ObjectUtils.requireNonNull(element.getAttributeValue("name")), - CollectionUtil.singletonList(element), - analyzeDependencies(element)); - }).collect(Collectors.toMap(content -> content.getTypeName(), Function.identity(), (e1, e2) -> e2, + .map(element -> new JDom2DatatypeContent( + ObjectUtils.requireNonNull(element.getAttributeValue("name")), + CollectionUtil.singletonList(element), + analyzeDependencies(element))) + .collect(Collectors.toMap((Function) IDatatypeContent::getTypeName, + Function.identity(), (e1, e2) -> e2, LinkedHashMap::new))); } } diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlDatatypeManager.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlDatatypeManager.java index 331bdf39d..bbc9b0be2 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlDatatypeManager.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlDatatypeManager.java @@ -38,7 +38,7 @@ public void generateDatatypes(@NonNull XMLStreamWriter2 writer) throws XMLStream Set used = getUsedTypes(); Set requiredTypes = getDatatypeTranslationMap().values().stream() - .filter(type -> used.contains(type)) + .filter(used::contains) .collect(Collectors.toCollection(LinkedHashSet::new)); for (IDatatypeProvider provider : DATATYPE_PROVIDERS.get()) { diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlProseCompositDatatypeProvider.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlProseCompositDatatypeProvider.java index 7e7daff87..e11787667 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlProseCompositDatatypeProvider.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/datatype/XmlProseCompositDatatypeProvider.java @@ -37,7 +37,7 @@ public XmlProseCompositDatatypeProvider(@NonNull List proxied if (!result.isEmpty()) { // apply core markup types Collection datatypes = proseBaseProvider.getDatatypes().values(); - Set proseBaseTypes = datatypes.stream().map(content -> content.getTypeName()).collect(Collectors.toSet()); + Set proseBaseTypes = datatypes.stream().map(IDatatypeContent::getTypeName).collect(Collectors.toSet()); proseBaseProvider.generateDatatypes(proseBaseTypes, writer); } return result; diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/impl/XmlGenerationState.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/impl/XmlGenerationState.java index 701db407b..14202214f 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/impl/XmlGenerationState.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/impl/XmlGenerationState.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; @@ -56,7 +57,7 @@ public class XmlGenerationState @NonNull private final Map definitionToTypeMap = new ConcurrentHashMap<>(); - private int prefixNum; // 0 + private final AtomicInteger prefixNum = new AtomicInteger(); // 0 public XmlGenerationState( @NonNull IModule module, @@ -91,13 +92,9 @@ public String getNS(@NonNull IModelElement modelElement) { public String getNSPrefix(String namespace) { String retval = null; if (!getDefaultNS().equals(namespace)) { - synchronized (this) { - retval = namespaceToPrefixMap.get(namespace); - if (retval == null) { - retval = String.format("ns%d", ++prefixNum); - namespaceToPrefixMap.put(namespace, retval); - } - } + retval = namespaceToPrefixMap.computeIfAbsent( + namespace, + key -> String.format("ns%d", prefixNum.incrementAndGet())); } return retval; } @@ -256,6 +253,7 @@ public void writeNamespace(String prefix, String namespaceUri) throws XMLStreamE getXMLStreamWriter().writeNamespace(prefix, namespaceUri); } + @SuppressWarnings("resource") @Override public void flushWriter() throws IOException { try { diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/schematype/XmlSimpleTypeUnion.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/schematype/XmlSimpleTypeUnion.java index 61556b3e8..71256a7af 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/schematype/XmlSimpleTypeUnion.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/xml/schematype/XmlSimpleTypeUnion.java @@ -69,7 +69,7 @@ public void generate(XmlGenerationState state) { // NOPMD unavoidable complexity state.writeAttribute( "memberTypes", ObjectUtils.notNull(memberTypes.stream() - .map(type -> type.getTypeReference()) + .map(IXmlSimpleType::getTypeReference) .collect(Collectors.joining(" ")))); } diff --git a/schemagen/src/main/java/module-info.java b/schemagen/src/main/java/module-info.java index 6c0b512da..0898a1d20 100644 --- a/schemagen/src/main/java/module-info.java +++ b/schemagen/src/main/java/module-info.java @@ -19,6 +19,7 @@ requires org.jdom2; requires Saxon.HE; + requires org.eclipse.jdt.annotation; exports gov.nist.secauto.metaschema.schemagen; exports gov.nist.secauto.metaschema.schemagen.json;