CPD Results
The following document contains the results of PMD's CPD 7.17.0.
Duplications
| File | Project | Line |
|---|---|---|
| psiprobe/Tomcat10ContainerAdapter.java | psi-probe-tomcat10 | 60 |
| psiprobe/Tomcat11ContainerAdapter.java | psi-probe-tomcat11 | 60 |
|| binding.startsWith("Vmware tc") && binding.contains("/10.1");
}
/**
* Gets the filter mappings.
*
* @param fmap the fmap
* @param dm the dm
* @param filterClass the filter class
*
* @return the filter mappings
*/
protected List<FilterMapping> getFilterMappings(FilterMap fmap, String dm, String filterClass) {
String[] urls = fmap.getURLPatterns();
String[] servlets = fmap.getServletNames();
List<FilterMapping> results = new ArrayList<>(urls.length + servlets.length);
addFilterMapping(fmap.getFilterName(), dm, filterClass, urls, results, FilterMapType.URL);
addFilterMapping(fmap.getFilterName(), dm, filterClass, servlets, results,
FilterMapType.SERVLET_NAME);
return results;
}
@Override
protected JspCompilationContext createJspCompilationContext(String name, Options opt,
ServletContext sctx, JspRuntimeContext jrctx, ClassLoader classLoader) {
JspCompilationContext jcctx = new JspCompilationContext(name, opt, sctx, null, jrctx);
jcctx.setClassLoader(classLoader);
return jcctx;
}
@Override
public void addContextResourceLink(Context context, List<ApplicationResource> resourceList) {
NamingResourcesImpl namingResources = context.getNamingResources();
for (ContextResourceLink link : namingResources.findResourceLinks()) {
ApplicationResource resource = new ApplicationResource();
logger.debug("reading resourceLink: {}", link.getName());
resource.setApplicationName(context.getName());
resource.setName(link.getName());
resource.setType(link.getType());
resource.setLinkTo(link.getGlobal());
registerGlobalResourceAccess(link);
resourceList.add(resource);
}
}
@Override
public void addContextResource(Context context, List<ApplicationResource> resourceList) {
NamingResourcesImpl namingResources = context.getNamingResources();
for (ContextResource contextResource : namingResources.findResources()) {
ApplicationResource resource = new ApplicationResource();
logger.info("reading resource: {}", contextResource.getName());
resource.setApplicationName(context.getName());
resource.setName(contextResource.getName());
resource.setType(contextResource.getType());
resource.setScope(contextResource.getScope());
resource.setAuth(contextResource.getAuth());
resource.setDescription(contextResource.getDescription());
resourceList.add(resource);
}
}
@Override
public List<FilterMapping> getApplicationFilterMaps(Context context) {
FilterMap[] fms = context.findFilterMaps();
List<FilterMapping> filterMaps = new ArrayList<>(fms.length);
for (FilterMap filterMap : fms) {
if (filterMap != null) {
String dm;
switch (filterMap.getDispatcherMapping()) {
case FilterMap.ASYNC:
dm = "ASYNC";
break;
case FilterMap.ERROR:
dm = "ERROR";
break;
case FilterMap.FORWARD:
dm = "FORWARD";
break;
case FilterMap.INCLUDE:
dm = "INCLUDE";
break;
case FilterMap.REQUEST:
dm = "REQUEST";
break;
default:
// Can be any other filters, for those set to space
dm = "";
}
String filterClass = "";
FilterDef fd = context.findFilterDef(filterMap.getFilterName());
if (fd != null) {
filterClass = fd.getFilterClass();
}
List<FilterMapping> filterMappings = getFilterMappings(filterMap, dm, filterClass);
filterMaps.addAll(filterMappings);
}
}
return filterMaps;
}
@Override
public List<FilterInfo> getApplicationFilters(Context context) {
FilterDef[] fds = context.findFilterDefs();
List<FilterInfo> filterDefs = new ArrayList<>(fds.length);
for (FilterDef filterDef : fds) {
if (filterDef != null) {
FilterInfo fi = getFilterInfo(filterDef);
filterDefs.add(fi);
}
}
return filterDefs;
}
/**
* Gets the filter info.
*
* @param fd the fd
*
* @return the filter info
*/
private static FilterInfo getFilterInfo(FilterDef fd) {
FilterInfo fi = new FilterInfo();
fi.setFilterName(fd.getFilterName());
fi.setFilterClass(fd.getFilterClass());
fi.setFilterDesc(fd.getDescription());
return fi;
}
@Override
public List<ApplicationParam> getApplicationInitParams(Context context) {
/*
* We'll try to determine if a parameter value comes from a deployment descriptor or a context
* descriptor.
*
* Assumption: context.findParameter() returns only values of parameters that are declared in a
* deployment descriptor.
*
* If a parameter is declared in a context descriptor with override=false and redeclared in a
* deployment descriptor, context.findParameter() still returns its value, even though the value
* is taken from a context descriptor.
*
* context.findApplicationParameters() returns all parameters that are declared in a context
* descriptor regardless of whether they are overridden in a deployment descriptor or not or
* not.
*/
/*
* creating a set of parameter names that are declared in a context descriptor and can not be
* overridden in a deployment descriptor.
*/
Set<String> nonOverridableParams = new HashSet<>();
for (ApplicationParameter appParam : context.findApplicationParameters()) {
if (appParam != null && !appParam.getOverride()) {
nonOverridableParams.add(appParam.getName());
}
}
List<ApplicationParam> initParams = new ArrayList<>(20);
ServletContext servletCtx = context.getServletContext();
for (String paramName : Collections.list(servletCtx.getInitParameterNames())) {
ApplicationParam param = new ApplicationParam();
param.setName(paramName);
param.setValue(servletCtx.getInitParameter(paramName));
/*
* if the parameter is declared in a deployment descriptor and it is not declared in a context
* descriptor with override=false, the value comes from the deployment descriptor
*/
param.setFromDeplDescr(
context.findParameter(paramName) != null && !nonOverridableParams.contains(paramName));
initParams.add(param);
}
return initParams;
}
@Override
public boolean resourceExists(String name, Context context) {
return context.getResources().getResource(name) != null;
}
@Override
public InputStream getResourceStream(String name, Context context) throws IOException {
WebResource resource = context.getResources().getResource(name);
return resource.getInputStream();
}
@Override
public Long[] getResourceAttributes(String name, Context context) {
Long[] result = new Long[2];
WebResource resource = context.getResources().getResource(name);
result[0] = resource.getContentLength();
result[1] = resource.getLastModified();
return result;
}
/**
* Returns the security token required to bind to a naming context.
*
* @param context the catalina context
*
* @return the security token for use with <code>ContextBindings</code>
*/
@Override
protected Object getNamingToken(Context context) {
// Used by NamingContextListener when setting up JNDI context
Object token = context.getNamingToken();
if (!ContextAccessController.checkSecurityToken(context, token)) {
logger.error("Couldn't get a valid security token. ClassLoader binding will fail.");
}
return token;
}
} | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/logback/LogbackLoggerAccessor.java | psi-probe-core | 71 |
| psiprobe/tools/logging/logback13/Logback13LoggerAccessor.java | psi-probe-core | 68 |
for (LogbackAppenderAccessor wrappedAppender : appenders) {
if (wrappedAppender.getIndex().equals(name)) {
return wrappedAppender;
}
}
}
return wrapAppender(appender);
} catch (Exception e) {
logger.error("{}#getAppender() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Checks if is context.
*
* @return true, if is context
*/
public boolean isContext() {
return false;
}
/**
* Checks if is root.
*
* @return true, if is root
*/
public boolean isRoot() {
return "ROOT".equals(getName());
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return (String) getProperty(getTarget(), "name", null);
}
/**
* Gets the log level of this logger.
*
* @return the level of this logger
*/
public String getLevel() {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
return (String) MethodUtils.invokeMethod(level, "toString");
} catch (Exception e) {
logger.error("{}#getLevel() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Sets the log level of this logger.
*
* @param newLevelStr the name of the new level
*/
public void setLevel(String newLevelStr) {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
Object newLevel = MethodUtils.invokeMethod(level, "toLevel", newLevelStr);
MethodUtils.invokeMethod(getTarget(), "setLevel", newLevel);
} catch (Exception e) {
logger.error("{}#setLevel('{}') failed", getTarget().getClass().getName(), newLevelStr, e);
}
}
/**
* Gets the sifted appenders.
*
* @param appender the appender
*
* @return the sifted appenders
*
* @throws Exception the exception
*/
@SuppressWarnings("unchecked")
private List<Object> getSiftedAppenders(Object appender) throws Exception {
if ("ch.qos.logback.classic.sift.SiftingAppender".equals(appender.getClass().getName())) {
Object tracker = MethodUtils.invokeMethod(appender, "getAppenderTracker");
if (tracker != null) {
return (List<Object>) MethodUtils.invokeMethod(tracker, "allComponents");
}
}
return Collections.emptyList();
}
/**
* Wrap and add appender.
*
* @param appender the appender
* @param appenders the appenders
*/
private void wrapAndAddAppender(Object appender, Collection<LogbackAppenderAccessor> appenders) { | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/logback/LogbackLoggerAccessor.java | psi-probe-core | 71 |
| psiprobe/tools/logging/slf4jlogback/TomcatSlf4jLogbackLoggerAccessor.java | psi-probe-core | 72 |
| psiprobe/tools/logging/slf4jlogback13/TomcatSlf4jLogback13LoggerAccessor.java | psi-probe-core | 72 |
for (LogbackAppenderAccessor wrappedAppender : appenders) {
if (wrappedAppender.getIndex().equals(name)) {
return wrappedAppender;
}
}
}
return wrapAppender(appender);
} catch (Exception e) {
logger.error("{}#getAppender() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Checks if is context.
*
* @return true, if is context
*/
public boolean isContext() {
return false;
}
/**
* Checks if is root.
*
* @return true, if is root
*/
public boolean isRoot() {
return "ROOT".equals(getName());
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return (String) getProperty(getTarget(), "name", null);
}
/**
* Gets the log level of this logger.
*
* @return the level of this logger
*/
public String getLevel() {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
return (String) MethodUtils.invokeMethod(level, "toString");
} catch (Exception e) {
logger.error("{}#getLevel() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Sets the log level of this logger.
*
* @param newLevelStr the name of the new level
*/
public void setLevel(String newLevelStr) {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
Object newLevel = MethodUtils.invokeMethod(level, "toLevel", newLevelStr);
MethodUtils.invokeMethod(getTarget(), "setLevel", newLevel);
} catch (Exception e) {
logger.error("{}#setLevel('{}') failed", getTarget().getClass().getName(), newLevelStr, e);
}
}
/**
* Gets the sifted appenders.
*
* @param appender the appender
*
* @return the sifted appenders
*
* @throws Exception the exception
*/
@SuppressWarnings("unchecked")
private List<Object> getSiftedAppenders(Object appender) throws Exception {
if ("ch.qos.logback.classic.sift.SiftingAppender".equals(appender.getClass().getName())) { | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/logback/LogbackAppenderAccessor.java | psi-probe-core | 72 |
| psiprobe/tools/logging/logback13/Logback13AppenderAccessor.java | psi-probe-core | 72 |
| psiprobe/tools/logging/slf4jlogback/TomcatSlf4jLogbackAppenderAccessor.java | psi-probe-core | 72 |
| psiprobe/tools/logging/slf4jlogback13/TomcatSlf4jLogback13AppenderAccessor.java | psi-probe-core | 72 |
}
/**
* Returns the name of this appender.
*
* @return the name of this appender.
*/
@Override
public String getIndex() {
return (String) getProperty(getTarget(), "name", null);
}
/**
* Returns the file that this appender writes to by accessing the {@code file} bean property of
* the appender.
*
* <p>
* If no such property exists, we assume the appender to write to stdout or stderr so the output
* will be contained in catalina.out.
*
* @return the file this appender writes to
*/
@Override
public File getFile() {
String fileName = (String) getProperty(getTarget(), "file", null);
return fileName != null ? Path.of(fileName).toFile() : getStdoutFile();
}
@Override
public String getEncoding() {
if (getTarget() instanceof OutputStreamAppender appender) {
Encoder<?> encoder = appender.getEncoder();
if (encoder instanceof LayoutWrappingEncoder base) {
if (base.getCharset() != null) {
return base.getCharset().name();
}
}
}
return null;
}
/**
* Gets the level of the associated logger.
*
* @return the logger's level
*/
@Override
public String getLevel() {
return getLoggerAccessor().getLevel();
}
/**
* Returns the valid log level names.
*
* <p>
* Note that Logback has no FATAL level.
*
* @return the valid log level names
*/
@Override
public String[] getValidLevels() {
return new String[] {"OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", "ALL"};
}
} | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/log4j/Log4JLoggerAccessor.java | psi-probe-core | 93 |
| psiprobe/tools/logging/logback/LogbackLoggerAccessor.java | psi-probe-core | 99 |
| psiprobe/tools/logging/logback13/Logback13LoggerAccessor.java | psi-probe-core | 96 |
| psiprobe/tools/logging/slf4jlogback/TomcatSlf4jLogbackLoggerAccessor.java | psi-probe-core | 100 |
| psiprobe/tools/logging/slf4jlogback13/TomcatSlf4jLogback13LoggerAccessor.java | psi-probe-core | 100 |
return "root".equals(getName()) && "org.apache.log4j.spi.RootLogger".equals(getTargetClass());
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return (String) getProperty(getTarget(), "name", null);
}
/**
* Gets the level.
*
* @return the level
*/
public String getLevel() {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
return (String) MethodUtils.invokeMethod(level, "toString");
} catch (Exception e) {
logger.error("{}#getLevel() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Sets the level.
*
* @param newLevelStr the new level
*/
public void setLevel(String newLevelStr) {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
Object newLevel = MethodUtils.invokeMethod(level, "toLevel", newLevelStr);
MethodUtils.invokeMethod(getTarget(), "setLevel", newLevel);
} catch (Exception e) {
logger.error("{}#setLevel('{}') failed", getTarget().getClass().getName(), newLevelStr, e);
}
} | ||
| File | Project | Line |
|---|---|---|
| psiprobe/controllers/deploy/CopySingleFileController.java | psi-probe-core | 72 |
| psiprobe/controllers/deploy/DeployController.java | psi-probe-core | 46 |
HttpServletRequest request) throws IOException {
List<Context> apps;
try {
apps = getContainerWrapper().getTomcatContainer().findContexts();
} catch (NullPointerException ex) {
throw new IllegalStateException(
"No container found for your server: " + getServletContext().getServerInfo(), ex);
}
List<Map<String, String>> applications = new ArrayList<>();
for (Context appContext : apps) {
// check if this is not the ROOT webapp
if (!Strings.isNullOrEmpty(appContext.getName())) {
Map<String, String> app = new HashMap<>();
app.put("value", appContext.getName());
app.put("label", appContext.getName());
applications.add(app);
}
}
request.setAttribute("apps", applications); | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/log4j2/Log4J2LoggerConfigAccessor.java | psi-probe-core | 145 |
| psiprobe/tools/logging/logback/LogbackLoggerAccessor.java | psi-probe-core | 99 |
| psiprobe/tools/logging/logback13/Logback13LoggerAccessor.java | psi-probe-core | 96 |
| psiprobe/tools/logging/slf4jlogback/TomcatSlf4jLogbackLoggerAccessor.java | psi-probe-core | 100 |
| psiprobe/tools/logging/slf4jlogback13/TomcatSlf4jLogback13LoggerAccessor.java | psi-probe-core | 100 |
return Strings.isNullOrEmpty(getName());
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return (String) getProperty(getTarget(), "name", null);
}
/**
* Gets the level.
*
* @return the level
*/
public String getLevel() {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
return (String) MethodUtils.invokeMethod(level, "toString");
} catch (Exception e) {
logger.error("{}#getLevel() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Sets the level.
*
* @param newLevelStr the new level
*/
public void setLevel(String newLevelStr) {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
Object newLevel = MethodUtils.invokeMethod(level, "toLevel", newLevelStr);
MethodUtils.invokeMethod(getTarget(), "setLevel", newLevel); | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/log4j/Log4JLoggerAccessor.java | psi-probe-core | 93 |
| psiprobe/tools/logging/log4j2/Log4J2LoggerConfigAccessor.java | psi-probe-core | 145 |
return "root".equals(getName()) && "org.apache.log4j.spi.RootLogger".equals(getTargetClass());
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return (String) getProperty(getTarget(), "name", null);
}
/**
* Gets the level.
*
* @return the level
*/
public String getLevel() {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
return (String) MethodUtils.invokeMethod(level, "toString");
} catch (Exception e) {
logger.error("{}#getLevel() failed", getTarget().getClass().getName(), e);
}
return null;
}
/**
* Sets the level.
*
* @param newLevelStr the new level
*/
public void setLevel(String newLevelStr) {
try {
Object level = MethodUtils.invokeMethod(getTarget(), "getLevel");
Object newLevel = MethodUtils.invokeMethod(level, "toLevel", newLevelStr);
MethodUtils.invokeMethod(getTarget(), "setLevel", newLevel); | ||
| File | Project | Line |
|---|---|---|
| psiprobe/beans/accessors/Dbcp2DatasourceAccessor.java | psi-probe-core | 20 |
| psiprobe/beans/accessors/OpenEjbBasicDatasourceAccessor.java | psi-probe-core | 20 |
public class Dbcp2DatasourceAccessor implements DatasourceAccessor {
@Override
public DataSourceInfo getInfo(Object resource) {
DataSourceInfo dataSourceInfo = null;
if (canMap(resource)) {
BasicDataSource source = (BasicDataSource) resource;
dataSourceInfo = new DataSourceInfo();
dataSourceInfo.setBusyConnections(source.getNumActive());
dataSourceInfo.setEstablishedConnections(source.getNumIdle() + source.getNumActive());
dataSourceInfo.setMaxConnections(source.getMaxTotal());
dataSourceInfo.setJdbcUrl(source.getUrl());
dataSourceInfo.setUsername(source.getUserName());
dataSourceInfo.setResettable(false);
dataSourceInfo.setType("commons-dbcp2");
}
return dataSourceInfo;
}
@Override
public boolean reset(Object resource) {
return false;
}
@Override
public boolean canMap(Object resource) {
return "org.apache.commons.dbcp2.BasicDataSource".equals(resource.getClass().getName()) | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/logback13/Logback13FactoryAccessor.java | psi-probe-core | 47 |
| psiprobe/tools/logging/slf4jlogback13/TomcatSlf4jLogback13FactoryAccessor.java | psi-probe-core | 48 |
public Logback13FactoryAccessor(ClassLoader cl)
throws ClassNotFoundException, IllegalAccessException, InvocationTargetException,
NoSuchMethodException, SecurityException, IllegalArgumentException {
// Get the SLF4J provider binding, which may or may not be Logback, depending on the binding.
final List<?> providers = findServiceProviders(cl);
if (providers.isEmpty()) {
throw new RuntimeException("The SLF4J provider binding was not Logback");
}
// Get the service provider
Object provider = providers.get(0);
// Initialize the service provider
Method initialize = MethodUtils.getAccessibleMethod(provider.getClass(), "initialize");
initialize.invoke(provider);
// Call the logger factory
Method getLoggerFactory =
MethodUtils.getAccessibleMethod(provider.getClass(), "getLoggerFactory");
Object loggerFactory = getLoggerFactory.invoke(provider);
// Check if the binding is indeed Logback
Class<?> loggerFactoryClass = cl.loadClass("ch.qos.logback.classic.LoggerContext"); | ||
| File | Project | Line |
|---|---|---|
| psiprobe/beans/accessors/Dbcp2DatasourceAccessor.java | psi-probe-core | 20 |
| psiprobe/beans/accessors/Tomcat10DbcpDatasourceAccessor.java | psi-probe-tomcat10 | 20 |
| psiprobe/beans/accessors/Tomcat11DbcpDatasourceAccessor.java | psi-probe-tomcat11 | 20 |
public class Dbcp2DatasourceAccessor implements DatasourceAccessor {
@Override
public DataSourceInfo getInfo(Object resource) {
DataSourceInfo dataSourceInfo = null;
if (canMap(resource)) {
BasicDataSource source = (BasicDataSource) resource;
dataSourceInfo = new DataSourceInfo();
dataSourceInfo.setBusyConnections(source.getNumActive());
dataSourceInfo.setEstablishedConnections(source.getNumIdle() + source.getNumActive());
dataSourceInfo.setMaxConnections(source.getMaxTotal());
dataSourceInfo.setJdbcUrl(source.getUrl());
dataSourceInfo.setUsername(source.getUserName());
dataSourceInfo.setResettable(false);
dataSourceInfo.setType("commons-dbcp2"); | ||
| File | Project | Line |
|---|---|---|
| psiprobe/beans/accessors/TomEeJdbcPoolDatasourceAccessor.java | psi-probe-core | 28 |
| psiprobe/beans/accessors/TomcatJdbcPoolDatasourceAccessor.java | psi-probe-core | 26 |
(TomEEDataSourceCreator.TomEEDataSource) resource;
dataSourceInfo = new DataSourceInfo();
dataSourceInfo.setBusyConnections(source.getNumActive());
dataSourceInfo.setEstablishedConnections(source.getNumIdle() + source.getNumActive());
dataSourceInfo.setMaxConnections(source.getMaxActive());
dataSourceInfo.setJdbcUrl(source.getUrl());
dataSourceInfo.setUsername(source.getUsername());
dataSourceInfo.setResettable(false);
dataSourceInfo.setType("tomcat-jdbc");
}
return dataSourceInfo;
}
@Override
public boolean reset(Object resource) {
return false;
}
@Override
public boolean canMap(Object resource) {
return "org.apache.tomee.jdbc.TomEEDataSourceCreator$TomEEDataSource" | ||
| File | Project | Line |
|---|---|---|
| psiprobe/tools/logging/logback/LogbackLoggerAccessor.java | psi-probe-core | 37 |
| psiprobe/tools/logging/slf4jlogback/TomcatSlf4jLogbackLoggerAccessor.java | psi-probe-core | 37 |
| psiprobe/tools/logging/slf4jlogback13/TomcatSlf4jLogback13LoggerAccessor.java | psi-probe-core | 37 |
List<LogbackAppenderAccessor> appenders = new ArrayList<>();
try {
for (Object appender : Collections.list(Iterators.asEnumeration(
(Iterator<Object>) MethodUtils.invokeMethod(getTarget(), "iteratorForAppenders")))) {
List<Object> siftedAppenders = getSiftedAppenders(appender);
if (!siftedAppenders.isEmpty()) {
for (Object siftedAppender : siftedAppenders) {
wrapAndAddAppender(siftedAppender, appenders);
}
} else {
wrapAndAddAppender(appender, appenders);
}
}
} catch (NoClassDefFoundError e) {
logger.error("{}#getAppenders() failed, To see this logger, upgrade slf4j to 1.7.21+", | ||


