diff --git a/pax-logging-log4j2-maven-plugin/pom.xml b/pax-logging-log4j2-maven-plugin/pom.xml new file mode 100644 index 000000000..f6b00b367 --- /dev/null +++ b/pax-logging-log4j2-maven-plugin/pom.xml @@ -0,0 +1,104 @@ + + + + + 4.0.0 + + + org.ops4j.pax + logging + 2.2.8-SNAPSHOT + ../pom.xml + + + org.ops4j.pax.logging + pax-logging-log4j2-maven-plugin + maven-plugin + + OPS4J Pax Logging - Maven plugin + + + This plugin is used to generate additional /META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat + files available from additional entries on Bundle-ClassPath. + + + + + + org.apache.maven.plugins + maven-plugin-plugin + + + org.codehaus.plexus + plexus-component-metadata + + + + generate-metadata + + + + + + + + + + + + + org.apache.logging.log4j + log4j-api + provided + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-layout-template-json + provided + + + + + + org.apache.maven + maven-core + provided + + + org.apache.maven + maven-plugin-api + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + provided + true + + + + + diff --git a/pax-logging-log4j2-maven-plugin/src/main/java/org/ops4j/pax/logging/log4j/maven/Generate.java b/pax-logging-log4j2-maven-plugin/src/main/java/org/ops4j/pax/logging/log4j/maven/Generate.java new file mode 100644 index 000000000..944ae9b3b --- /dev/null +++ b/pax-logging-log4j2-maven-plugin/src/main/java/org/ops4j/pax/logging/log4j/maven/Generate.java @@ -0,0 +1,162 @@ +/* + * Copyright 2020 OPS4J. + * + * 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. + */ +package org.ops4j.pax.logging.log4j.maven; + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.inject.Inject; + +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry; +import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; +import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Dependency; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.repository.RepositorySystem; + +/** + * Log4j2 has deprecated {@code org.apache.logging.log4j.core.config.plugins.util.PluginManager#addPackage()} method, + * so we need to allow Log4j to discover another location of {@code Log4j2Plugins.dat} file. + * This plugin generates such file into a Jar which will be added to {@code Bundle-ClassPath} OSGi manifest header + * (because we can't override the file coming from log4j-core...). + */ +@Mojo(name = "generate-log4j-plugin-descriptor", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true, aggregator = true) +public class Generate extends AbstractMojo { + + @Parameter(defaultValue = "${project}", readonly = true) + private MavenProject project; + + @Parameter(defaultValue = "${session}", readonly = true) + private MavenSession session; + + @Inject + private RepositorySystem system; + + @Parameter + private String[] plugins; + + @Override + public void execute() { + // prepare classpath + Set locations = new LinkedHashSet<>(); + locations.add(project.getBuild().getOutputDirectory()); + ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler(); + for (Dependency d : project.getDependencies()) { + ArtifactResolutionRequest req = new ArtifactResolutionRequest(); + DefaultArtifact artifact = new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(), d.getType(), d.getClassifier(), artifactHandler); + req.setArtifact(artifact); + ArtifactResolutionResult result = system.resolve(req); + if (!result.hasExceptions()) { + for (Artifact a : result.getArtifacts()) { + locations.add(a.getFile().getAbsolutePath()); + } + } + } + + List cp = new ArrayList<>(); + for (String loc : locations) { + try { + cp.add(new File(loc).toURI().toURL()); + } catch (MalformedURLException ignored) { + } + } + + Set> classes = new LinkedHashSet<>(); + List foundAnnotations = new LinkedList<>(); + Map> a2c = new IdentityHashMap<>(); + try (URLClassLoader cl = new URLClassLoader(cp.toArray(new URL[0]), Plugin.class.getClassLoader())) { + for (String plugin : plugins) { + try { + Class pluginClass = cl.loadClass(plugin); + getLog().info("Analyzing package " + pluginClass.getPackage().getName()); + collectPlugins(cl, pluginClass.getPackage(), foundAnnotations, a2c); + } catch (ClassNotFoundException e) { + getLog().warn("Can't load " + plugin + ":" + e.getMessage()); + } + } + } catch (IOException ignored) { + } + + // keyed by plugin category + final Map> pluginMap = new LinkedHashMap<>(); + foundAnnotations.forEach(p -> pluginMap.computeIfAbsent(p.category(), k -> new ArrayList<>()).add(p)); + + // see org.apache.logging.log4j.core.config.plugins.processor.PluginCache.loadCacheFiles() + File log4jPluginDataJar = new File(project.getBuild().getOutputDirectory(), "META-INF/pax-logging-log4j-plugins/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat"); + log4jPluginDataJar.getParentFile().mkdirs(); + try (final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(Files.newOutputStream(log4jPluginDataJar.toPath())))) { + out.writeInt(pluginMap.size()); + for (Map.Entry> entry : pluginMap.entrySet()) { + String category = entry.getKey(); + List pluginsInCategory = entry.getValue(); + out.writeUTF(category.toLowerCase(Locale.ROOT)); + out.writeInt(pluginsInCategory.size()); + for (Plugin plugin : pluginsInCategory) { + // Must always read all parts of the entry, even if not adding, so that the stream progresses + // see org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PluginElementVisitor.visitType() + out.writeUTF(plugin.name().toLowerCase(Locale.ROOT)); + out.writeUTF(a2c.get(plugin).getName()); + out.writeUTF(Plugin.EMPTY.equals(plugin.elementType()) ? plugin.name() : plugin.elementType()); + out.writeBoolean(plugin.printObject()); + out.writeBoolean(plugin.deferChildren()); + + } + } + } catch (IOException e) { + getLog().error("Can't write jar file with Pax Logging Lo4j2 annotation data", e); + } + } + + private void collectPlugins(ClassLoader loader, Package pkg, List foundAnnotations, Map> a2c) { + final ResolverUtil resolver = new ResolverUtil(); + resolver.setClassLoader(loader); + resolver.findInPackage(new PluginRegistry.PluginTest(), pkg.getName()); + + for (Class cls : resolver.getClasses()) { + final Plugin annotation = cls.getAnnotation(Plugin.class); + if (annotation != null) { + getLog().info(" Found plugin " + cls.getName()); + foundAnnotations.add(annotation); + a2c.put(annotation, cls); + } + } + } + +} diff --git a/pax-logging-log4j2/osgi.bnd b/pax-logging-log4j2/osgi.bnd index 5346a7038..d692b73e5 100644 --- a/pax-logging-log4j2/osgi.bnd +++ b/pax-logging-log4j2/osgi.bnd @@ -19,6 +19,8 @@ Bundle-Activator: org.ops4j.pax.logging.log4j2.internal.Activator +Bundle-ClassPath: ., META-INF/pax-logging-log4j-plugins + Private-Package: \ org.apache.logging.log4j.core.*; -split-package:=merge-first, \ org.apache.logging.log4j.layout.*; -split-package:=merge-first, \ @@ -30,6 +32,7 @@ Private-Package: \ Include-Resource: \ {maven-resources}, \ META-INF/maven=target/classes/META-INF/maven, \ + META-INF/pax-logging-log4j-plugins=target/classes/META-INF/pax-logging-log4j-plugins, \ META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat=target/classes/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat, \ /=target/classes;filter:=*.json;recursive:=false, \ /=target/classes;filter:=*.xsd;recursive:=false, \ diff --git a/pax-logging-log4j2/pom.xml b/pax-logging-log4j2/pom.xml index aefeea095..21f8de6bf 100644 --- a/pax-logging-log4j2/pom.xml +++ b/pax-logging-log4j2/pom.xml @@ -153,6 +153,28 @@ + + org.ops4j.pax.logging + pax-logging-log4j2-maven-plugin + + + generate-pax-logging-log4j2-plugin-descriptor + prepare-package + + generate-log4j-plugin-descriptor + + + + + org.ops4j.pax.logging.log4j2.internal.bridges.PaxOsgiAppender + org.apache.logging.log4j.layout.template.json.JsonTemplateLayout + org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory + org.apache.logging.log4j.layout.template.json.util.RecyclerFactoryConverter + + + + + org.apache.maven.plugins maven-jar-plugin @@ -199,6 +221,12 @@ org.ops4j.pax.logging pax-logging-api + + + org.ops4j.pax.logging + pax-logging-log4j2-maven-plugin + runtime + diff --git a/pax-logging-log4j2/src/main/java/org/ops4j/pax/logging/log4j2/internal/PaxLoggingServiceImpl.java b/pax-logging-log4j2/src/main/java/org/ops4j/pax/logging/log4j2/internal/PaxLoggingServiceImpl.java index 7e483c0d0..40b010a74 100644 --- a/pax-logging-log4j2/src/main/java/org/ops4j/pax/logging/log4j2/internal/PaxLoggingServiceImpl.java +++ b/pax-logging-log4j2/src/main/java/org/ops4j/pax/logging/log4j2/internal/PaxLoggingServiceImpl.java @@ -76,10 +76,13 @@ public class PaxLoggingServiceImpl implements PaxLoggingService, ServiceFactory< // We don't have to add "org.apache.logging.log4j.core", because this package will be handled // using default cache file "/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat" // taken unchanged from "org.apache.logging.log4j:log4j-core". - PluginManager.addPackage(PaxOsgiAppender.class.getPackage().getName()); - PluginManager.addPackage(JsonTemplateLayout.class.getPackage().getName()); - PluginManager.addPackage(LoggerResolverFactory.class.getPackage().getName()); - PluginManager.addPackage(RecyclerFactoryConverter.class.getPackage().getName()); + // plugins are now added using org.ops4j.pax.logging:pax-logging-log4j2-maven-plugin + // and the descriptor it generates, because + // org.apache.logging.log4j.core.config.plugins.util.PluginManager.addPackage() is now deprecated +// PluginManager.addPackage(PaxOsgiAppender.class.getPackage().getName()); +// PluginManager.addPackage(JsonTemplateLayout.class.getPackage().getName()); +// PluginManager.addPackage(LoggerResolverFactory.class.getPackage().getName()); +// PluginManager.addPackage(RecyclerFactoryConverter.class.getPackage().getName()); } private final BundleContext m_bundleContext; diff --git a/pom.xml b/pom.xml index 47b7d6ea3..80736711a 100644 --- a/pom.xml +++ b/pom.xml @@ -234,6 +234,8 @@ 6.0.5 7.0.5 2.24.1 + 3.9.9 + 3.15.0 1_3 1.2.14 @@ -267,6 +269,7 @@ 3.2.7 3.1.3 3.8.0 + 3.15.0 3.4.2 3.10.0 3.1.1 @@ -280,6 +283,7 @@ + 2.2.0 5.1.9 3.6.0 4.6 @@ -405,6 +409,11 @@ maven-invoker-plugin ${plugin.maven-invoker-plugin} + + org.apache.maven.plugins + maven-plugin-plugin + ${version.plugin.maven-plugin-plugin} + org.apache.maven.plugins maven-release-plugin @@ -481,6 +490,17 @@ license-maven-plugin ${plugin.mycila.license-maven-plugin} + + org.codehaus.plexus + plexus-component-metadata + ${plugin.codehaus.plexus-component-metadata} + + + + org.ops4j.pax.logging + pax-logging-log4j2-maven-plugin + ${project.version} + @@ -586,6 +606,11 @@ pax-logging-log4j2 ${project.version} + + org.ops4j.pax.logging + pax-logging-log4j2-maven-plugin + ${project.version} + org.ops4j.pax.logging @@ -948,6 +973,24 @@ + + + + org.apache.maven + maven-core + ${version.org.apache.maven} + + + org.apache.maven + maven-plugin-api + ${version.org.apache.maven} + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${version.org.apache.maven.plugin-tools} + + @@ -1009,6 +1052,7 @@ pax-logging-api pax-logging-api-test + pax-logging-log4j2-maven-plugin pax-logging-log4j2 pax-logging-log4j2-extra pax-logging-logback