${basedir}
META-INF
diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java
index d131ece4be7..66a9afb27b7 100644
--- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java
+++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java
@@ -17,93 +17,128 @@
*/
package org.owasp.dependencycheck.ant.logging;
+import java.util.Objects;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
+import org.slf4j.Logger;
+import org.slf4j.Marker;
import org.slf4j.helpers.FormattingTuple;
-import org.slf4j.helpers.MarkerIgnoringBase;
import org.slf4j.helpers.MessageFormatter;
/**
* An instance of {@link org.slf4j.Logger} which simply calls the log method on
- * the delegate Ant task.
+ * the current Ant task obtained from {@link AntTaskHolder}.
*
* @author colezlaw
*/
-public class AntLoggerAdapter extends MarkerIgnoringBase {
+public class AntLoggerAdapter implements Logger {
+
/**
- * The serial version UID for serialization.
- */
- private static final long serialVersionUID = -8546294566287970709L;
- /**
- * A reference to the Ant task used for logging.
+ * The logger name.
*/
- private transient Task task;
+ private final String name;
/**
- * Constructs an Ant Logger Adapter.
+ * Constructor.
*
- * @param task the Ant Task to use for logging
+ * @param name the logger name
*/
- public AntLoggerAdapter(Task task) {
- super();
- this.task = task;
+ public AntLoggerAdapter(String name) {
+ this.name = Objects.requireNonNull(name, "Logger name cannot be null");
}
- /**
- * Sets the current Ant task to use for logging.
- *
- * @param task the Ant task to use for logging
- */
- public void setTask(Task task) {
- this.task = task;
+ @Override
+ public String getName() {
+ return name;
}
+ private Task task() {
+ return AntTaskHolder.getTask();
+ }
+
+ // --- TRACE ---
+
@Override
public boolean isTraceEnabled() {
- // Might be a more efficient way to do this, but Ant doesn't enable or disable
- // various levels globally - it just fires things at registered Listeners.
return true;
}
@Override
public void trace(String msg) {
- if (task != null) {
- task.log(msg, Project.MSG_VERBOSE);
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, Project.MSG_VERBOSE);
}
}
@Override
public void trace(String format, Object arg) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg);
- task.log(tp.getMessage(), Project.MSG_VERBOSE);
+ t.log(tp.getMessage(), Project.MSG_VERBOSE);
}
}
@Override
public void trace(String format, Object arg1, Object arg2) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
- task.log(tp.getMessage(), Project.MSG_VERBOSE);
+ t.log(tp.getMessage(), Project.MSG_VERBOSE);
}
}
@Override
public void trace(String format, Object... arguments) {
- if (task != null) {
- final FormattingTuple tp = MessageFormatter.format(format, arguments);
- task.log(tp.getMessage(), Project.MSG_VERBOSE);
+ final Task t = task();
+ if (t != null) {
+ final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
+ t.log(tp.getMessage(), Project.MSG_VERBOSE);
}
}
@Override
- public void trace(String msg, Throwable t) {
- if (task != null) {
- task.log(msg, t, Project.MSG_VERBOSE);
+ public void trace(String msg, Throwable throwable) {
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, throwable, Project.MSG_VERBOSE);
}
}
+ @Override
+ public boolean isTraceEnabled(Marker marker) {
+ return isTraceEnabled();
+ }
+
+ @Override
+ public void trace(Marker marker, String msg) {
+ trace(msg);
+ }
+
+ @Override
+ public void trace(Marker marker, String format, Object arg) {
+ trace(format, arg);
+ }
+
+ @Override
+ public void trace(Marker marker, String format, Object arg1, Object arg2) {
+ trace(format, arg1, arg2);
+ }
+
+ @Override
+ public void trace(Marker marker, String format, Object... argArray) {
+ trace(format, argArray);
+ }
+
+ @Override
+ public void trace(Marker marker, String msg, Throwable throwable) {
+ trace(msg, throwable);
+ }
+
+ // --- DEBUG ---
+
@Override
public boolean isDebugEnabled() {
return true;
@@ -111,42 +146,79 @@ public boolean isDebugEnabled() {
@Override
public void debug(String msg) {
- if (task != null) {
- task.log(msg, Project.MSG_DEBUG);
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, Project.MSG_DEBUG);
}
}
@Override
public void debug(String format, Object arg) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg);
- task.log(tp.getMessage(), Project.MSG_DEBUG);
+ t.log(tp.getMessage(), Project.MSG_DEBUG);
}
}
@Override
public void debug(String format, Object arg1, Object arg2) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
- task.log(tp.getMessage(), Project.MSG_DEBUG);
+ t.log(tp.getMessage(), Project.MSG_DEBUG);
}
}
@Override
public void debug(String format, Object... arguments) {
- if (task != null) {
- final FormattingTuple tp = MessageFormatter.format(format, arguments);
- task.log(tp.getMessage(), Project.MSG_DEBUG);
+ final Task t = task();
+ if (t != null) {
+ final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
+ t.log(tp.getMessage(), Project.MSG_DEBUG);
}
}
@Override
- public void debug(String msg, Throwable t) {
- if (task != null) {
- task.log(msg, t, Project.MSG_DEBUG);
+ public void debug(String msg, Throwable throwable) {
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, throwable, Project.MSG_DEBUG);
}
}
+ @Override
+ public boolean isDebugEnabled(Marker marker) {
+ return isDebugEnabled();
+ }
+
+ @Override
+ public void debug(Marker marker, String msg) {
+ debug(msg);
+ }
+
+ @Override
+ public void debug(Marker marker, String format, Object arg) {
+ debug(format, arg);
+ }
+
+ @Override
+ public void debug(Marker marker, String format, Object arg1, Object arg2) {
+ debug(format, arg1, arg2);
+ }
+
+ @Override
+ public void debug(Marker marker, String format, Object... arguments) {
+ debug(format, arguments);
+ }
+
+ @Override
+ public void debug(Marker marker, String msg, Throwable throwable) {
+ debug(msg, throwable);
+ }
+
+ // --- INFO ---
+
@Override
public boolean isInfoEnabled() {
return true;
@@ -154,42 +226,79 @@ public boolean isInfoEnabled() {
@Override
public void info(String msg) {
- if (task != null) {
- task.log(msg, Project.MSG_INFO);
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, Project.MSG_INFO);
}
}
@Override
public void info(String format, Object arg) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg);
- task.log(tp.getMessage(), Project.MSG_INFO);
+ t.log(tp.getMessage(), Project.MSG_INFO);
}
}
@Override
public void info(String format, Object arg1, Object arg2) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
- task.log(tp.getMessage(), Project.MSG_INFO);
+ t.log(tp.getMessage(), Project.MSG_INFO);
}
}
@Override
public void info(String format, Object... arguments) {
- if (task != null) {
- final FormattingTuple tp = MessageFormatter.format(format, arguments);
- task.log(tp.getMessage(), Project.MSG_INFO);
+ final Task t = task();
+ if (t != null) {
+ final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
+ t.log(tp.getMessage(), Project.MSG_INFO);
}
}
@Override
- public void info(String msg, Throwable t) {
- if (task != null) {
- task.log(msg, t, Project.MSG_INFO);
+ public void info(String msg, Throwable throwable) {
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, throwable, Project.MSG_INFO);
}
}
+ @Override
+ public boolean isInfoEnabled(Marker marker) {
+ return isInfoEnabled();
+ }
+
+ @Override
+ public void info(Marker marker, String msg) {
+ info(msg);
+ }
+
+ @Override
+ public void info(Marker marker, String format, Object arg) {
+ info(format, arg);
+ }
+
+ @Override
+ public void info(Marker marker, String format, Object arg1, Object arg2) {
+ info(format, arg1, arg2);
+ }
+
+ @Override
+ public void info(Marker marker, String format, Object... arguments) {
+ info(format, arguments);
+ }
+
+ @Override
+ public void info(Marker marker, String msg, Throwable throwable) {
+ info(msg, throwable);
+ }
+
+ // --- WARN ---
+
@Override
public boolean isWarnEnabled() {
return true;
@@ -197,42 +306,79 @@ public boolean isWarnEnabled() {
@Override
public void warn(String msg) {
- if (task != null) {
- task.log(msg, Project.MSG_WARN);
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, Project.MSG_WARN);
}
}
@Override
public void warn(String format, Object arg) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg);
- task.log(tp.getMessage(), Project.MSG_WARN);
+ t.log(tp.getMessage(), Project.MSG_WARN);
}
}
@Override
public void warn(String format, Object... arguments) {
- if (task != null) {
- final FormattingTuple tp = MessageFormatter.format(format, arguments);
- task.log(tp.getMessage(), Project.MSG_WARN);
+ final Task t = task();
+ if (t != null) {
+ final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
+ t.log(tp.getMessage(), Project.MSG_WARN);
}
}
@Override
public void warn(String format, Object arg1, Object arg2) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
- task.log(tp.getMessage(), Project.MSG_WARN);
+ t.log(tp.getMessage(), Project.MSG_WARN);
}
}
@Override
- public void warn(String msg, Throwable t) {
- if (task != null) {
- task.log(msg, t, Project.MSG_WARN);
+ public void warn(String msg, Throwable throwable) {
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, throwable, Project.MSG_WARN);
}
}
+ @Override
+ public boolean isWarnEnabled(Marker marker) {
+ return isWarnEnabled();
+ }
+
+ @Override
+ public void warn(Marker marker, String msg) {
+ warn(msg);
+ }
+
+ @Override
+ public void warn(Marker marker, String format, Object arg) {
+ warn(format, arg);
+ }
+
+ @Override
+ public void warn(Marker marker, String format, Object arg1, Object arg2) {
+ warn(format, arg1, arg2);
+ }
+
+ @Override
+ public void warn(Marker marker, String format, Object... arguments) {
+ warn(format, arguments);
+ }
+
+ @Override
+ public void warn(Marker marker, String msg, Throwable throwable) {
+ warn(msg, throwable);
+ }
+
+ // --- ERROR ---
+
@Override
public boolean isErrorEnabled() {
return true;
@@ -240,39 +386,74 @@ public boolean isErrorEnabled() {
@Override
public void error(String msg) {
- if (task != null) {
- task.log(msg, Project.MSG_ERR);
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, Project.MSG_ERR);
}
}
@Override
public void error(String format, Object arg) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg);
- task.log(tp.getMessage(), Project.MSG_ERR);
+ t.log(tp.getMessage(), Project.MSG_ERR);
}
}
@Override
public void error(String format, Object arg1, Object arg2) {
- if (task != null) {
+ final Task t = task();
+ if (t != null) {
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
- task.log(tp.getMessage(), Project.MSG_ERR);
+ t.log(tp.getMessage(), Project.MSG_ERR);
}
}
@Override
public void error(String format, Object... arguments) {
- if (task != null) {
- final FormattingTuple tp = MessageFormatter.format(format, arguments);
- task.log(tp.getMessage(), Project.MSG_ERR);
+ final Task t = task();
+ if (t != null) {
+ final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
+ t.log(tp.getMessage(), Project.MSG_ERR);
}
}
@Override
- public void error(String msg, Throwable t) {
- if (task != null) {
- task.log(msg, t, Project.MSG_ERR);
+ public void error(String msg, Throwable throwable) {
+ final Task t = task();
+ if (t != null) {
+ t.log(msg, throwable, Project.MSG_ERR);
}
}
+
+ @Override
+ public boolean isErrorEnabled(Marker marker) {
+ return isErrorEnabled();
+ }
+
+ @Override
+ public void error(Marker marker, String msg) {
+ error(msg);
+ }
+
+ @Override
+ public void error(Marker marker, String format, Object arg) {
+ error(format, arg);
+ }
+
+ @Override
+ public void error(Marker marker, String format, Object arg1, Object arg2) {
+ error(format, arg1, arg2);
+ }
+
+ @Override
+ public void error(Marker marker, String format, Object... arguments) {
+ error(format, arguments);
+ }
+
+ @Override
+ public void error(Marker marker, String msg, Throwable throwable) {
+ error(msg, throwable);
+ }
}
diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java
index f5d10d5193e..1c8dd84ac75 100644
--- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java
+++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java
@@ -17,7 +17,6 @@
*/
package org.owasp.dependencycheck.ant.logging;
-import org.apache.tools.ant.Task;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
@@ -28,29 +27,14 @@
*/
public class AntLoggerFactory implements ILoggerFactory {
- /**
- * A reference to the Ant logger Adapter.
- */
- private final AntLoggerAdapter antLoggerAdapter;
-
- /**
- * Constructs a new Ant Logger Factory.
- *
- * @param task the Ant task to use for logging
- */
- public AntLoggerFactory(Task task) {
- super();
- this.antLoggerAdapter = new AntLoggerAdapter(task);
- }
-
/**
* Returns the Ant logger adapter.
*
- * @param name ignored in this implementation
+ * @param name the logger name
* @return the Ant logger adapter
*/
@Override
public Logger getLogger(String name) {
- return antLoggerAdapter;
+ return new AntLoggerAdapter(name);
}
}
diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java
new file mode 100644
index 00000000000..418efe8b36e
--- /dev/null
+++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java
@@ -0,0 +1,69 @@
+/*
+ * This file is part of dependency-check-ant.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.ant.logging;
+
+import org.slf4j.ILoggerFactory;
+import org.slf4j.IMarkerFactory;
+import org.slf4j.helpers.BasicMarkerFactory;
+import org.slf4j.helpers.NOPMDCAdapter;
+import org.slf4j.spi.MDCAdapter;
+import org.slf4j.spi.SLF4JServiceProvider;
+
+/**
+ * SLF4J 2.0 service provider for the dependency-check Ant integration.
+ * Replaces the old StaticLoggerBinder mechanism used in SLF4J 1.x.
+ */
+public class AntSlf4jServiceProvider implements SLF4JServiceProvider {
+
+ /**
+ * Declare the version of the SLF4J API this implementation is compiled
+ * against.
+ */
+ private static final String REQUESTED_API_VERSION = "2.0";
+
+ private ILoggerFactory loggerFactory;
+ private IMarkerFactory markerFactory;
+ private MDCAdapter mdcAdapter;
+
+ @Override
+ public ILoggerFactory getLoggerFactory() {
+ return loggerFactory;
+ }
+
+ @Override
+ public IMarkerFactory getMarkerFactory() {
+ return markerFactory;
+ }
+
+ @Override
+ public MDCAdapter getMDCAdapter() {
+ return mdcAdapter;
+ }
+
+ @Override
+ public String getRequestedApiVersion() {
+ return REQUESTED_API_VERSION;
+ }
+
+ @Override
+ public void initialize() {
+ loggerFactory = new AntLoggerFactory();
+ markerFactory = new BasicMarkerFactory();
+ mdcAdapter = new NOPMDCAdapter();
+ }
+}
diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java
new file mode 100644
index 00000000000..5cabdd7fc09
--- /dev/null
+++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of dependency-check-ant.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.ant.logging;
+
+import org.apache.tools.ant.Task;
+
+/**
+ * Holds a reference to the current Ant Task for logging. Replaces the old
+ * StaticLoggerBinder singleton pattern used with SLF4J 1.x.
+ *
+ * Uses ThreadLocal to ensure thread-safety when Ant runs tasks in parallel.
+ *
+ */
+public final class AntTaskHolder {
+
+ private static final ThreadLocal task = new ThreadLocal<>();
+
+ private AntTaskHolder() {
+ }
+
+ /**
+ * Sets the current Ant task to use for logging.
+ *
+ * @param t the Ant task
+ */
+ public static void setTask(Task t) {
+ task.set(t);
+ }
+
+ /**
+ * Returns the current Ant task.
+ *
+ * @return the Ant task, or null if not set
+ */
+ public static Task getTask() {
+ return task.get();
+ }
+
+ /**
+ * Removes the current Ant task from the thread-local storage.
+ * This should be called when the task completes to prevent memory leaks
+ * in environments with thread pooling.
+ */
+ public static void remove() {
+ task.remove();
+ }
+}
diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java
index 3882743a3d0..cd74addae4b 100644
--- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java
+++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java
@@ -46,7 +46,7 @@
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.SeverityUtil;
import org.owasp.dependencycheck.utils.scarf.TelemetryCollector;
-import org.slf4j.impl.StaticLoggerBinder;
+import org.owasp.dependencycheck.ant.logging.AntTaskHolder;
//CSOFF: MethodCount
/**
@@ -517,7 +517,7 @@ public Check() {
super();
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
// core end up coming through this tasks logger
- StaticLoggerBinder.getSingleton().setTask(this);
+ AntTaskHolder.setTask(this);
}
/**
diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java
index 023087b8f7e..5f4f6011af6 100644
--- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java
+++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java
@@ -29,7 +29,7 @@
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
-import org.slf4j.impl.StaticLoggerBinder;
+import org.owasp.dependencycheck.ant.logging.AntTaskHolder;
/**
* An Ant task definition to execute dependency-check during an Ant build.
@@ -65,7 +65,7 @@ public Purge() {
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
// core end up coming through this tasks logger
- StaticLoggerBinder.getSingleton().setTask(this);
+ AntTaskHolder.setTask(this);
}
public Settings getSettings() {
@@ -121,6 +121,7 @@ public final void execute() throws BuildException {
executeWithContextClassloader();
} finally {
Thread.currentThread().setContextClassLoader(current);
+ AntTaskHolder.remove();
}
}
diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
index 1cac8153188..9736dfc277e 100644
--- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
+++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
@@ -25,7 +25,7 @@
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
-import org.slf4j.impl.StaticLoggerBinder;
+import org.owasp.dependencycheck.ant.logging.AntTaskHolder;
/**
* An Ant task definition to execute dependency-check update. This will download
@@ -222,7 +222,7 @@ public Update() {
super();
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
// core end up coming through this tasks logger
- StaticLoggerBinder.getSingleton().setTask(this);
+ AntTaskHolder.setTask(this);
}
/**
diff --git a/ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
deleted file mode 100644
index 683fd331fcf..00000000000
--- a/ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * This file is part of dependency-check-ant.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
- */
-package org.slf4j.impl;
-
-import org.apache.tools.ant.Task;
-import org.owasp.dependencycheck.ant.logging.AntLoggerFactory;
-import org.slf4j.ILoggerFactory;
-import org.slf4j.spi.LoggerFactoryBinder;
-
-/**
- * The binding of org.slf4j.LoggerFactory class with an actual instance of
- * org.slf4j.ILoggerFactory is performed using information returned by this
- * class.
- *
- * @author colezlaw
- */
-//CSOFF: FinalClass
-@SuppressWarnings({"squid:S1444", "squid:ClassVariableVisibilityCheck"})
-public class StaticLoggerBinder implements LoggerFactoryBinder {
-//CSON: FinalClass
-
- /**
- * The unique instance of this class
- */
- private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
- /**
- * Ant tasks have the log method we actually want to call. So we hang onto
- * the task as a delegate
- */
- private Task task = null;
-
- /**
- * Declare the version of the SLF4J API this implementation is compiled
- * against. The value of this filed is usually modified with each release.
- */
- // to avoid constant folding by the compiler, this field must *not* be final
- //CSOFF: StaticVariableName
- //CSOFF: VisibilityModifier
- @SuppressWarnings("squid:S3008")
- public static String REQUESTED_API_VERSION = "1.7.12"; // final
- //CSON: VisibilityModifier
- //CSON: StaticVariableName
-
- /**
- * The logger factory class string.
- */
- private static final String LOGGER_FACTORY_CLASS = AntLoggerFactory.class.getName();
-
- /**
- * The ILoggerFactory instance returned by the {@link #getLoggerFactory}
- * method should always be the same object
- */
- private ILoggerFactory loggerFactory;
-
- /**
- * Return the singleton of this class.
- *
- * @return the StaticLoggerBinder singleton
- */
- public static StaticLoggerBinder getSingleton() {
- return SINGLETON;
- }
-
- /**
- * Set the Task which will this is to log through.
- *
- * @param task the task through which to log
- */
- public void setTask(Task task) {
- this.task = task;
- loggerFactory = new AntLoggerFactory(task);
- }
-
- /**
- * Constructs a new static logger binder.
- */
- private StaticLoggerBinder() {
- loggerFactory = new AntLoggerFactory(task);
- }
-
- /**
- * Returns the logger factory.
- *
- * @return the logger factory
- */
- @Override
- public ILoggerFactory getLoggerFactory() {
- return loggerFactory;
- }
-
- /**
- * Returns the logger factory class string.
- *
- * @return the logger factory class string
- */
- @Override
- public String getLoggerFactoryClassStr() {
- return LOGGER_FACTORY_CLASS;
- }
-}
diff --git a/ant/src/main/java/org/slf4j/impl/package-info.java b/ant/src/main/java/org/slf4j/impl/package-info.java
deleted file mode 100644
index c0c8e350575..00000000000
--- a/ant/src/main/java/org/slf4j/impl/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * This package contains the static binder for the slf4j-ant logger.
- */
-package org.slf4j.impl;
diff --git a/ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider
new file mode 100644
index 00000000000..efb8d4c5678
--- /dev/null
+++ b/ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider
@@ -0,0 +1 @@
+org.owasp.dependencycheck.ant.logging.AntSlf4jServiceProvider
diff --git a/ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java b/ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java
new file mode 100644
index 00000000000..af95c45a748
--- /dev/null
+++ b/ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java
@@ -0,0 +1,173 @@
+/*
+ * This file is part of dependency-check-ant.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.ant.logging;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ServiceLoader;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.spi.SLF4JServiceProvider;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests that the {@link AntSlf4jServiceProvider} is discoverable via the
+ * {@link ServiceLoader} mechanism and that log output is routed through the
+ * Ant task.
+ */
+class AntSlf4jServiceProviderTest {
+
+ @AfterEach
+ void tearDown() {
+ AntTaskHolder.remove();
+ }
+
+ /**
+ * Verifies the META-INF/services descriptor exists in src/main/resources
+ * and that ServiceLoader can discover the provider when that directory is
+ * on the classpath (simulates the packaged JAR).
+ */
+ @Test
+ void testProviderIsDiscoverableViaServiceLoader() throws Exception {
+ // Build a classloader that includes src/main/resources so the
+ // META-INF/services file is visible, as it would be in the packaged JAR.
+ Path resources = Paths.get("src", "main", "resources");
+ try (URLClassLoader cl = new URLClassLoader(
+ new URL[]{resources.toUri().toURL()},
+ getClass().getClassLoader())) {
+
+ ServiceLoader loader = ServiceLoader.load(SLF4JServiceProvider.class, cl);
+ boolean found = false;
+ for (SLF4JServiceProvider provider : loader) {
+ if (provider instanceof AntSlf4jServiceProvider) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found,
+ "AntSlf4jServiceProvider was not found via ServiceLoader; "
+ + "check META-INF/services/org.slf4j.spi.SLF4JServiceProvider");
+ }
+ }
+
+ /**
+ * Verifies the services descriptor file contents match the provider class.
+ */
+ @Test
+ void testServiceDescriptorContainsCorrectClassName() throws Exception {
+ try (InputStream is = getClass().getClassLoader()
+ .getResourceAsStream("META-INF/services/org.slf4j.spi.SLF4JServiceProvider")) {
+ if (is == null) {
+ // The file may not be on the test classpath due to resource
+ // filtering; load it directly from source.
+ Path file = Paths.get("src", "main", "resources",
+ "META-INF", "services", "org.slf4j.spi.SLF4JServiceProvider");
+ assertTrue(file.toFile().exists(),
+ "Service descriptor file not found at " + file);
+ try (BufferedReader reader = java.nio.file.Files.newBufferedReader(file)) {
+ String line = reader.readLine();
+ assertNotNull(line);
+ assertEquals(AntSlf4jServiceProvider.class.getName(), line.trim());
+ }
+ } else {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
+ String line = reader.readLine();
+ assertNotNull(line);
+ assertEquals(AntSlf4jServiceProvider.class.getName(), line.trim());
+ }
+ }
+ }
+ }
+
+ @Test
+ void testInitializeCreatesFactories() {
+ AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider();
+ provider.initialize();
+
+ assertNotNull(provider.getLoggerFactory(), "LoggerFactory should not be null after initialize()");
+ assertInstanceOf(AntLoggerFactory.class, provider.getLoggerFactory());
+ assertNotNull(provider.getMarkerFactory(), "MarkerFactory should not be null after initialize()");
+ assertNotNull(provider.getMDCAdapter(), "MDCAdapter should not be null after initialize()");
+ assertEquals("2.0", provider.getRequestedApiVersion());
+ }
+
+ @Test
+ void testLoggerFactoryReturnsAntLoggerAdapter() {
+ AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider();
+ provider.initialize();
+
+ Logger logger = provider.getLoggerFactory().getLogger("test.logger");
+ assertInstanceOf(AntLoggerAdapter.class, logger,
+ "Logger should be an AntLoggerAdapter instance");
+ assertEquals("test.logger", logger.getName());
+ }
+
+ @Test
+ void testLogOutputRoutedThroughAntTask() {
+ Task mockTask = mock(Task.class);
+ AntTaskHolder.setTask(mockTask);
+
+ AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider();
+ provider.initialize();
+ Logger logger = provider.getLoggerFactory().getLogger("test.routing");
+
+ logger.info("hello from SLF4J");
+
+ verify(mockTask).log("hello from SLF4J", Project.MSG_INFO);
+ }
+
+ @Test
+ void testLogLevelMappings() {
+ Task mockTask = mock(Task.class);
+ AntTaskHolder.setTask(mockTask);
+
+ AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider();
+ provider.initialize();
+ Logger logger = provider.getLoggerFactory().getLogger("test.levels");
+
+ logger.trace("trace-msg");
+ verify(mockTask).log("trace-msg", Project.MSG_VERBOSE);
+
+ logger.debug("debug-msg");
+ verify(mockTask).log("debug-msg", Project.MSG_DEBUG);
+
+ logger.info("info-msg");
+ verify(mockTask).log("info-msg", Project.MSG_INFO);
+
+ logger.warn("warn-msg");
+ verify(mockTask).log("warn-msg", Project.MSG_WARN);
+
+ logger.error("error-msg");
+ verify(mockTask).log("error-msg", Project.MSG_ERR);
+ }
+}
diff --git a/pom.xml b/pom.xml
index d8237adc29e..c496e24f10d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,8 +122,8 @@ Copyright (c) 2012 - Jeremy Long
1.10.15
- 1.7.36
- 1.2.13
+ 2.0.17
+ 1.5.25
3.6.3
3.6.0