This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch doc-reference
in repository https://gitbox.apache.org/repos/asf/logging-log4j-tools.git
The following commit(s) were added to refs/heads/doc-reference by this push:
new 2f6b96f Add XSD generator
2f6b96f is described below
commit 2f6b96f28390c5235ac7576d59b42703d0e10830
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Mon Dec 4 10:00:20 2023 +0100
Add XSD generator
---
log4j-changelog-maven-plugin/.mvn | 1 +
log4j-changelog/.mvn | 1 +
log4j-docgen/.mvn | 1 +
{log4j-doc-reference => log4j-docgen}/pom.xml | 68 ++++-
.../logging/log4j/docgen/SchemaGenerator.java | 27 ++
.../docgen/internal/DefaultSchemaGenerator.java | 340 +++++++++++++++++++++
log4j-docgen/src/main/mdo/plugins.xml | 306 +++++++++++++++++++
.../log4j/docgen/internal/configuration.xml | 151 +++++++++
.../org.apache.logging.log4j.core.Appender.adoc | 0
...ogging.log4j.core.appender.ConsoleAppender.adoc | 0
....logging.log4j.core.config.AppendersPlugin.adoc | 0
...he.logging.log4j.core.config.Configuration.adoc | 0
.../src/site/Properties/index.adoc | 0
.../src/site/TypeConverters/index.adoc | 0
.../logging/log4j/docgen/SchemaGeneratorTest.java | 45 +++
log4j-docgen/src/test/resources/expected-log4j.xsd | 229 ++++++++++++++
.../src/test/resources/log4j-plugins.xml | 0
.../src/test/resources/log4j.xsd | 0
log4j-docgen/src/test/resources/test-plugins.xml | 250 +++++++++++++++
log4j-tools-parent/.mvn | 1 +
log4j-tools-parent/pom.xml | 40 ++-
pom.xml | 2 +-
22 files changed, 1443 insertions(+), 19 deletions(-)
diff --git a/log4j-changelog-maven-plugin/.mvn
b/log4j-changelog-maven-plugin/.mvn
new file mode 120000
index 0000000..19172e1
--- /dev/null
+++ b/log4j-changelog-maven-plugin/.mvn
@@ -0,0 +1 @@
+../.mvn
\ No newline at end of file
diff --git a/log4j-changelog/.mvn b/log4j-changelog/.mvn
new file mode 120000
index 0000000..19172e1
--- /dev/null
+++ b/log4j-changelog/.mvn
@@ -0,0 +1 @@
+../.mvn
\ No newline at end of file
diff --git a/log4j-docgen/.mvn b/log4j-docgen/.mvn
new file mode 120000
index 0000000..19172e1
--- /dev/null
+++ b/log4j-docgen/.mvn
@@ -0,0 +1 @@
+../.mvn
\ No newline at end of file
diff --git a/log4j-doc-reference/pom.xml b/log4j-docgen/pom.xml
similarity index 53%
rename from log4j-doc-reference/pom.xml
rename to log4j-docgen/pom.xml
index 084ade1..c382738 100644
--- a/log4j-doc-reference/pom.xml
+++ b/log4j-docgen/pom.xml
@@ -24,7 +24,7 @@
<relativePath>../log4j-tools-parent</relativePath>
</parent>
- <artifactId>log4j-doc-reference</artifactId>
+ <artifactId>log4j-docgen</artifactId>
<properties>
<bnd.baseline.fail.on.missing>false</bnd.baseline.fail.on.missing>
@@ -44,15 +44,73 @@
</dependencyManagement>
<dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.13.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>txw2</artifactId>
+ <version>3.0.2</version>
+ </dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
- <version>2.22.0</version>
+ <version>3.0.0-SNAPSHOT</version>
</dependency>
<dependency>
- <groupId>org.codehaus.modello</groupId>
- <artifactId>modello-plugin-xsd</artifactId>
- <version>2.1.2</version>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-plugin-processor</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
+
+ <repositories>
+ <repository>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <id>apache.https.snapshots</id>
+ <url>https://repository.apache.org/snapshots</url>
+ </repository>
+ </repositories>
+ <build>
+ <plugins>
+
+ <plugin>
+ <groupId>org.codehaus.modello</groupId>
+ <artifactId>modello-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-model</id>
+ <goals>
+ <goal>java</goal>
+ <goal>stax-reader</goal>
+ <goal>stax-writer</goal>
+ <goal>xdoc</goal>
+ <goal>xsd</goal>
+ </goals>
+ <configuration>
+ <domAsXpp3>false</domAsXpp3>
+ <models>
+ <model>src/main/mdo/plugins.xml</model>
+ </models>
+ <version>0.1.0</version>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
</project>
diff --git
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/SchemaGenerator.java
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/SchemaGenerator.java
new file mode 100644
index 0000000..7764b32
--- /dev/null
+++
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/SchemaGenerator.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.apache.logging.log4j.docgen;
+
+import java.util.Collection;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.logging.log4j.docgen.model.PluginBundle;
+
+public interface SchemaGenerator {
+
+ void generateSchema(Collection<PluginBundle> bundles, XMLStreamWriter
writer) throws XMLStreamException;
+}
diff --git
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/internal/DefaultSchemaGenerator.java
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/internal/DefaultSchemaGenerator.java
new file mode 100644
index 0000000..f29280c
--- /dev/null
+++
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/internal/DefaultSchemaGenerator.java
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.apache.logging.log4j.docgen.internal;
+
+import com.sun.xml.txw2.output.IndentingXMLStreamWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.logging.log4j.docgen.SchemaGenerator;
+import org.apache.logging.log4j.docgen.model.Description;
+import org.apache.logging.log4j.docgen.model.EnumType;
+import org.apache.logging.log4j.docgen.model.EnumValue;
+import org.apache.logging.log4j.docgen.model.PluginAttribute;
+import org.apache.logging.log4j.docgen.model.PluginBundle;
+import org.apache.logging.log4j.docgen.model.PluginElement;
+import org.apache.logging.log4j.docgen.model.PluginEntry;
+import org.apache.logging.log4j.docgen.model.io.stax.PluginBundleStaxReader;
+
+public class DefaultSchemaGenerator implements SchemaGenerator {
+
+ private static final String PLUGIN_NAMESPACE = "Core";
+ private static final String LOG4J_PREFIX = "log4j";
+ private static final String LOG4J_NAMESPACE =
"http://logging.apache.org/log4j/2.0/config";
+ private static final String XSD_NAMESPACE =
"http://www.w3.org/2001/XMLSchema";
+ private static final String MULTIPLICITY_UNBOUNDED = "*";
+
+ @Override
+ public void generateSchema(Collection<PluginBundle> bundles,
XMLStreamWriter writer) throws XMLStreamException {
+ try {
+ final PluginBundle configurationBundle =
+ new
PluginBundleStaxReader().read(getClass().getResourceAsStream("configuration.xml"));
+ final Set<PluginBundle> extendedBundles = new HashSet<>(bundles);
+ extendedBundles.add(configurationBundle);
+ final TypeLookup lookup = new TypeLookup(extendedBundles);
+ writeSchema(lookup, new IndentingXMLStreamWriter(writer));
+ } catch (IOException e) {
+ throw new XMLStreamException(e);
+ }
+ }
+
+ private void writeSchema(final TypeLookup lookup, final XMLStreamWriter
writer) throws XMLStreamException {
+ writer.writeStartDocument("UTF-8", "1.0");
+ writer.setDefaultNamespace(XSD_NAMESPACE);
+ writer.writeStartElement(XSD_NAMESPACE, "schema");
+ writer.writeDefaultNamespace(XSD_NAMESPACE);
+ writer.writeNamespace(LOG4J_PREFIX, LOG4J_NAMESPACE);
+ writer.writeAttribute("elementFormDefault", "qualified");
+ writer.writeAttribute("targetNamespace", LOG4J_NAMESPACE);
+
+ // The root element
+ writer.writeEmptyElement(XSD_NAMESPACE, "element");
+ writer.writeAttribute("type", LOG4J_PREFIX +
":org.apache.logging.log4j.core.config.Configuration");
+ writer.writeAttribute("name", "Configuration");
+
+ // Simple types
+ writeEnumTypes(lookup.getRequiredEnums(), writer);
+
+ // Plugins
+ writePluginEntries(lookup, writer);
+
+ // Interfaces
+ writeGroups(lookup, lookup.getRequiredGroups(), writer);
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ }
+
+ private void writePluginEntries(final TypeLookup lookup, final
XMLStreamWriter writer) throws XMLStreamException {
+ for (final PluginEntry entry : lookup.getPlugins()) {
+ writePluginEntry(lookup, entry, writer);
+ }
+ }
+
+ private void writePluginEntry(final TypeLookup lookup, final PluginEntry
entry, final XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement(XSD_NAMESPACE, "complexType");
+ writer.writeAttribute("name", entry.getClassName());
+
+ final boolean hasSimpleContent = entry.getElements().isEmpty();
+
+ if (!hasSimpleContent) {
+ writer.writeStartElement(XSD_NAMESPACE, "sequence");
+ for (final PluginElement element : entry.getElements()) {
+ writePluginElement(lookup, element, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ for (final PluginAttribute attribute : entry.getAttributes()) {
+ writePluginAttribute(lookup, attribute, writer);
+ }
+
+ writer.writeEndElement();
+ }
+
+ private void writePluginElement(final TypeLookup lookup, final
PluginElement element, final XMLStreamWriter writer)
+ throws XMLStreamException {
+ final String type = element.getType();
+ final String xmlType = lookup.getXmlType(type, false);
+ final PluginEntry entry = lookup.getPluginByType(type);
+ /*
+ * If some plugins have `type` as super type or if the type is unknown,
+ * we use a <group> element.
+ */
+ if (lookup.getPluginsByGroup(type) != null || entry == null) {
+ writer.writeStartElement(XSD_NAMESPACE, "group");
+ writer.writeAttribute("ref", xmlType);
+ writeMultiplicity(element.isRequired(), element.getMultiplicity(),
writer);
+ writeDocumentation(element.getDescription(), writer);
+ writer.writeEndElement();
+ } else
+ for (final String key : entry.getKeys()) {
+ writer.writeStartElement(XSD_NAMESPACE, "element");
+ writer.writeAttribute("name", key);
+ writer.writeAttribute("type", xmlType);
+ writeMultiplicity(element.isRequired(),
element.getMultiplicity(), writer);
+ writeDocumentation(element.getDescription(), writer);
+ writer.writeEndElement();
+ }
+ }
+
+ private void writeMultiplicity(final boolean required, final String
multiplicity, final XMLStreamWriter writer)
+ throws XMLStreamException {
+ if (!required) {
+ writer.writeAttribute("minOccurs", "0");
+ }
+ if (MULTIPLICITY_UNBOUNDED.equals(multiplicity)) {
+ writer.writeAttribute("maxOccurs", "unbounded");
+ }
+ }
+
+ private void writePluginAttribute(
+ final TypeLookup lookup, final PluginAttribute attribute, final
XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement(XSD_NAMESPACE, "attribute");
+ writer.writeAttribute("name", attribute.getName());
+ writer.writeAttribute("type", lookup.getXmlType(attribute.getType(),
true));
+ final Description description = attribute.getDescription();
+ if (description != null) {
+ writeDocumentation(description, writer);
+ }
+ writer.writeEndElement();
+ }
+
+ private void writeDocumentation(final Description description, final
XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement(XSD_NAMESPACE, "annotation");
+ writer.writeStartElement(XSD_NAMESPACE, "documentation");
+ writer.writeCharacters(normalizeAsciidoc(description.getText()));
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+
+ private String normalizeAsciidoc(final String text) {
+ final StringBuilder sb = new StringBuilder();
+ for (final String line : text.split("\r?\n", -1)) {
+ sb.append(line.trim()).append('\n');
+ }
+ final int length = sb.length();
+ if (length > 0) {
+ sb.setLength(length - 1);
+ }
+ return sb.toString();
+ }
+
+ private void writeEnumTypes(final Collection<EnumType> types, final
XMLStreamWriter writer)
+ throws XMLStreamException {
+ for (final EnumType type : types) {
+ writeEnumType(type, writer);
+ }
+ }
+
+ private void writeGroups(final TypeLookup lookup, final Collection<String>
groups, final XMLStreamWriter writer)
+ throws XMLStreamException {
+ for (final String group : groups) {
+ writeGroup(
+ lookup,
+ group,
+
Optional.ofNullable(lookup.getPluginsByGroup(group)).orElse(Collections.emptySet()),
+ writer);
+ }
+ }
+
+ private void writeGroup(
+ final TypeLookup lookup,
+ final String groups,
+ final Collection<PluginEntry> entries,
+ final XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement(XSD_NAMESPACE, "group");
+ writer.writeAttribute("name", groups + ".group");
+ writer.writeStartElement(XSD_NAMESPACE, "choice");
+
+ for (final PluginEntry entry : entries) {
+ final Set<String> actualKeys = new HashSet<>(entry.getKeys());
+ actualKeys.add(entry.getName());
+ for (final String key : actualKeys) {
+ writer.writeEmptyElement(XSD_NAMESPACE, "element");
+ writer.writeAttribute("name", key);
+ writer.writeAttribute("type", LOG4J_PREFIX + ":" +
entry.getClassName());
+ }
+ }
+
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+
+ private void writeEnumType(final EnumType type, final XMLStreamWriter
writer) throws XMLStreamException {
+ writer.writeStartElement(XSD_NAMESPACE, "simpleType");
+ writer.writeAttribute("name", type.getClassName());
+
+ writer.writeStartElement(XSD_NAMESPACE, "restriction");
+ writer.writeAttribute("base", "string");
+
+ for (final EnumValue value : type.getValues()) {
+ writeEnumValue(value, writer);
+ }
+
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+
+ private void writeEnumValue(final EnumValue value, final XMLStreamWriter
writer) throws XMLStreamException {
+ writer.writeStartElement(XSD_NAMESPACE, "enumeration");
+ writer.writeAttribute("value", value.getName());
+
+ writeDocumentation(value, writer);
+
+ writer.writeEndElement();
+ }
+
+ private static class TypeLookup {
+
+ private final Map<String, EnumType> enumByName = new HashMap<>();
+ private final Map<String, PluginEntry> pluginsByName = new TreeMap<>();
+ private final Map<String, Set<PluginEntry>> pluginsByGroup = new
HashMap<>();
+ private final Set<EnumType> requiredEnums = new
TreeSet<>(Comparator.comparing(EnumType::getClassName));
+ private final Set<String> requiredGroups = new TreeSet<>();
+
+ public TypeLookup(final Collection<PluginBundle> bundles) {
+ bundles.forEach(bundle -> {
+ bundle.getPlugins().forEach(entry -> {
+ if (PLUGIN_NAMESPACE.equals(entry.getNamespace())) {
+ pluginsByName.put(entry.getClassName(), entry);
+ entry.getSupertypes().forEach(type -> pluginsByGroup
+ .computeIfAbsent(type, ignored -> new
HashSet<>())
+ .add(entry));
+ }
+ });
+ bundle.getEnums().forEach(enumType ->
enumByName.put(enumType.getClassName(), enumType));
+ });
+ // Validates the required types.
+ validateTypes();
+ }
+
+ private void validateTypes() {
+ getPlugins().forEach(entry -> {
+ entry.getAttributes().forEach(attribute ->
getXmlType(attribute.getType(), true));
+ entry.getElements().forEach(element ->
getXmlType(element.getType(), false));
+ });
+ }
+
+ public Collection<EnumType> getRequiredEnums() {
+ return requiredEnums;
+ }
+
+ public Collection<String> getRequiredGroups() {
+ return requiredGroups;
+ }
+
+ public Set<PluginEntry> getPluginsByGroup(final String group) {
+ return pluginsByGroup.get(group);
+ }
+
+ public Collection<PluginEntry> getPlugins() {
+ return pluginsByName.values();
+ }
+
+ public PluginEntry getPluginByType(final String javaType) {
+ return pluginsByName.get(javaType);
+ }
+
+ public String getXmlType(final String javaType, final boolean simple) {
+ switch (javaType) {
+ case "boolean":
+ case "byte":
+ case "double":
+ case "float":
+ case "int":
+ case "short":
+ case "long":
+ return javaType;
+ case "java.lang.String":
+ return "string";
+ }
+ if (enumByName.containsKey(javaType)) {
+ requiredEnums.add(enumByName.get(javaType));
+ return LOG4J_PREFIX + ":" + javaType;
+ }
+ if (!simple) {
+ final Set<PluginEntry> group = pluginsByGroup.get(javaType);
+ final PluginEntry entry = pluginsByName.get(javaType);
+ if (group == null && entry != null &&
entry.getKeys().isEmpty()) {
+ return LOG4J_PREFIX + ":" + javaType;
+ }
+ requiredGroups.add(javaType);
+ // Add also the base class to the group
+ if (entry != null) {
+ group.add(entry);
+ }
+ return LOG4J_PREFIX + ":" + javaType + ".group";
+ }
+ throw new IllegalArgumentException("Unknown simple Java type '" +
javaType + "'.");
+ }
+ }
+}
diff --git a/log4j-docgen/src/main/mdo/plugins.xml
b/log4j-docgen/src/main/mdo/plugins.xml
new file mode 100644
index 0000000..e626c5b
--- /dev/null
+++ b/log4j-docgen/src/main/mdo/plugins.xml
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to you 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.
+ -->
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://codehaus-plexus.github.io/MODELLO/2.0.0"
+ xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/2.0.0
https://codehaus-plexus.github.io/modello/xsd/modello-2.0.0.xsd"
+ xml.namespace="https://logging.apache.org/log4j/plugins">
+ <id>plugins</id>
+ <name>PluginBundle</name>
+ <description>Documents a bundle of Log4j plugins.</description>
+ <versionDefinition>
+ <type>field</type>
+ <value>schemaVersion</value>
+ </versionDefinition>
+ <defaults>
+ <default>
+ <key>package</key>
+ <value>org.apache.logging.log4j.docgen.model</value>
+ </default>
+ </defaults>
+
+ <classes>
+ <class rootElement="true">
+ <name>PluginBundle</name>
+ <description>Documents a bundle of Log4j plugins.</description>
+ <fields>
+ <field xml.attribute="true" xml.tagName="version">
+ <name>schemaVersion</name>
+ <type>String</type>
+ <required>true</required>
+ <description>The version of the schema used by the XML
document.</description>
+ </field>
+ <field>
+ <name>groupId</name>
+ <type>String</type>
+ <description>The group id of the bundle.</description>
+ </field>
+ <field>
+ <name>artifactId</name>
+ <type>String</type>
+ <description>The artifact id of the bundle.</description>
+ </field>
+ <field>
+ <name>version</name>
+ <type>String</type>
+ <description>The version of the bundle.</description>
+ </field>
+ <field>
+ <name>description</name>
+ <association>
+ <type>Description</type>
+ </association>
+ <description>Description of the bundle.</description>
+ </field>
+ <field>
+ <name>enums</name>
+ <association>
+ <type>EnumType</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>A list of all enums used in
properties.</description>
+ </field>
+ <field>
+ <name>plugins</name>
+ <association>
+ <type>PluginEntry</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>A list of all plugins in the
bundle.</description>
+ </field>
+ </fields>
+ </class>
+
+ <class xml.tagName="plugin">
+ <name>PluginEntry</name>
+ <description>Describes the properties available to
plugins.</description>
+ <fields>
+ <field xml.attribute="true">
+ <name>name</name>
+ <type>String</type>
+ <required>true</required>
+ <description>The unique name of this plugin.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>namespace</name>
+ <type>String</type>
+ <required>true</required>
+ <description>The namespace of the plugin.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>className</name>
+ <type>String</type>
+ <required>true</required>
+ <description>Fully qualified name of the class
implementing the plugin.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>deferChildren</name>
+ <type>boolean</type>
+ <defaultValue>false</defaultValue>
+ </field>
+ <field>
+ <name>description</name>
+ <association>
+ <type>Description</type>
+ </association>
+ <description>Description of the plugin.</description>
+ </field>
+ <field>
+ <name>keys</name>
+ <required>true</required>
+ <association>
+ <type>String</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>
+ The different keys (e.g. XML tag names) under which
the plugin can be used.
+ </description>
+ </field>
+ <!-- These are necessary to find all possible nested
components -->
+ <field>
+ <name>supertypes</name>
+ <association>
+ <type>String</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>
+ List of all the supertypes of a plugin.
+ </description>
+ </field>
+ <field>
+ <name>attributes</name>
+ <required>true</required>
+ <association>
+ <type>PluginAttribute</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>List of **all** the configuration attributes
supported</description>
+ </field>
+ <field>
+ <name>elements</name>
+ <required>true</required>
+ <association>
+ <type>PluginElement</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>List of **all** possible nested
components.</description>
+ </field>
+ </fields>
+ </class>
+
+ <class xml.tagName="attribute">
+ <name>PluginAttribute</name>
+ <description>A scalar configuration value for the
plugin.</description>
+ <fields>
+ <field xml.attribute="true">
+ <name>name</name>
+ <type>String</type>
+ <required>true</required>
+ <description>The name of the property.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>type</name>
+ <type>String</type>
+ <defaultValue>java.lang.String</defaultValue>
+ <description>The Java name of this attribute's type, e.g.
`boolean`, `java.lang.String`,
+ fully qualified name of an enum. The type must be an
enum or must have a type converter.
+ </description>
+ </field>
+ <field xml.attribute="true">
+ <name>required</name>
+ <type>boolean</type>
+ <defaultValue>false</defaultValue>
+ <description>If set to `true` the attribute is
required.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>defaultValue</name>
+ <type>String</type>
+ <description>The default value of this attribute as
string.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>defaultProperty</name>
+ <type>String</type>
+ <description>The Log4j property that contains the default
value of this attribute.</description>
+ </field>
+ <field>
+ <name>description</name>
+ <association>
+ <type>Description</type>
+ </association>
+ <description>A description of the property.</description>
+ </field>
+ </fields>
+ </class>
+
+ <class xml.tagName="enum" xsd.compositor="sequence">
+ <name>EnumType</name>
+ <description>Describes a Java enum type.</description>
+ <fields>
+ <field xml.attribute="true">
+ <name>className</name>
+ <type>String</type>
+ <required>true</required>
+ <description>The Java class name of the enum.</description>
+ </field>
+ <field>
+ <name>description</name>
+ <association>
+ <type>Description</type>
+ </association>
+ <description>An HTML description of the
property.</description>
+ </field>
+ <field>
+ <name>values</name>
+ <required>true</required>
+ <association xml.itemsStyle="flat">
+ <type>EnumValue</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <description>The possible values of this
enum.</description>
+ </field>
+ </fields>
+ </class>
+
+ <class xml.tagName="description">
+ <name>Description</name>
+ <description>General documentation tag.</description>
+ <fields>
+ <field xml.attribute="true">
+ <name>format</name>
+ <type>String</type>
+ <defaultValue>asciidoc</defaultValue>
+ <description>Format used by the documentation text.
Currently it **must** be "asciidoc".
+ </description>
+ </field>
+ <field xml.content="true">
+ <name>text</name>
+ <type>String</type>
+ <required>true</required>
+ <description>Description of the element.</description>
+ </field>
+ </fields>
+ </class>
+
+ <class xml.tagName="value">
+ <name>EnumValue</name>
+ <superClass>Description</superClass>
+ <description>One of the possible values of an enum.</description>
+ <fields>
+ <field xml.attribute="true">
+ <name>name</name>
+ <type>String</type>
+ <required>true</required>
+ <description>The name of the property.</description>
+ </field>
+ </fields>
+ </class>
+
+ <class xml.tagName="element">
+ <name>PluginElement</name>
+ <description>Describes a nested configuration
component.</description>
+ <fields>
+ <field xml.attribute="true">
+ <name>multiplicity</name>
+ <type>String</type>
+ <defaultValue>1</defaultValue>
+ <description>Either '*' if the field accepts a collection
of elements or '1'.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>required</name>
+ <type>boolean</type>
+ <defaultValue>false</defaultValue>
+ <description>If set to `true` the field must be not null
or a not empty collection.</description>
+ </field>
+ <field xml.attribute="true">
+ <name>type</name>
+ <type>String</type>
+ <required>true</required>
+ <description>
+ The fully qualified name of the Java type (class or
interface) of this component.
+ If the type is an array or collection, this returns
the type of the element.
+ </description>
+ </field>
+ <field>
+ <name>description</name>
+ <association>
+ <type>Description</type>
+ </association>
+ <description>An HTML description of this
element.</description>
+ </field>
+ </fields>
+ </class>
+ </classes>
+</model>
diff --git
a/log4j-docgen/src/main/resources/org/apache/logging/log4j/docgen/internal/configuration.xml
b/log4j-docgen/src/main/resources/org/apache/logging/log4j/docgen/internal/configuration.xml
new file mode 100644
index 0000000..442b274
--- /dev/null
+++
b/log4j-docgen/src/main/resources/org/apache/logging/log4j/docgen/internal/configuration.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to you 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.
+ -->
+<pluginBundle xmlns="https://logging.apache.org/log4j/plugins"
+ version="0.1.0">
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>2.22.0</version>
+ <description>Reference implementation of the Log4j API.</description>
+
+ <!--
+ ~ Level is not an enum, but for the purpose of the XSD we can limit its
values to the standard ones.
+ -->
+ <enums>
+ <enum className="org.apache.logging.log4j.Level">
+ <description>
+ Represents a logging level.
+ **Note**: the Log4j API supports custom levels, the following
list contains only the standard ones.
+ </description>
+ <value name="OFF">
+ Special level that disables logging. No events should be
logged at this level.
+ </value>
+ <value name="FATAL">
+ A fatal event that will prevent the application from
continuing.
+ </value>
+ <value name="ERROR">
+ An error in the application, possibly recoverable.
+ </value>
+ <value name="WARN">
+ An event that might possible lead to an error.
+ </value>
+ <value name="INFO">
+ An event for informational purposes.
+ </value>
+ <value name="DEBUG">
+ A general debugging event.
+ </value>
+ <value name="TRACE">
+ A fine-grained debug message, typically capturing the flow
through the application.
+ </value>
+ <value name="ALL">
+ All events should be logged.
+ </value>
+ </enum>
+ </enums>
+
+ <!--
+ ~ The main `Configuration` element is not a plugin, so we add a fake
entry for it.
+ -->
+ <plugins>
+ <plugin name="Configuration" namespace="Core"
className="org.apache.logging.log4j.core.config.Configuration">
+ <description>
+ A Log4j 2.x configuration contains many components, two of
them `Appenders` and `Loggers` are required.
+ </description>
+ <attributes>
+ <attribute name="advertiser">
+ <description>
+ If set it should contain the name of an `Advertiser`
plugin (cf.
+
https://logging.apache.org/log4j/2.x/manual/configuration.html#chainsaw-can-automatically-process-your-log-files-advertising-ap[documentation]
+ ).
+ Log4j Core provides a single implementation based on
JmDNS called `MulticastDns`.
+ </description>
+ </attribute>
+ <attribute name="dest" defaultValue="err">
+ <description>
+ Specifies the destination for StatusLogger events.
+ The possible values are:
+ * `out` for using standard out (default),
+ * `err` for using standard error,
+ * a string that is interpreted in order as URI, URL or
the path to a local file.
+
+ If the provided value is invalid, then the default
destination of standard out will be used.
+ </description>
+ </attribute>
+ <attribute name="name" required="true">
+ <description>Name of the configuration.</description>
+ </attribute>
+ <attribute name="monitorInterval" type="int" defaultValue="0">
+ <description>Number of seconds between polls for
configuration changes.</description>
+ </attribute>
+ <attribute name="schema">
+ <description>
+ The name of a classpath resource to use to validate
the configuration.
+ </description>
+ </attribute>
+ <attribute name="shutdownHook">
+ <description>
+ Specifies whether Log4j should automatically shut down
when the JVM shuts down.
+ Possible values:
+ * `enable`: to enable unconditionally the hook,
+ * `disable`: to disable unconditionally the hook.
+
+ The shutdown hook is enabled by default, unless Log4j
Core detects the presence of the Servlet
+ API.
+ </description>
+ </attribute>
+ <attribute name="shutdownTimeout" type="int">
+ <description>
+ Timeout in milliseconds of the logger context shut
down.
+ </description>
+ </attribute>
+ <attribute name="status" type="org.apache.logging.log4j.Level"
defaultValue="ERROR">
+ <description>Sets the level of the status
logger.</description>
+ </attribute>
+ <attribute name="strict" type="boolean" defaultValue="false">
+ <description>
+ If set to `true` the configuration file will be
validated using an XML schema.
+ </description>
+ </attribute>
+ <attribute name="verbose">
+ <description>
+ Specifies the verbosity level for the status logger.
+ This only applies to classes configured by
`StatusConfiguration#setVerboseClasses`.
+ </description>
+ </attribute>
+ </attributes>
+ <elements>
+ <element
type="org.apache.logging.log4j.core.config.PropertiesPlugin">
+ <description>
+ Wrapper element for a list of properties.
+
+ If present, this element must be the **first** child
of the configuration.
+ </description>
+ </element>
+ <element
type="org.apache.logging.log4j.core.config.AppendersPlugin" required="true">
+ <description>Wrapper element for a list of
appenders.</description>
+ </element>
+ <element
type="org.apache.logging.log4j.core.config.CustomLevels">
+ <description>Wrapper element for a list of custom
levels.</description>
+ </element>
+ <element
type="org.apache.logging.log4j.core.config.LoggersPlugin">
+ <description>Wrapper element for a list of logger
configurations.</description>
+ </element>
+ </elements>
+ </plugin>
+ </plugins>
+</pluginBundle>
diff --git
a/log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.Appender.adoc
b/log4j-docgen/src/site/Core/org.apache.logging.log4j.core.Appender.adoc
similarity index 100%
rename from
log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.Appender.adoc
rename to log4j-docgen/src/site/Core/org.apache.logging.log4j.core.Appender.adoc
diff --git
a/log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.appender.ConsoleAppender.adoc
b/log4j-docgen/src/site/Core/org.apache.logging.log4j.core.appender.ConsoleAppender.adoc
similarity index 100%
rename from
log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.appender.ConsoleAppender.adoc
rename to
log4j-docgen/src/site/Core/org.apache.logging.log4j.core.appender.ConsoleAppender.adoc
diff --git
a/log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.config.AppendersPlugin.adoc
b/log4j-docgen/src/site/Core/org.apache.logging.log4j.core.config.AppendersPlugin.adoc
similarity index 100%
rename from
log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.config.AppendersPlugin.adoc
rename to
log4j-docgen/src/site/Core/org.apache.logging.log4j.core.config.AppendersPlugin.adoc
diff --git
a/log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.config.Configuration.adoc
b/log4j-docgen/src/site/Core/org.apache.logging.log4j.core.config.Configuration.adoc
similarity index 100%
rename from
log4j-doc-reference/src/site/Core/org.apache.logging.log4j.core.config.Configuration.adoc
rename to
log4j-docgen/src/site/Core/org.apache.logging.log4j.core.config.Configuration.adoc
diff --git a/log4j-doc-reference/src/site/Properties/index.adoc
b/log4j-docgen/src/site/Properties/index.adoc
similarity index 100%
rename from log4j-doc-reference/src/site/Properties/index.adoc
rename to log4j-docgen/src/site/Properties/index.adoc
diff --git a/log4j-doc-reference/src/site/TypeConverters/index.adoc
b/log4j-docgen/src/site/TypeConverters/index.adoc
similarity index 100%
rename from log4j-doc-reference/src/site/TypeConverters/index.adoc
rename to log4j-docgen/src/site/TypeConverters/index.adoc
diff --git
a/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/SchemaGeneratorTest.java
b/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/SchemaGeneratorTest.java
new file mode 100644
index 0000000..967150a
--- /dev/null
+++
b/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/SchemaGeneratorTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.apache.logging.log4j.docgen;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.logging.log4j.docgen.internal.DefaultSchemaGenerator;
+import org.apache.logging.log4j.docgen.model.PluginBundle;
+import org.apache.logging.log4j.docgen.model.io.stax.PluginBundleStaxReader;
+import org.junit.jupiter.api.Test;
+
+public class SchemaGeneratorTest {
+
+ @Test
+ void schemaGeneration() throws XMLStreamException, IOException {
+ final PluginBundleStaxReader reader = new PluginBundleStaxReader();
+ final PluginBundle bundle =
reader.read(SchemaGeneratorTest.class.getResourceAsStream("/test-plugins.xml"));
+ final SchemaGenerator generator = new DefaultSchemaGenerator();
+ final XMLOutputFactory factory = XMLOutputFactory.newInstance();
+ final Path actualSchema =
Paths.get("target/test-classes/actual-log4j.xsd");
+ final XMLStreamWriter writer =
factory.createXMLStreamWriter(Files.newOutputStream(actualSchema));
+ generator.generateSchema(Collections.singleton(bundle), writer);
+ writer.close();
+ }
+}
diff --git a/log4j-docgen/src/test/resources/expected-log4j.xsd
b/log4j-docgen/src/test/resources/expected-log4j.xsd
new file mode 100644
index 0000000..67e1dcb
--- /dev/null
+++ b/log4j-docgen/src/test/resources/expected-log4j.xsd
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:log4j="http://logging.apache.org/log4j/2.0/config"
elementFormDefault="qualified">
+ <simpleType name="org.apache.logging.log4j.Level">
+ <restriction base="string">
+ <enumeration value="OFF">
+ <annotation>
+ <documentation>Special level that disables logging. No
events should be logged at this level.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="FATAL">
+ <annotation>
+ <documentation>A fatal event that will prevent the
application from continuing.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="ERROR">
+ <annotation>
+ <documentation>An error in the application, possibly
recoverable.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="WARN">
+ <annotation>
+ <documentation>An event that might possible lead to an
error.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="INFO">
+ <annotation>
+ <documentation>An event for informational
purposes.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="DEBUG">
+ <annotation>
+ <documentation>A general debugging event.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="TRACE">
+ <annotation>
+ <documentation>A fine-grained debug message, typically
capturing the flow through the application.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="ALL">
+ <annotation>
+ <documentation>All events should be logged.</documentation>
+ </annotation>
+ </enumeration>
+ </restriction>
+ </simpleType>
+
+ <element type="log4j:org.apache.logging.log4j.core.config.Configuration"
name="Configuration"></element>
+ <complexType name="org.apache.logging.log4j.core.appender.ConsoleAppender">
+ <complexContent>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>The name of the appender used in appender
references.
+ Must be unique.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="ignoreExceptions" type="boolean">
+ <annotation>
+ <documentation>If set to `false` logging exceptions will
be forwarded to the caller.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="bufferedIo" type="boolean">
+ <annotation>
+ <documentation>If set to `true` (default) the appender
will buffer messages before sending them.
+ This attribute is ignored if `immediateFlush` is set
to `true`.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="bufferSize" type="int">
+ <annotation>
+ <documentation>Size in bytes of the appender's
buffer.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="immediateFlush" type="boolean">
+ <annotation>
+ <documentation>If set to `true`, the appender flushes the
output stream at each message and
+ buffering is disabled regardless of the value of
`bufferedIo`.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="target"
type="log4j:org.apache.logging.log4j.core.appender.ConsoleAppender.Target">
+ <annotation>
+ <documentation>Specifies the target of the
appender.</documentation>
+ </annotation>
+ </attribute>
+ <group ref="log4j:org.apache.logging.log4j.core.Layout">
+ <annotation>
+ <documentation>The layout to be used with the
appender.</documentation>
+ </annotation>
+ </group>
+ </complexContent>
+ </complexType>
+ <complexType name="org.apache.logging.log4j.core.config.Property">
+ <simpleContent>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>Name of the property.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="value" type="string">
+ <annotation>
+ <documentation>Value of the property.</documentation>
+ </annotation>
+ </attribute>
+ </simpleContent>
+ </complexType>
+ <complexType name="org.apache.logging.log4j.core.config.AppendersPlugin">
+ <complexContent>
+ <group ref="log4j:org.apache.logging.log4j.core.Appender"
minOccurs="0" maxOccurs="unbounded">
+ <annotation>
+ <documentation>A list of appender.</documentation>
+ </annotation>
+ </group>
+ </complexContent>
+ </complexType>
+ <complexType name="org.apache.logging.log4j.core.config.LoggersPlugin">
+ <complexContent>
+ <group
ref="log4j:org.apache.logging.log4j.core.config.LoggerConfig" minOccurs="0"
maxOccurs="unbounded">
+ <annotation>
+ <documentation>A list of logger
configurations.</documentation>
+ </annotation>
+ </group>
+ </complexContent>
+ </complexType>
+ <complexType name="org.apache.logging.log4j.core.config.PropertiesPlugin">
+ <complexContent></complexContent>
+ </complexType>
+ <complexType name="org.apache.logging.log4j.core.config.Configuration">
+ <complexContent>
+ <attribute name="advertiser" type="string">
+ <annotation>
+ <documentation>If set it should contain the name of an
`Advertiser` plugin (cf.
+
https://logging.apache.org/log4j/2.x/manual/configuration.html#chainsaw-can-automatically-process-your-log-files-advertising-ap[documentation]
+ ).
+ Log4j Core provides a single implementation based on
JmDNS called `MulticastDns`.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="dest" type="string">
+ <annotation>
+ <documentation>Specifies the destination for StatusLogger
events.
+ The possible values are:
+ * `out` for using standard out (default),
+ * `err` for using standard error,
+ * a string that is interpreted in order as URI, URL or
the path to a local file.
+
+ If the provided value is invalid, then the default
destination of standard out will be used.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>Name of the configuration.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="monitorInterval" type="int">
+ <annotation>
+ <documentation>Number of seconds between polls for
configuration changes.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="schema" type="string">
+ <annotation>
+ <documentation>The name of a classpath resource to use to
validate the configuration.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="shutdownHook" type="string">
+ <annotation>
+ <documentation>Specifies whether Log4j should
automatically shut down when the JVM shuts down.
+ Possible values:
+ * `enable`: to enable unconditionally the hook,
+ * `disable`: to disable unconditionally the hook.
+
+ The shutdown hook is enabled by default, unless Log4j
Core detects the presence of the Servlet
+ API.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="shutdownTimeout" type="int">
+ <annotation>
+ <documentation>Timeout in milliseconds of the logger
context shut down.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="status"
type="log4j:org.apache.logging.log4j.Level">
+ <annotation>
+ <documentation>Sets the level of the status
logger.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="strict" type="boolean">
+ <annotation>
+ <documentation>If set to `true` the configuration file
will be validated using an XML schema.</documentation>
+ </annotation>
+ </attribute>
+ <attribute name="verbose" type="string">
+ <annotation>
+ <documentation>Specifies the verbosity level for the
status logger.
+ This only applies to classes configured by
`StatusConfiguration#setVerboseClasses`.</documentation>
+ </annotation>
+ </attribute>
+ <group
ref="log4j:org.apache.logging.log4j.core.config.CustomLevels" minOccurs="0">
+ <annotation>
+ <documentation>Wrapper element for a list of custom
levels.</documentation>
+ </annotation>
+ </group>
+ </complexContent>
+ </complexType>
+ <simpleType
name="org.apache.logging.log4j.core.appender.ConsoleAppender.Target">
+ <restriction base="string">
+ <enumeration value="SYSTEM_OUT">
+ <annotation>
+ <documentation>Logs to the standard output.</documentation>
+ </annotation>
+ </enumeration>
+ <enumeration value="SYSTEM_ERR">
+ <annotation>
+ <documentation>Logs to the standard error.</documentation>
+ </annotation>
+ </enumeration>
+ </restriction>
+ </simpleType>
+ <group name="org.apache.logging.log4j.core.config.LoggerConfig">
+ <choice></choice>
+ </group>
+ <group name="org.apache.logging.log4j.core.Appender">
+ <choice>
+ <element name="Console"
type="log4j:org.apache.logging.log4j.core.appender.ConsoleAppender"></element>
+ </choice>
+ </group>
+ <group name="org.apache.logging.log4j.core.config.CustomLevels">
+ <choice></choice>
+ </group>
+ <group name="org.apache.logging.log4j.core.Layout">
+ <choice></choice>
+ </group>
+</schema>
\ No newline at end of file
diff --git a/log4j-doc-reference/src/test/resources/log4j-plugins.xml
b/log4j-docgen/src/test/resources/log4j-plugins.xml
similarity index 100%
rename from log4j-doc-reference/src/test/resources/log4j-plugins.xml
rename to log4j-docgen/src/test/resources/log4j-plugins.xml
diff --git a/log4j-doc-reference/src/test/resources/log4j.xsd
b/log4j-docgen/src/test/resources/log4j.xsd
similarity index 100%
rename from log4j-doc-reference/src/test/resources/log4j.xsd
rename to log4j-docgen/src/test/resources/log4j.xsd
diff --git a/log4j-docgen/src/test/resources/test-plugins.xml
b/log4j-docgen/src/test/resources/test-plugins.xml
new file mode 100644
index 0000000..e35f522
--- /dev/null
+++ b/log4j-docgen/src/test/resources/test-plugins.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to you 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.
+ -->
+<pluginBundle xmlns="https://logging.apache.org/log4j/plugins"
+ version="0.1.0">
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>2.22.0</version>
+ <description>Reference implementation of the Log4j API.</description>
+
+ <enums>
+ <enum
className="org.apache.logging.log4j.core.appender.ConsoleAppender.Target">
+ <description>Specifies the target of a console
appender.</description>
+ <value name="SYSTEM_OUT">
+ Logs to the standard output.
+ </value>
+ <value name="SYSTEM_ERR">
+ Logs to the standard error.
+ </value>
+ </enum>
+ <enum className="org.apache.logging.log4j.core.Filter.Result">
+ <description>The result that can returned from a filter method
call.</description>
+ <value name="ACCEPT">
+ The event will be processed without further filtering based on
the log Level.
+ </value>
+ <value name="NEUTRAL">
+ No decision could be made, further filtering should occur.
+ </value>
+ <value name="DENY">
+ The event should not be processed.
+ </value>
+ </enum>
+ </enums>
+
+ <plugins>
+ <!-- Direct children of Configuration -->
+ <plugin name="Appenders" namespace="Core"
className="org.apache.logging.log4j.core.config.AppendersPlugin">
+ <description>A wrapper for a list of appenders.</description>
+ <elements>
+ <element type="org.apache.logging.log4j.core.Appender"
multiplicity="*">
+ <description>A list of appender.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <plugin name="CustomLevels" namespace="Core"
className="org.apache.logging.log4j.core.config.CustomLevels">
+ <description>A wrapper for a list of custom level
configurations.</description>
+ <elements>
+ <element
type="org.apache.logging.log4j.core.config.CustomLevelConfig" multiplicity="*">
+ <description>A list of custom level
configurations.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <plugin name="Loggers" namespace="Core"
className="org.apache.logging.log4j.core.config.LoggersPlugin">
+ <description>A wrapper for a list of logger
configurations.</description>
+ <elements>
+ <element
type="org.apache.logging.log4j.core.config.LoggerConfig" multiplicity="*">
+ <description>A list of logger configurations.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <plugin name="Properties" namespace="Core"
className="org.apache.logging.log4j.core.config.PropertiesPlugin">
+ <description>A wrapper for a list of properties.</description>
+ <elements>
+ <element type="org.apache.logging.log4j.core.config.Property"
multiplicity="*">
+ <description>A list of properties.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <!-- Second nesting level elements -->
+ <plugin name="Console" namespace="Core"
className="org.apache.logging.log4j.core.appender.ConsoleAppender">
+ <supertypes>
+ <supertype>org.apache.logging.log4j.core.Appender</supertype>
+ </supertypes>
+ <description>
+ Write log events to the console.
+ </description>
+ <attributes>
+ <attribute name="name" required="true">
+ <description>
+ The name of the appender used in appender references.
+ Must be unique.
+ </description>
+ </attribute>
+ <attribute name="ignoreExceptions" type="boolean"
defaultValue="true">
+ <description>
+ If set to `false` logging exceptions will be forwarded
to the caller.
+ </description>
+ </attribute>
+ <attribute name="bufferedIo" type="boolean"
defaultValue="true">
+ <description>
+ If set to `true` (default) the appender will buffer
messages before sending them.
+ This attribute is ignored if `immediateFlush` is set
to `true`.
+ </description>
+ </attribute>
+ <attribute name="bufferSize" type="int"
defaultProperty="log4j2.encoderByteBufferSize">
+ <description>Size in bytes of the appender's
buffer.</description>
+ </attribute>
+ <attribute name="immediateFlush" type="boolean"
defaultValue="true">
+ <description>
+ If set to `true`, the appender flushes the output
stream at each message and
+ buffering is disabled regardless of the value of
`bufferedIo`.
+ </description>
+ </attribute>
+ <attribute name="target"
type="org.apache.logging.log4j.core.appender.ConsoleAppender.Target"
+ defaultValue="SYSTEM_OUT">
+ <description>
+ Specifies the target of the appender.
+ </description>
+ </attribute>
+ </attributes>
+ <elements>
+ <element type="org.apache.logging.log4j.core.Filter">
+ <description>A filter to apply to events before sending
them to destination.</description>
+ </element>
+ <element type="org.apache.logging.log4j.core.Layout"
required="true">
+ <description>The layout to be used with the
appender.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <plugin name="CustomLevel" namespace="Core"
className="org.apache.logging.log4j.core.config.CustomLevelConfig">
+ <description>Configures a custom level.</description>
+ <attributes>
+ <attribute name="name" required="true">
+ <description>The name of the level.</description>
+ </attribute>
+ <attribute name="intLevel" type="int" required="true">
+ <description>
+ An integer determines the strength of the custom level
relative to the built-in levels.
+ </description>
+ </attribute>
+ </attributes>
+ </plugin>
+
+ <plugin name="Logger" namespace="Core"
className="org.apache.logging.log4j.core.config.LoggerConfig">
+ <description>Configures a particular logger</description>
+ <attributes>
+ <attribute name="name" required="true">
+ <description>The name of the logger.</description>
+ </attribute>
+ <attribute name="level" type="org.apache.logging.log4j.Level">
+ <description>The level of the logger.</description>
+ </attribute>
+ </attributes>
+ <elements>
+ <element
type="org.apache.logging.log4j.core.config.AppenderRef" multiplicity="*">
+ <description>A list of appenders to use with this
logger.</description>
+ </element>
+ <element type="org.apache.logging.log4j.core.Filter">
+ <description>A filter to filter events, before calling the
appenders.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <plugin name="Root" namespace="Core"
className="org.apache.logging.log4j.core.config.LoggerConfig.RootLogger">
+ <description>Configures the root logger</description>
+ <supertypes>
+
<supertype>org.apache.logging.log4j.core.config.LoggerConfig</supertype>
+ </supertypes>
+ <attributes>
+ <attribute name="level" type="org.apache.logging.log4j.Level">
+ <description>The level of the logger.</description>
+ </attribute>
+ </attributes>
+ <elements>
+ <element
type="org.apache.logging.log4j.core.config.AppenderRef" multiplicity="*">
+ <description>A list of appenders to use with this
logger.</description>
+ </element>
+ <element type="org.apache.logging.log4j.core.Filter">
+ <description>A filter to filter events, before calling the
appenders.</description>
+ </element>
+ </elements>
+ </plugin>
+
+ <plugin name="Property" namespace="Core"
className="org.apache.logging.log4j.core.config.Property">
+ <description>Represents a key/value pair in the
configuration.</description>
+ <attributes>
+ <attribute name="name" required="true">
+ <description>Name of the property.</description>
+ </attribute>
+ <attribute name="value">
+ <description>Value of the property.</description>
+ </attribute>
+ </attributes>
+ </plugin>
+
+ <!-- Additional plugins -->
+ <plugin name="AppenderRef" namespace="Core"
className="org.apache.logging.log4j.core.config.AppenderRef">
+ <description>Reference to an appender defined in the `Appenders`
section.</description>
+ </plugin>
+
+ <plugin name="BurstFilter" namespace="Core"
className="org.apache.logging.log4j.core.filter.BurstFilter">
+ <description>
+ The BurstFilter is a logging filter that regulates logging
traffic.
+ Use this filter when you want to control the mean rate and
maximum burst of log statements that can be
+ sent to an appender.
+ </description>
+ <supertypes>
+ <supertype>org.apache.logging.log4j.core.Filter</supertype>
+ </supertypes>
+ <attributes>
+ <attribute name="onMatch"
type="org.apache.logging.log4j.core.Filter.Result" defaultValue="NEUTRAL">
+ <description>
+ Action to perform if the filter matches.
+ </description>
+ </attribute>
+ <attribute name="onMismatch"
type="org.apache.logging.log4j.core.Filter.Result" defaultValue="DENY">
+ <description>
+ Action to perform if the filter does not match.
+ </description>
+ </attribute>
+ <attribute name="level" type="org.apache.logging.log4j.Level"
defaultValue="WARN">
+ <description>
+ Log events less specific than this level are filtered,
while events with level equal or more
+ specific always match.
+ </description>
+ </attribute>
+ <attribute name="rate" type="float" defaultValue="10">
+ <description>
+ Sets the average number of events per second to allow.
+ </description>
+ </attribute>
+ <attribute name="maxBurst" type="long">
+ <description>
+ Sets the maximum number of events that can occur
before events are filtered for exceeding the
+ average rate.
+ </description>
+ </attribute>
+ </attributes>
+ </plugin>
+ </plugins>
+</pluginBundle>
diff --git a/log4j-tools-parent/.mvn b/log4j-tools-parent/.mvn
new file mode 120000
index 0000000..19172e1
--- /dev/null
+++ b/log4j-tools-parent/.mvn
@@ -0,0 +1 @@
+../.mvn
\ No newline at end of file
diff --git a/log4j-tools-parent/pom.xml b/log4j-tools-parent/pom.xml
index 86ad55a..5479a8a 100644
--- a/log4j-tools-parent/pom.xml
+++ b/log4j-tools-parent/pom.xml
@@ -31,19 +31,31 @@
<properties>
- <!-- dependency versions -->
+ <!-- Dependency versions -->
<assertj.version>3.24.2</assertj.version>
<commons-io.version>2.13.0</commons-io.version>
<freemarker.version>2.3.32</freemarker.version>
<junit.version>5.10.1</junit.version>
+ <modello.version>2.1.2</modello.version>
+
+ <!-- Maven plugin versions -->
<maven-plugin.version>3.8.2</maven-plugin.version>
<maven-plugin-api.version>3.6.3</maven-plugin-api.version>
+
<modello-maven-plugin.version>${modello.version}</modello-maven-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
+ <dependency>
+ <groupId>org.junit</groupId>
+ <artifactId>junit-bom</artifactId>
+ <version>${junit.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
@@ -62,18 +74,6 @@
<version>${freemarker.version}</version>
</dependency>
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-engine</artifactId>
- <version>${junit.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-params</artifactId>
- <version>${junit.version}</version>
- </dependency>
-
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
@@ -91,4 +91,18 @@
</dependencies>
</dependencyManagement>
+ <build>
+ <pluginManagement>
+ <plugins>
+
+ <plugin>
+ <groupId>org.codehaus.modello</groupId>
+ <artifactId>modello-maven-plugin</artifactId>
+ <version>${modello-maven-plugin.version}</version>
+ </plugin>
+
+ </plugins>
+ </pluginManagement>
+ </build>
+
</project>
diff --git a/pom.xml b/pom.xml
index c0b30bb..57a9bed 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,7 +86,7 @@
<!-- Modules here must have a corresponding entry in `dependencyManagement
> dependencies` block below! -->
<module>log4j-changelog</module>
<module>log4j-changelog-maven-plugin</module>
- <module>log4j-doc-reference</module>
+ <module>log4j-docgen</module>
</modules>