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>
 

Reply via email to