You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2020/08/10 02:19:54 UTC

[tomee-site-generator] branch master updated (166066d -> 5094a05)

This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git.


    from 166066d  Add downloads for TomEE 8.0.4 and 9.0.0-M2
     new ddab643  Reformat code
     new b5405cf  Checks for the Asciidoc content
     new b9f71d6  Merge branch 'master' of github.com:apache/tomee-site-generator
     new 28c0ed8  Ability to insert links into javadoc
     new 858d666  Functional bi-directional links from javadocs to examples
     new 03258bf  Sort examples by (hopefully) most relevant
     new 17d681d  Support multiple languages in @example javadoc tags
     new 4a5b45a  Use colored top bar Remove transitions Bold section titles
     new 44a6c56  Re-add previous versions
     new 444f755  Update "APIs Used" heading level
     new 5094a05  Enable linking for all Javadoc/APIs (Jakarta, MicroProfile, TomEE)

The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../tomee/website/AddAsciidocCodeblocks.java       |  20 +-
 .../java/org/apache/tomee/website/ApisUsed.java    |  69 ++++++
 .../java/org/apache/tomee/website/Example.java     |  34 ++-
 .../org/apache/tomee/website/ExampleLinks.java     | 102 +++++++++
 .../org/apache/tomee/website/GroupedIndex.java     |  68 +++---
 .../java/org/apache/tomee/website/Javadocs.java    |   6 +
 .../org/apache/tomee/website/LearningLinks.java    | 117 +++++++++-
 .../java/org/apache/tomee/website/SeeLinks.java    |  29 ---
 .../java/org/apache/tomee/website/Sources.java     |   1 +
 .../JbakeHeaderHasNoSpace.java}                    |  37 ++--
 src/main/jbake/assets/css/cardio.css               | 103 +++++----
 .../org/apache/tomee/website/ApisUsedTest.java     | 127 +++++++++++
 .../org/apache/tomee/website/ExampleLinksTest.java | 126 +++++++++++
 .../apache/tomee/website/LearningLinksTest.java    | 224 ++++++++++++++++++++
 .../org/apache/tomee/website/SeeLinksTest.java     |  90 --------
 .../ApisUsedTest/abnormalHeading/after.adoc        | 230 ++++++++++++++++++++
 .../ApisUsedTest/abnormalHeading/before.adoc       | 229 ++++++++++++++++++++
 .../ApisUsedTest/hasOtherSections/after.adoc       | 235 +++++++++++++++++++++
 .../ApisUsedTest/hasOtherSections/before.adoc      | 234 ++++++++++++++++++++
 .../resources/ApisUsedTest/insertHref/after.adoc   | 230 ++++++++++++++++++++
 .../resources/ApisUsedTest/insertHref/before.adoc  | 226 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/after1.adoc       | 230 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/after2.adoc       | 231 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/after3.adoc       | 232 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/before.adoc       | 226 ++++++++++++++++++++
 .../resources/ApisUsedTest/noDuplicates/after.adoc | 230 ++++++++++++++++++++
 .../ApisUsedTest/noDuplicates/before.adoc          | 226 ++++++++++++++++++++
 .../finalClass}/after.java                         |   4 +-
 .../finalClass}/before.java                        |   2 +-
 .../hasAnnotations/after.java                      |   2 +-
 .../hasAnnotations/before.java                     |   0
 .../insertHref/after.java                          |   2 +-
 .../insertHref/before.java                         |   0
 .../multipleInserts/after1.java                    |   2 +-
 .../multipleInserts/after2.java}                   |   5 +-
 .../multipleInserts/after3.java                    |   6 +-
 .../multipleInserts/before.java                    |   0
 .../multipleLanguages/after1.java}                 |   3 +-
 .../multipleLanguages}/after2.java                 |   4 +-
 .../multipleLanguages}/after3.java                 |   6 +-
 .../multipleLanguages}/before.java                 |   0
 .../noDuplicates}/after.java                       |   2 +-
 .../noDuplicates}/before.java                      |   0
 .../noJavadoc/after.java                           |   2 +-
 .../noJavadoc/before.java                          |   0
 45 files changed, 3693 insertions(+), 259 deletions(-)
 create mode 100644 src/main/java/org/apache/tomee/website/ApisUsed.java
 create mode 100644 src/main/java/org/apache/tomee/website/ExampleLinks.java
 delete mode 100644 src/main/java/org/apache/tomee/website/SeeLinks.java
 copy src/main/java/org/apache/tomee/website/{AddGroups.java => audit/JbakeHeaderHasNoSpace.java} (56%)
 create mode 100644 src/test/java/org/apache/tomee/website/ApisUsedTest.java
 create mode 100644 src/test/java/org/apache/tomee/website/ExampleLinksTest.java
 create mode 100644 src/test/java/org/apache/tomee/website/LearningLinksTest.java
 delete mode 100644 src/test/java/org/apache/tomee/website/SeeLinksTest.java
 create mode 100644 src/test/resources/ApisUsedTest/abnormalHeading/after.adoc
 create mode 100644 src/test/resources/ApisUsedTest/abnormalHeading/before.adoc
 create mode 100644 src/test/resources/ApisUsedTest/hasOtherSections/after.adoc
 create mode 100644 src/test/resources/ApisUsedTest/hasOtherSections/before.adoc
 create mode 100644 src/test/resources/ApisUsedTest/insertHref/after.adoc
 create mode 100644 src/test/resources/ApisUsedTest/insertHref/before.adoc
 create mode 100644 src/test/resources/ApisUsedTest/multipleInserts/after1.adoc
 create mode 100644 src/test/resources/ApisUsedTest/multipleInserts/after2.adoc
 create mode 100644 src/test/resources/ApisUsedTest/multipleInserts/after3.adoc
 create mode 100644 src/test/resources/ApisUsedTest/multipleInserts/before.adoc
 create mode 100644 src/test/resources/ApisUsedTest/noDuplicates/after.adoc
 create mode 100644 src/test/resources/ApisUsedTest/noDuplicates/before.adoc
 copy src/test/resources/{SeeLinksTest/insertHref => ExampleLinksTest/finalClass}/after.java (93%)
 copy src/test/resources/{SeeLinksTest/insertHref => ExampleLinksTest/finalClass}/before.java (97%)
 rename src/test/resources/{SeeLinksTest => ExampleLinksTest}/hasAnnotations/after.java (95%)
 rename src/test/resources/{SeeLinksTest => ExampleLinksTest}/hasAnnotations/before.java (100%)
 copy src/test/resources/{SeeLinksTest => ExampleLinksTest}/insertHref/after.java (95%)
 copy src/test/resources/{SeeLinksTest => ExampleLinksTest}/insertHref/before.java (100%)
 rename src/test/resources/{SeeLinksTest => ExampleLinksTest}/multipleInserts/after1.java (92%)
 copy src/test/resources/{SeeLinksTest/multipleInserts/after3.java => ExampleLinksTest/multipleInserts/after2.java} (83%)
 copy src/test/resources/{SeeLinksTest => ExampleLinksTest}/multipleInserts/after3.java (81%)
 copy src/test/resources/{SeeLinksTest => ExampleLinksTest}/multipleInserts/before.java (100%)
 copy src/test/resources/{SeeLinksTest/multipleInserts/after2.java => ExampleLinksTest/multipleLanguages/after1.java} (87%)
 rename src/test/resources/{SeeLinksTest/multipleInserts => ExampleLinksTest/multipleLanguages}/after2.java (85%)
 rename src/test/resources/{SeeLinksTest/multipleInserts => ExampleLinksTest/multipleLanguages}/after3.java (79%)
 rename src/test/resources/{SeeLinksTest/multipleInserts => ExampleLinksTest/multipleLanguages}/before.java (100%)
 rename src/test/resources/{SeeLinksTest/insertHref => ExampleLinksTest/noDuplicates}/after.java (95%)
 rename src/test/resources/{SeeLinksTest/insertHref => ExampleLinksTest/noDuplicates}/before.java (100%)
 rename src/test/resources/{SeeLinksTest => ExampleLinksTest}/noJavadoc/after.java (93%)
 rename src/test/resources/{SeeLinksTest => ExampleLinksTest}/noJavadoc/before.java (100%)


[tomee-site-generator] 10/11: Update "APIs Used" heading level

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 444f75588334b7be2be5ea8a9425293829de9f90
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 18:58:02 2020 -0700

    Update "APIs Used" heading level
---
 src/main/java/org/apache/tomee/website/ApisUsed.java         | 8 ++++----
 src/test/java/org/apache/tomee/website/ApisUsedTest.java     | 2 +-
 src/test/resources/ApisUsedTest/abnormalHeading/after.adoc   | 2 +-
 src/test/resources/ApisUsedTest/hasOtherSections/after.adoc  | 2 +-
 src/test/resources/ApisUsedTest/hasOtherSections/before.adoc | 2 +-
 src/test/resources/ApisUsedTest/insertHref/after.adoc        | 2 +-
 src/test/resources/ApisUsedTest/multipleInserts/after1.adoc  | 2 +-
 src/test/resources/ApisUsedTest/multipleInserts/after2.adoc  | 2 +-
 src/test/resources/ApisUsedTest/multipleInserts/after3.adoc  | 2 +-
 src/test/resources/ApisUsedTest/noDuplicates/after.adoc      | 2 +-
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/ApisUsed.java b/src/main/java/org/apache/tomee/website/ApisUsed.java
index 08d24a9..aa61897 100644
--- a/src/main/java/org/apache/tomee/website/ApisUsed.java
+++ b/src/main/java/org/apache/tomee/website/ApisUsed.java
@@ -28,7 +28,7 @@ public class ApisUsed {
     public static String insertHref(String source, final String link, final String linkText) {
         source = normalize(source);
 
-        if (source.contains("\n= APIs Used\n")) {
+        if (source.contains("\n== APIs Used\n")) {
             return updateApiList(source, link, linkText);
         } else {
             return addApiList(source, link, linkText);
@@ -38,7 +38,7 @@ public class ApisUsed {
     private static String addApiList(final String source, final String link, final String linkText) {
         final PrintString out = new PrintString();
         out.println("");
-        out.println("= APIs Used");
+        out.println("== APIs Used");
         out.println("");
         out.printf("- link:%s[%s]%n", link, linkText);
 
@@ -46,7 +46,7 @@ public class ApisUsed {
     }
 
     private static String updateApiList(final String source, final String link, final String linkText) {
-        final int start = source.indexOf("\n= APIs Used\n");
+        final int start = source.indexOf("\n== APIs Used\n");
         final int end = ExampleLinks.min(source.indexOf("\n=", start + 1), source.length());
         final String content = source.substring(start, end);
 
@@ -64,6 +64,6 @@ public class ApisUsed {
         final Matcher matcher = HEADER.matcher(source);
         if (!matcher.find()) return source;
 
-        return matcher.replaceAll("\n= APIs Used\n");
+        return matcher.replaceAll("\n== APIs Used\n");
     }
 }
diff --git a/src/test/java/org/apache/tomee/website/ApisUsedTest.java b/src/test/java/org/apache/tomee/website/ApisUsedTest.java
index 6807e5b..484df03 100644
--- a/src/test/java/org/apache/tomee/website/ApisUsedTest.java
+++ b/src/test/java/org/apache/tomee/website/ApisUsedTest.java
@@ -121,7 +121,7 @@ public class ApisUsedTest {
 
     @Test
     public void normalize() throws Exception {
-        assertEquals("\n= APIs Used\n- link", ApisUsed.normalize("\n====  ApIs usEd\n- link"));
+        assertEquals("\n== APIs Used\n- link", ApisUsed.normalize("\n====  ApIs usEd\n- link"));
     }
 
 }
diff --git a/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc b/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc
index 9a6d5db..059541a 100644
--- a/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc
+++ b/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc
@@ -225,6 +225,6 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
diff --git a/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc b/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc
index f6e1e43..aa3e841 100644
--- a/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc
+++ b/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc
@@ -225,7 +225,7 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
diff --git a/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc b/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc
index 7966535..d5a06a4 100644
--- a/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc
+++ b/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc
@@ -225,7 +225,7 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
 
diff --git a/src/test/resources/ApisUsedTest/insertHref/after.adoc b/src/test/resources/ApisUsedTest/insertHref/after.adoc
index f83a09d..bcfdfa3 100644
--- a/src/test/resources/ApisUsedTest/insertHref/after.adoc
+++ b/src/test/resources/ApisUsedTest/insertHref/after.adoc
@@ -225,6 +225,6 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc b/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc
index f83a09d..bcfdfa3 100644
--- a/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc
+++ b/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc
@@ -225,6 +225,6 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc b/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc
index 95aaa88..849b13a 100644
--- a/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc
+++ b/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc
@@ -225,7 +225,7 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc b/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc
index 906b6ff..8bd4f04 100644
--- a/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc
+++ b/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc
@@ -225,7 +225,7 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
diff --git a/src/test/resources/ApisUsedTest/noDuplicates/after.adoc b/src/test/resources/ApisUsedTest/noDuplicates/after.adoc
index f83a09d..bcfdfa3 100644
--- a/src/test/resources/ApisUsedTest/noDuplicates/after.adoc
+++ b/src/test/resources/ApisUsedTest/noDuplicates/after.adoc
@@ -225,6 +225,6 @@ Results :
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
 ----
 
-= APIs Used
+== APIs Used
 
 - link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]


[tomee-site-generator] 06/11: Sort examples by (hopefully) most relevant

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 03258bf40cd8c05bc3cd16d272de2118fc29a441
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 13:26:48 2020 -0700

    Sort examples by (hopefully) most relevant
---
 .../org/apache/tomee/website/LearningLinks.java    |  39 ++++-
 .../apache/tomee/website/LearningLinksTest.java    | 184 +++++++++++++++++++++
 2 files changed, 222 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/tomee/website/LearningLinks.java b/src/main/java/org/apache/tomee/website/LearningLinks.java
index 9f170f4..aa0f488 100644
--- a/src/main/java/org/apache/tomee/website/LearningLinks.java
+++ b/src/main/java/org/apache/tomee/website/LearningLinks.java
@@ -24,6 +24,7 @@ import org.tomitribe.tio.lang.JvmLang;
 import java.io.File;
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -80,7 +81,9 @@ public class LearningLinks {
         if (!source.getName().contains("jakarta")) return;
         final Map<String, JavadocSource> sources = getJavadocSources(source.stream());
 
-        for (final Example example : examples.getExamples()) {
+        final List<Example> examples = sort(this.examples.getExamples());
+
+        for (final Example example : examples) {
             final List<String> apisUsed = getImports(example).stream()
                     .filter(sources::containsKey)
                     .collect(Collectors.toList());
@@ -101,6 +104,40 @@ public class LearningLinks {
         }
     }
 
+    protected static List<Example> sort(final List<Example> list) {
+        final List<Example> examples = new ArrayList<>(list);
+
+        // Sort by size of example description (favor better documented examples)
+        examples.sort(LearningLinks::compareBySize);
+
+        // Sort by TomEE version
+        examples.sort(LearningLinks::compareByVersion);
+
+        // Sort "latest" to the top
+        examples.sort(LearningLinks::compareByLatest);
+
+        return examples;
+    }
+
+    protected static int compareByLatest(final Example a, final Example b) {
+        return Integer.compare(rankLatest(b), rankLatest(a));
+    }
+
+    protected static int compareByVersion(final Example a, final Example b) {
+        return pathFromContentRoot(b.getDestReadme()).compareTo(pathFromContentRoot(a.getDestReadme()));
+    }
+
+    protected static int compareBySize(final Example a, final Example b) {
+        return Long.compare(b.getDestReadme().length(), a.getDestReadme().length());
+    }
+
+    private static int rankLatest(final Example example) {
+        final String path = pathFromContentRoot(example.getDestReadme());
+        if (path.startsWith("latest/")) return 1;
+        if (path.startsWith("master/")) return -1;
+        return 0;
+    }
+
     private void addApisUsed(final Example example, final List<String> apisUsed, final Map<String, JavadocSource> sources, final Source source) {
         Collections.sort(apisUsed);
 
diff --git a/src/test/java/org/apache/tomee/website/LearningLinksTest.java b/src/test/java/org/apache/tomee/website/LearningLinksTest.java
index 09e8b37..9f26e55 100644
--- a/src/test/java/org/apache/tomee/website/LearningLinksTest.java
+++ b/src/test/java/org/apache/tomee/website/LearningLinksTest.java
@@ -17,8 +17,15 @@
 package org.apache.tomee.website;
 
 import org.junit.Test;
+import org.tomitribe.util.Archive;
+import org.tomitribe.util.Files;
+import org.tomitribe.util.Join;
 
 import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
 
@@ -37,4 +44,181 @@ public class LearningLinksTest {
         final String basePath = LearningLinks.pathFromContentRoot(file);
         assertEquals("tomee-9.0/pt/examples/injection-of-entitymanager.adoc", basePath);
     }
+
+    @Test
+    public void sortBySize() throws IOException {
+        final File dir = Archive.archive()
+                .add("target/jbake/content/tomee-9.0/examples/b.adoc", new byte[141])
+                .add("target/jbake/content/tomee-9.0/examples/a.adoc", new byte[60])
+                .add("target/jbake/content/tomee-9.0/examples/c.adoc", new byte[10])
+                .add("target/jbake/content/tomee-8.0/examples/b.adoc", new byte[123])
+                .add("target/jbake/content/tomee-8.0/examples/a.adoc", new byte[61])
+                .add("target/jbake/content/tomee-8.0/examples/c.adoc", new byte[4])
+                .add("target/jbake/content/latest/examples/b.adoc", new byte[12])
+                .add("target/jbake/content/latest/examples/a.adoc", new byte[5])
+                .add("target/jbake/content/latest/examples/c.adoc", new byte[90])
+                .toDir();
+
+        final List<Example> examples = Files.collect(dir).stream()
+                .filter(file -> file.getName().endsWith(".adoc"))
+                .map(Example::from)
+                .peek(example -> example.setDestReadme(example.getSrcReadme()))
+                .collect(Collectors.toList());
+
+        Collections.shuffle(examples);
+
+        examples.sort(LearningLinks::compareBySize);
+
+        final List<String> collect = examples.stream()
+                .map(Example::getDestReadme)
+                .map(LearningLinks::pathFromContentRoot)
+                .collect(Collectors.toList());
+
+        assertEquals("tomee-9.0/examples/b.adoc\n" +
+                "tomee-8.0/examples/b.adoc\n" +
+                "latest/examples/c.adoc\n" +
+                "tomee-8.0/examples/a.adoc\n" +
+                "tomee-9.0/examples/a.adoc\n" +
+                "latest/examples/b.adoc\n" +
+                "tomee-9.0/examples/c.adoc\n" +
+                "latest/examples/a.adoc\n" +
+                "tomee-8.0/examples/c.adoc", Join.join("\n", collect));
+    }
+
+    @Test
+    public void sortByVersion() throws IOException {
+        final File dir = Archive.archive()
+                .add("target/jbake/content/tomee-9.0/examples/b.adoc", new byte[141])
+                .add("target/jbake/content/tomee-9.0/examples/a.adoc", new byte[60])
+                .add("target/jbake/content/tomee-9.0/examples/c.adoc", new byte[10])
+                .add("target/jbake/content/tomee-8.0/examples/b.adoc", new byte[123])
+                .add("target/jbake/content/tomee-8.0/examples/a.adoc", new byte[61])
+                .add("target/jbake/content/tomee-8.0/examples/c.adoc", new byte[4])
+                .add("target/jbake/content/latest/examples/b.adoc", new byte[12])
+                .add("target/jbake/content/latest/examples/a.adoc", new byte[5])
+                .add("target/jbake/content/latest/examples/c.adoc", new byte[90])
+                .toDir();
+
+        final List<Example> examples = Files.collect(dir).stream()
+                .filter(file -> file.getName().endsWith(".adoc"))
+                .map(Example::from)
+                .peek(example -> example.setDestReadme(example.getSrcReadme()))
+                .collect(Collectors.toList());
+
+        Collections.shuffle(examples);
+
+        examples.sort(LearningLinks::compareBySize); // for stability
+        examples.sort(LearningLinks::compareByVersion);
+
+        final List<String> collect = examples.stream()
+                .map(Example::getDestReadme)
+                .map(LearningLinks::pathFromContentRoot)
+                .collect(Collectors.toList());
+
+        assertEquals("" +
+                "tomee-9.0/examples/c.adoc\n" +
+                "tomee-9.0/examples/b.adoc\n" +
+                "tomee-9.0/examples/a.adoc\n" +
+                "tomee-8.0/examples/c.adoc\n" +
+                "tomee-8.0/examples/b.adoc\n" +
+                "tomee-8.0/examples/a.adoc\n" +
+                "latest/examples/c.adoc\n" +
+                "latest/examples/b.adoc\n" +
+                "latest/examples/a.adoc", Join.join("\n", collect));
+    }
+
+    @Test
+    public void sortByLatest() throws IOException {
+        final File dir = Archive.archive()
+                .add("target/jbake/content/master/examples/b.adoc", new byte[111])
+                .add("target/jbake/content/master/examples/a.adoc", new byte[70])
+                .add("target/jbake/content/master/examples/c.adoc", new byte[20])
+                .add("target/jbake/content/tomee-9.0/examples/b.adoc", new byte[141])
+                .add("target/jbake/content/tomee-9.0/examples/a.adoc", new byte[60])
+                .add("target/jbake/content/tomee-9.0/examples/c.adoc", new byte[10])
+                .add("target/jbake/content/tomee-8.0/examples/b.adoc", new byte[123])
+                .add("target/jbake/content/tomee-8.0/examples/a.adoc", new byte[61])
+                .add("target/jbake/content/tomee-8.0/examples/c.adoc", new byte[4])
+                .add("target/jbake/content/latest/examples/b.adoc", new byte[12])
+                .add("target/jbake/content/latest/examples/a.adoc", new byte[5])
+                .add("target/jbake/content/latest/examples/c.adoc", new byte[90])
+                .toDir();
+
+        final List<Example> examples = Files.collect(dir).stream()
+                .filter(file -> file.getName().endsWith(".adoc"))
+                .map(Example::from)
+                .peek(example -> example.setDestReadme(example.getSrcReadme()))
+                .collect(Collectors.toList());
+
+        Collections.shuffle(examples);
+
+        examples.sort(LearningLinks::compareBySize);
+        examples.sort(LearningLinks::compareByLatest);
+        assertEquals("" +
+                "latest/examples/c.adoc\n" +
+                "latest/examples/b.adoc\n" +
+                "latest/examples/a.adoc\n" +
+                "tomee-9.0/examples/b.adoc\n" +
+                "tomee-8.0/examples/b.adoc\n" +
+                "tomee-8.0/examples/a.adoc\n" +
+                "tomee-9.0/examples/a.adoc\n" +
+                "tomee-9.0/examples/c.adoc\n" +
+                "tomee-8.0/examples/c.adoc\n" +
+                "master/examples/b.adoc\n" +
+                "master/examples/a.adoc\n" +
+                "master/examples/c.adoc", toPaths(examples));
+    }
+
+    @Test
+    public void sort() throws IOException {
+        final File dir = Archive.archive()
+                .add("target/jbake/content/master/examples/b.adoc", new byte[111])
+                .add("target/jbake/content/master/examples/a.adoc", new byte[70])
+                .add("target/jbake/content/master/examples/c.adoc", new byte[20])
+                .add("target/jbake/content/tomee-9.0/examples/b.adoc", new byte[141])
+                .add("target/jbake/content/tomee-9.0/examples/a.adoc", new byte[60])
+                .add("target/jbake/content/tomee-9.0/examples/c.adoc", new byte[10])
+                .add("target/jbake/content/tomee-8.0/examples/b.adoc", new byte[123])
+                .add("target/jbake/content/tomee-8.0/examples/a.adoc", new byte[61])
+                .add("target/jbake/content/tomee-8.0/examples/c.adoc", new byte[4])
+                .add("target/jbake/content/latest/examples/b.adoc", new byte[12])
+                .add("target/jbake/content/latest/examples/a.adoc", new byte[5])
+                .add("target/jbake/content/latest/examples/c.adoc", new byte[90])
+                .toDir();
+
+        final List<Example> examples = Files.collect(dir).stream()
+                .filter(file -> file.getName().endsWith(".adoc"))
+                .map(Example::from)
+                .peek(example -> example.setDestReadme(example.getSrcReadme()))
+                .collect(Collectors.toList());
+
+        Collections.shuffle(examples);
+
+        final List<Example> sorted = LearningLinks.sort(examples);
+
+        assertEquals("" +
+                "latest/examples/c.adoc\n" +
+                "latest/examples/b.adoc\n" +
+                "latest/examples/a.adoc\n" +
+                "tomee-9.0/examples/c.adoc\n" +
+                "tomee-9.0/examples/b.adoc\n" +
+                "tomee-9.0/examples/a.adoc\n" +
+                "tomee-8.0/examples/c.adoc\n" +
+                "tomee-8.0/examples/b.adoc\n" +
+                "tomee-8.0/examples/a.adoc\n" +
+                "master/examples/c.adoc\n" +
+                "master/examples/b.adoc\n" +
+                "master/examples/a.adoc", toPaths(sorted));
+    }
+
+    private static String toPaths(final List<Example> examples) {
+        final List<String> collect = examples.stream()
+                .map(Example::getDestReadme)
+                .map(LearningLinks::pathFromContentRoot)
+                .collect(Collectors.toList());
+
+        final String actual = Join.join("\n", collect);
+        return actual;
+    }
+
 }


[tomee-site-generator] 05/11: Functional bi-directional links from javadocs to examples

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 858d66654ca2b2eb64faa87c56fea24df8cac60c
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 11:47:25 2020 -0700

    Functional bi-directional links from javadocs to examples
---
 .../java/org/apache/tomee/website/ApisUsed.java    |  69 ++++++
 .../org/apache/tomee/website/Configuration.java    |  12 +-
 .../website/{SeeLinks.java => ExampleLinks.java}   |  44 ++--
 .../java/org/apache/tomee/website/Javadocs.java    |   2 +
 .../org/apache/tomee/website/LearningLinks.java    |  74 ++++++-
 .../java/org/apache/tomee/website/Sources.java     |   1 +
 .../org/apache/tomee/website/ApisUsedTest.java     | 127 +++++++++++
 .../{SeeLinksTest.java => ExampleLinksTest.java}   |  28 +--
 .../apache/tomee/website/LearningLinksTest.java    |  40 ++++
 .../ApisUsedTest/abnormalHeading/after.adoc        | 230 ++++++++++++++++++++
 .../ApisUsedTest/abnormalHeading/before.adoc       | 229 ++++++++++++++++++++
 .../ApisUsedTest/hasOtherSections/after.adoc       | 235 +++++++++++++++++++++
 .../ApisUsedTest/hasOtherSections/before.adoc      | 234 ++++++++++++++++++++
 .../resources/ApisUsedTest/insertHref/after.adoc   | 230 ++++++++++++++++++++
 .../resources/ApisUsedTest/insertHref/before.adoc  | 226 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/after1.adoc       | 230 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/after2.adoc       | 231 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/after3.adoc       | 232 ++++++++++++++++++++
 .../ApisUsedTest/multipleInserts/before.adoc       | 226 ++++++++++++++++++++
 .../resources/ApisUsedTest/noDuplicates/after.adoc | 230 ++++++++++++++++++++
 .../ApisUsedTest/noDuplicates/before.adoc          | 226 ++++++++++++++++++++
 .../finalClass}/after.java                         |   4 +-
 .../finalClass}/before.java                        |   2 +-
 .../hasAnnotations/after.java                      |   2 +-
 .../hasAnnotations/before.java                     |   0
 .../insertHref}/after.java                         |   2 +-
 .../insertHref}/before.java                        |   0
 .../multipleInserts/after1.java                    |   2 +-
 .../multipleInserts/after2.java                    |   4 +-
 .../multipleInserts/after3.java                    |   6 +-
 .../multipleInserts/before.java                    |   0
 .../noDuplicates}/after.java                       |   2 +-
 .../noDuplicates}/before.java                      |   0
 .../noJavadoc/after.java                           |   2 +-
 .../noJavadoc/before.java                          |   0
 35 files changed, 3129 insertions(+), 53 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/ApisUsed.java b/src/main/java/org/apache/tomee/website/ApisUsed.java
new file mode 100644
index 0000000..08d24a9
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/ApisUsed.java
@@ -0,0 +1,69 @@
+/*
+ * 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.tomee.website;
+
+import org.tomitribe.util.PrintString;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ApisUsed {
+
+    private static final Pattern HEADER = Pattern.compile("\n=+ *apis +used *\n", Pattern.CASE_INSENSITIVE);
+
+    public static String insertHref(String source, final String link, final String linkText) {
+        source = normalize(source);
+
+        if (source.contains("\n= APIs Used\n")) {
+            return updateApiList(source, link, linkText);
+        } else {
+            return addApiList(source, link, linkText);
+        }
+    }
+
+    private static String addApiList(final String source, final String link, final String linkText) {
+        final PrintString out = new PrintString();
+        out.println("");
+        out.println("= APIs Used");
+        out.println("");
+        out.printf("- link:%s[%s]%n", link, linkText);
+
+        return source + out.toString();
+    }
+
+    private static String updateApiList(final String source, final String link, final String linkText) {
+        final int start = source.indexOf("\n= APIs Used\n");
+        final int end = ExampleLinks.min(source.indexOf("\n=", start + 1), source.length());
+        final String content = source.substring(start, end);
+
+        /*
+         * Do not add this link if there already one with the same title
+         */
+        if (content.contains(String.format("[%s]", linkText))) return source;
+
+        final String updated = content + String.format("- link:%s[%s]%n", link, linkText);
+
+        return source.replace(content, updated);
+    }
+
+    protected static String normalize(final String source) {
+        final Matcher matcher = HEADER.matcher(source);
+        if (!matcher.find()) return source;
+
+        return matcher.replaceAll("\n= APIs Used\n");
+    }
+}
diff --git a/src/main/java/org/apache/tomee/website/Configuration.java b/src/main/java/org/apache/tomee/website/Configuration.java
index 1b90fac..a182043 100644
--- a/src/main/java/org/apache/tomee/website/Configuration.java
+++ b/src/main/java/org/apache/tomee/website/Configuration.java
@@ -92,12 +92,12 @@ public class Configuration {
         return new Source[]{
 //                new Source("https://github.com/apache/tomee.git", "master", "tomee-8.0"),
                 new Source("https://github.com/apache/tomee.git", "master", "tomee-9.0").label("milestone").related(microProfile2).related(jakartaEE9).javadoc("^org.apache.(openejb|tomee).*"),
-                new Source("https://github.com/apache/tomee.git", "master", "tomee-8.0", true).related(microProfile2).related(jakartaEE8).javadoc("^org.apache.(openejb|tomee).*"),
-                new Source("https://github.com/apache/tomee.git", "tomee-7.1.0", "tomee-7.1").javadoc("^org.apache.(openejb|tomee).*"),
-                new Source("https://github.com/apache/tomee.git", "tomee-7.0.5", "tomee-7.0").javadoc("^org.apache.(openejb|tomee).*"),
-                new Source("https://github.com/apache/tomee.git", "master", "master").javadoc("^org.apache.(openejb|tomee).*"),
-                new Source("https://github.com/eclipse/microprofile-bom.git", "master", "microprofile-2.0").related(microProfile2).javadoc("^org.eclipse.microprofile.*"),
-                new Source("https://github.com/eclipse-ee4j/jakartaee-platform.git", "v8", "jakartaee-8.0").related(jakartaEE8).javadoc("^javax.*"),
+//                new Source("https://github.com/apache/tomee.git", "master", "tomee-8.0", true).related(microProfile2).related(jakartaEE8).javadoc("^org.apache.(openejb|tomee).*"),
+//                new Source("https://github.com/apache/tomee.git", "tomee-7.1.0", "tomee-7.1").javadoc("^org.apache.(openejb|tomee).*"),
+//                new Source("https://github.com/apache/tomee.git", "tomee-7.0.5", "tomee-7.0").javadoc("^org.apache.(openejb|tomee).*"),
+//                new Source("https://github.com/apache/tomee.git", "master", "master").javadoc("^org.apache.(openejb|tomee).*"),
+//                new Source("https://github.com/eclipse/microprofile-bom.git", "master", "microprofile-2.0").related(microProfile2).javadoc("^org.eclipse.microprofile.*"),
+//                new Source("https://github.com/eclipse-ee4j/jakartaee-platform.git", "v8", "jakartaee-8.0").related(jakartaEE8).javadoc("^javax.*"),
                 new Source("https://github.com/eclipse-ee4j/jakartaee-platform.git", "master", "jakartaee-9.0").related(jakartaEE9).javadoc("^jakarta.*")
         };
     }
diff --git a/src/main/java/org/apache/tomee/website/SeeLinks.java b/src/main/java/org/apache/tomee/website/ExampleLinks.java
similarity index 64%
rename from src/main/java/org/apache/tomee/website/SeeLinks.java
rename to src/main/java/org/apache/tomee/website/ExampleLinks.java
index 9979361..0044a7a 100644
--- a/src/main/java/org/apache/tomee/website/SeeLinks.java
+++ b/src/main/java/org/apache/tomee/website/ExampleLinks.java
@@ -16,18 +16,26 @@
  */
 package org.apache.tomee.website;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import org.tomitribe.swizzle.stream.StreamLexer;
+import org.tomitribe.util.IO;
+import org.tomitribe.util.Join;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
- * Utility class to insert additional @see links into java source code.
+ * Utility class to insert additional @example links into java source code.
  * If no Javadoc exists at the class level, some will be added.
+ *
+ * The @example tag is a custom javadoc tag that creates various "Examples" sections
+ * in the generated javadoc.
  */
-public class SeeLinks {
+public class ExampleLinks {
 
     public static String insertHref(final String source, final String link, final String linkText) {
         final int start = Math.max(source.lastIndexOf("\nimport "), source.indexOf("\npackage "));
-        final int end = min(source.indexOf("\npublic "), source.indexOf("\n@"));
+        final int end = min(min(source.indexOf("\npublic "), source.indexOf("\n@")), source.indexOf("\nfinal"));
 
         final String header = source.substring(start, end);
 
@@ -38,7 +46,10 @@ public class SeeLinks {
         }
     }
 
-    private static int min(final int a, final int b) {
+    /**
+     * Returns the lowest viable index
+     */
+    public static int min(final int a, final int b) {
         if (a == -1) return b;
         if (b == -1) return a;
         return Math.min(a, b);
@@ -46,7 +57,7 @@ public class SeeLinks {
 
     private static String addComment(final String source, final String link, final String linkText, final String header) {
         final String href = href(link, linkText);
-        final String comment = header + "\n/**" + href + "\n */";
+        final String comment = header + "\n/**\n" + href + "\n */";
         return source.replace(header, comment);
     }
 
@@ -56,22 +67,27 @@ public class SeeLinks {
          */
         if (header.contains(String.format(">%s</a>", linkText))) return source;
 
-        final Pattern commentPattern = Pattern.compile("/\\*\\*(.*\n*)*?\n *\\*/");
-        final Matcher matcher = commentPattern.matcher(header);
-        if (!matcher.find()) return source;
-
-        final String comment = matcher.group(0);
+        final StreamLexer lexer = new StreamLexer(IO.read(header));
+        final String comment;
+        try {
+            comment = lexer.readToken("/**", "*/");
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
 
         final String href = href(link, linkText);
 
-        final String updatedComment = comment.replaceFirst("(\n *\\*/)", href + "$1");
+        final List<String> lines = new ArrayList<>(Arrays.asList(comment.split("\n")));
+        lines.add(lines.size() - 1, href);
+
+        final String updatedComment = Join.join("\n", lines);
 
         // TODO
         return source.replace(comment, updatedComment);
     }
 
     private static String href(final String link, final String linkText) {
-        final String href = String.format("\n * @see <a href=\"%s\">%s</a>", link, linkText);
+        final String href = String.format(" * @example <a href=\"%s\">%s</a>", link, linkText);
         return href;
     }
 }
diff --git a/src/main/java/org/apache/tomee/website/Javadocs.java b/src/main/java/org/apache/tomee/website/Javadocs.java
index 5198e63..ae187d9 100644
--- a/src/main/java/org/apache/tomee/website/Javadocs.java
+++ b/src/main/java/org/apache/tomee/website/Javadocs.java
@@ -92,6 +92,8 @@ public class Javadocs {
             final File javadocOutput = sources.getGeneratedDestFor(source, "javadoc");
             final ProcessBuilder cmd = new ProcessBuilder(
                     getJavadocCommand().getAbsolutePath(),
+                    "-tag",
+                    "example:a:Examples:",
                     "-sourcepath",
                     javaSources.getAbsolutePath(),
                     "-d",
diff --git a/src/main/java/org/apache/tomee/website/LearningLinks.java b/src/main/java/org/apache/tomee/website/LearningLinks.java
index 1f2614c..9f170f4 100644
--- a/src/main/java/org/apache/tomee/website/LearningLinks.java
+++ b/src/main/java/org/apache/tomee/website/LearningLinks.java
@@ -21,11 +21,14 @@ import org.tomitribe.tio.Dir;
 import org.tomitribe.tio.Match;
 import org.tomitribe.tio.lang.JvmLang;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -99,7 +102,60 @@ public class LearningLinks {
     }
 
     private void addApisUsed(final Example example, final List<String> apisUsed, final Map<String, JavadocSource> sources, final Source source) {
-        // TODO
+        Collections.sort(apisUsed);
+
+        String content = null;
+        try {
+            content = IO.slurp(example.getDestReadme());
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+
+        final String basePath = pathToContentRoot(example.getDestReadme());
+
+        final List<JavadocSource> list = apisUsed.stream()
+                .map(sources::get)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        for (JavadocSource javadocSource : list) {
+            final String link = String.format("%s%s/javadoc/%s.html",
+                    basePath,
+                    source.getName(),
+                    javadocSource.getClassName().replace(".", "/"));
+
+            content = ApisUsed.insertHref(content, link, javadocSource.getClassName());
+        }
+
+        try {
+            IO.copy(IO.read(content), example.getDestReadme());
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    static String pathToContentRoot(final File file) {
+        final StringBuilder sb = new StringBuilder();
+
+        File parent = file;
+        while ((parent = parent.getParentFile()) != null && !parent.getName().equals("content")) {
+            sb.append("../");
+        }
+
+        return sb.toString();
+    }
+
+    static String pathFromContentRoot(final File file) {
+        final String absolutePath = file.getAbsolutePath();
+
+        final String content = "/content/";
+        final int indexOfContent = absolutePath.indexOf(content);
+
+        if (indexOfContent == -1) {
+            throw new IllegalStateException("Expected '/content/' section of path not found: " + absolutePath);
+        }
+
+        return absolutePath.substring(indexOfContent + content.length());
     }
 
 
@@ -107,18 +163,23 @@ public class LearningLinks {
         try {
             final String content = IO.slurp(javadocSource.getSourceFile());
 
-            // TODO this link won't resolve as-is, it needs to be relative
-            final String link = example.getHref();
+            final String toContentRoot = pathToContentRoot(javadocSource.getSourceFile());
+            final String fromContentRoot = pathFromContentRoot(example.getDestReadme())
+                    .replace(".adoc", ".html")
+                    .replace(".md", ".html");
+
+            final String link = toContentRoot + fromContentRoot;
 
             final String name = example.getName();
 
+
             // Update the source contents to include an href link
-            final String modified = SeeLinks.insertHref(content, link, name);
+            final String modified = ExampleLinks.insertHref(content, link, name);
 
             // Overwrite the source with the newly linked version
             IO.copy(IO.read(modified), javadocSource.getSourceFile());
-        } catch (IOException e) {
-            throw new UncheckedIOException("Unable to add link to example: " + example.getName(), e);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unable to add link to java source: " + javadocSource.getSourceFile().getAbsolutePath(), e);
         }
     }
 
@@ -162,4 +223,5 @@ public class LearningLinks {
 
     }
 
+
 }
diff --git a/src/main/java/org/apache/tomee/website/Sources.java b/src/main/java/org/apache/tomee/website/Sources.java
index 579790d..b0bd03a 100644
--- a/src/main/java/org/apache/tomee/website/Sources.java
+++ b/src/main/java/org/apache/tomee/website/Sources.java
@@ -157,6 +157,7 @@ public class Sources {
                 .flatMap(Source::stream)
                 .map(Source::getPerform)
                 .flatMap(Collection::stream)
+                .peek(runnable -> System.out.println("Running Hook " + runnable))
                 .forEach(Runnable::run);
 
         VersionsIndex.prepare(this);
diff --git a/src/test/java/org/apache/tomee/website/ApisUsedTest.java b/src/test/java/org/apache/tomee/website/ApisUsedTest.java
new file mode 100644
index 0000000..6807e5b
--- /dev/null
+++ b/src/test/java/org/apache/tomee/website/ApisUsedTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.tomee.website;
+
+import org.junit.Test;
+
+import static org.apache.tomee.website.Scenario.scenario;
+import static org.junit.Assert.assertEquals;
+
+public class ApisUsedTest {
+
+
+    /**
+     * If an "APIs Used" section exists, but uses slightly different
+     * formatting, we should normalize it so it is consistent with
+     * all the other "APIs Used" sections
+     */
+    @Test
+    public void abnormalHeading() throws Exception {
+        final Scenario scenario = scenario(ApisUsedTest.class, "abnormalHeading");
+
+        final String input = scenario.get("before.adoc");
+
+        final String actual = ApisUsed.insertHref(input, "../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html", "jakarta.persistence.EntityManager");
+
+        assertEquals(scenario.get("after.adoc"), actual);
+    }
+
+    /**
+     * If an "APIs Used" section exists in the middle of a document
+     * and therefore has sections after it, we should update the
+     * section where it lives and not move it or mistakenly append
+     * another "APIs Used" section.
+     */
+    @Test
+    public void hasOtherSections() throws Exception {
+        final Scenario scenario = scenario(ApisUsedTest.class, "hasOtherSections");
+
+        final String input = scenario.get("before.adoc");
+
+        final String actual = ApisUsed.insertHref(input, "../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html", "jakarta.persistence.EntityManager");
+
+        assertEquals(scenario.get("after.adoc"), actual);
+    }
+
+    /**
+     * Very basic happy-path test to add an "APIs Used" section
+     * to a document that doesn't yet have one.
+     */
+    @Test
+    public void insertHref() throws Exception {
+        final Scenario scenario = scenario(ApisUsedTest.class, "insertHref");
+
+        final String input = scenario.get("before.adoc");
+
+        final String actual = ApisUsed.insertHref(input, "../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html", "jakarta.persistence.Entity");
+
+        assertEquals(scenario.get("after.adoc"), actual);
+    }
+
+    /**
+     * We should be able to insert links into the "APIs Used"
+     * section in several different calls.  The first call
+     * will add the section and the subsequent calls will
+     * update the now-existing section.
+     */
+    @Test
+    public void multipleInserts() throws Exception {
+        final Scenario scenario = scenario(ApisUsedTest.class, "multipleInserts");
+
+        final String input = scenario.get("before.adoc");
+
+        final String after1 = ApisUsed.insertHref(input,
+                "../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html",
+                "jakarta.persistence.Entity");
+        assertEquals(scenario.get("after1.adoc"), after1);
+
+        final String after2 = ApisUsed.insertHref(after1,
+                "../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html",
+                "jakarta.persistence.EntityManager");
+        assertEquals(scenario.get("after2.adoc"), after2);
+
+        final String after3 = ApisUsed.insertHref(after2,
+                "../../../jakartaee-9.0/javadoc/jakarta/persistence/Id.html",
+                "jakarta.persistence.Id");
+        assertEquals(scenario.get("after3.adoc"), after3);
+    }
+
+    /**
+     * If an API is already listed in the "APIs Used" section we should
+     * not add it again.
+     */
+    @Test
+    public void noDuplicates() throws Exception {
+        final Scenario scenario = scenario(ApisUsedTest.class, "noDuplicates");
+
+        final String input = scenario.get("before.adoc");
+
+        final String after1 = ApisUsed.insertHref(input, "../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html", "jakarta.persistence.Entity");
+
+        assertEquals(scenario.get("after.adoc"), after1);
+
+        final String after2 = ApisUsed.insertHref(after1, "../../../jakartaee-8.0/javadoc/jakarta/persistence/Entity.html", "jakarta.persistence.Entity");
+
+        assertEquals(scenario.get("after.adoc"), after2);
+    }
+
+    @Test
+    public void normalize() throws Exception {
+        assertEquals("\n= APIs Used\n- link", ApisUsed.normalize("\n====  ApIs usEd\n- link"));
+    }
+
+}
diff --git a/src/test/java/org/apache/tomee/website/SeeLinksTest.java b/src/test/java/org/apache/tomee/website/ExampleLinksTest.java
similarity index 66%
rename from src/test/java/org/apache/tomee/website/SeeLinksTest.java
rename to src/test/java/org/apache/tomee/website/ExampleLinksTest.java
index e740239..3b15094 100644
--- a/src/test/java/org/apache/tomee/website/SeeLinksTest.java
+++ b/src/test/java/org/apache/tomee/website/ExampleLinksTest.java
@@ -25,18 +25,18 @@ import static org.apache.tomee.website.Scenario.scenario;
 import static org.junit.Assert.assertEquals;
 
 @Ignore
-public class SeeLinksTest {
+public class ExampleLinksTest {
 
     /**
      * Test we can insert an @see link into some code that already has some javadoc
      */
     @Test
     public void insertHref() throws IOException {
-        final Scenario scenario = scenario(SeeLinksTest.class, "insertHref");
+        final Scenario scenario = scenario(ExampleLinksTest.class, "insertHref");
 
         final String input = scenario.get("before.java");
 
-        final String actual = SeeLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
 
         assertEquals(scenario.get("after.java"), actual);
     }
@@ -46,11 +46,11 @@ public class SeeLinksTest {
      */
     @Test
     public void noJavadoc() throws IOException {
-        final Scenario scenario = scenario(SeeLinksTest.class, "noJavadoc");
+        final Scenario scenario = scenario(ExampleLinksTest.class, "noJavadoc");
 
         final String input = scenario.get("before.java");
 
-        final String actual = SeeLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
 
         assertEquals(scenario.get("after.java"), actual);
     }
@@ -60,17 +60,17 @@ public class SeeLinksTest {
      */
     @Test
     public void multipleInserts() throws IOException {
-        final Scenario scenario = scenario(SeeLinksTest.class, "multipleInserts");
+        final Scenario scenario = scenario(ExampleLinksTest.class, "multipleInserts");
 
         final String input = scenario.get("before.java");
 
-        final String after1 = SeeLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
         assertEquals(scenario.get("after1.java"), after1);
 
-        final String after2 = SeeLinks.insertHref(after1, "http://example.org/red.html", "Red Sample");
+        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/red.html", "Red Sample");
         assertEquals(scenario.get("after2.java"), after2);
 
-        final String after3 = SeeLinks.insertHref(after2, "http://example.org/yellow.html", "yellow");
+        final String after3 = ExampleLinks.insertHref(after2, "http://example.org/yellow.html", "yellow");
         assertEquals(scenario.get("after3.java"), after3);
     }
 
@@ -79,15 +79,15 @@ public class SeeLinksTest {
      */
     @Test
     public void noDuplicates() throws IOException {
-        final Scenario scenario = scenario(SeeLinksTest.class, "noDuplicates");
+        final Scenario scenario = scenario(ExampleLinksTest.class, "noDuplicates");
 
         final String input = scenario.get("before.java");
 
-        final String after1 = SeeLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
         assertEquals(scenario.get("after.java"), after1);
 
         // The second insert should be ignored as it has the same title "Orange Example"
-        final String after2 = SeeLinks.insertHref(after1, "http://example.org/foo.html", "Orange Example");
+        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/foo.html", "Orange Example");
         assertEquals(scenario.get("after.java"), after2);
     }
 
@@ -96,11 +96,11 @@ public class SeeLinksTest {
      */
     @Test
     public void hasAnnotations() throws IOException {
-        final Scenario scenario = scenario(SeeLinksTest.class, "hasAnnotations");
+        final Scenario scenario = scenario(ExampleLinksTest.class, "hasAnnotations");
 
         final String input = scenario.get("before.java");
 
-        final String actual = SeeLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
         assertEquals(scenario.get("after.java"), actual);
     }
 
diff --git a/src/test/java/org/apache/tomee/website/LearningLinksTest.java b/src/test/java/org/apache/tomee/website/LearningLinksTest.java
new file mode 100644
index 0000000..09e8b37
--- /dev/null
+++ b/src/test/java/org/apache/tomee/website/LearningLinksTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.tomee.website;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+
+public class LearningLinksTest {
+
+    @Test
+    public void pathToContentRoot() {
+        final File file = new File("tomee-site-generator/target/jbake/content/tomee-9.0/pt/examples/injection-of-entitymanager.adoc");
+        final String basePath = LearningLinks.pathToContentRoot(file);
+        assertEquals("../../../", basePath);
+    }
+
+    @Test
+    public void pathFromContentRoot() {
+        final File file = new File("tomee-site-generator/target/jbake/content/tomee-9.0/pt/examples/injection-of-entitymanager.adoc");
+        final String basePath = LearningLinks.pathFromContentRoot(file);
+        assertEquals("tomee-9.0/pt/examples/injection-of-entitymanager.adoc", basePath);
+    }
+}
diff --git a/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc b/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc
new file mode 100644
index 0000000..9a6d5db
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/abnormalHeading/after.adoc
@@ -0,0 +1,230 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
diff --git a/src/test/resources/ApisUsedTest/abnormalHeading/before.adoc b/src/test/resources/ApisUsedTest/abnormalHeading/before.adoc
new file mode 100644
index 0000000..7c72a68
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/abnormalHeading/before.adoc
@@ -0,0 +1,229 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+====  ApIs usEd
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
diff --git a/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc b/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc
new file mode 100644
index 0000000..f6e1e43
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/hasOtherSections/after.adoc
@@ -0,0 +1,235 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
+
+= Related Examples
+
+- link:foo.html
\ No newline at end of file
diff --git a/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc b/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc
new file mode 100644
index 0000000..7966535
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/hasOtherSections/before.adoc
@@ -0,0 +1,234 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
+
+= Related Examples
+
+- link:foo.html
\ No newline at end of file
diff --git a/src/test/resources/ApisUsedTest/insertHref/after.adoc b/src/test/resources/ApisUsedTest/insertHref/after.adoc
new file mode 100644
index 0000000..f83a09d
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/insertHref/after.adoc
@@ -0,0 +1,230 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
diff --git a/src/test/resources/ApisUsedTest/insertHref/before.adoc b/src/test/resources/ApisUsedTest/insertHref/before.adoc
new file mode 100644
index 0000000..5a86e09
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/insertHref/before.adoc
@@ -0,0 +1,226 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc b/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc
new file mode 100644
index 0000000..f83a09d
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/multipleInserts/after1.adoc
@@ -0,0 +1,230 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc b/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc
new file mode 100644
index 0000000..95aaa88
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/multipleInserts/after2.adoc
@@ -0,0 +1,231 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc b/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc
new file mode 100644
index 0000000..906b6ff
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/multipleInserts/after3.adoc
@@ -0,0 +1,232 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/EntityManager.html[jakarta.persistence.EntityManager]
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Id.html[jakarta.persistence.Id]
diff --git a/src/test/resources/ApisUsedTest/multipleInserts/before.adoc b/src/test/resources/ApisUsedTest/multipleInserts/before.adoc
new file mode 100644
index 0000000..5a86e09
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/multipleInserts/before.adoc
@@ -0,0 +1,226 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
diff --git a/src/test/resources/ApisUsedTest/noDuplicates/after.adoc b/src/test/resources/ApisUsedTest/noDuplicates/after.adoc
new file mode 100644
index 0000000..f83a09d
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/noDuplicates/after.adoc
@@ -0,0 +1,230 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
+
+= APIs Used
+
+- link:../../../jakartaee-9.0/javadoc/jakarta/persistence/Entity.html[jakarta.persistence.Entity]
diff --git a/src/test/resources/ApisUsedTest/noDuplicates/before.adoc b/src/test/resources/ApisUsedTest/noDuplicates/before.adoc
new file mode 100644
index 0000000..5a86e09
--- /dev/null
+++ b/src/test/resources/ApisUsedTest/noDuplicates/before.adoc
@@ -0,0 +1,226 @@
+= Injeção de Entitymanager
+:index-group: JPA
+:jbake-type: page
+:jbake-status: published
+
+Este exemplo mostra o uso de `@PersistenceContext` para ter um `EntityManager` com um contexto de persistência `EXTENDED` injetado em um `@Stateful bean`. Um bean JPA `@ Entity` é usado com o `EntityManager` para criar, persistir e mesclar dados em um banco de dados.
+
+== Criando a entidade JPA
+
+A própria entidade é simplesmente um pote anotado com `@Entity`. Criamos um chamado `Movie`, que podemos usar para armazenar registros de filmes.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.persistence.Entity;
+
+@Entity
+public class Movie {
+
+    @Id @GeneratedValue
+    private long id;
+
+    private String director;
+    private String title;
+    private int year;
+
+    public Movie() {
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Movie(String director, String title, int year) {
+        this.director = director;
+        this.title = title;
+        this.year = year;
+    }
+
+    public String getDirector() {
+        return director;
+    }
+
+    public void setDirector(String director) {
+        this.director = director;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getYear() {
+        return year;
+    }
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+}
+----
+
+== Configure o EntityManager por meio de um arquivo persistence.xml
+
+A entidade `Movie` acima pode ser criada, removida, atualizada ou excluída através de um objeto` EntityManager`.
+O próprio `EntityManager` é configurado através de um arquivo `META-INF/persistence.xml` que é colocado no mesmo jar que a entidade `Movie`.
+
+[source,xml,numbered]
+----
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+
+  <persistence-unit name="movie-unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+    <class>org.superbiz.injection.jpa.Movie</class>
+
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
+</persistence>
+----
+
+Observe que a entidade `Movie` é listada através de um elemento `<class>`. Isso não é necessário, mas pode ajudar no teste ou quando a classe `Movie` estiver localizada em um jar diferente do jar que contém o arquivo `persistence.xml`.
+
+==Injeção via @PersistenceContext
+
+O próprio `EntityManager` é criado pelo contêiner usando as informações no `persistence.xml`, portanto, para usá-lo em tempo de execução, basta solicitar que ele seja injetado em um de nossos componentes. Fazemos isso via `@PersistenceContext`
+
+A anotação `@PersistenceContext` pode ser usada em qualquer bean CDI, EJB, Servlet, Servlet Listener, Servlet Filter ou JSF ManagedBean. Se você não usar um EJB, precisará usar um `UserTransaction` para iniciar e confirmar transações manualmente. É necessária uma transação para que qualquer um dos métodos de criação, atualização ou exclusão do EntityManager funcione.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import jakarta.ejb.Stateful;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.PersistenceContextType;
+import jakarta.persistence.Query;
+import java.util.List;
+
+@Stateful
+public class Movies {
+
+    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
+    private EntityManager entityManager;
+
+    public void addMovie(Movie movie) throws Exception {
+        entityManager.persist(movie);
+    }
+
+    public void deleteMovie(Movie movie) throws Exception {
+        entityManager.remove(movie);
+    }
+
+    public List<Movie> getMovies() throws Exception {
+        Query query = entityManager.createQuery("SELECT m from Movie as m");
+        return query.getResultList();
+    }
+}
+----
+
+Este `EntityManager` específico é injetado como um contexto de persistência `EXTENDED`, o que significa simplesmente que o `EntityManager` é criado quando o bean `@Stateful` é criado e destruído quando o bean `@Stateful` é destruído. Simplificando, os dados no `EntityManager` são armazenados em cache durante o tempo de vida do bean `@ Stateful`.
+
+O uso de contextos de persistência `EXTENDED` está *apenas* disponível para beans `@Stateful`. Consulte o link: ../../jpa-concepts.html [Conceitos da JPA] para obter uma explicação de alto nível sobre o que realmente é um "contexto de persistência" e como é significativo para a JPA.
+
+== MoviesTest
+
+Testar o JPA é bastante fácil, podemos simplesmente usar a API `EJBContainer` para criar um contêiner em nosso caso de teste.
+
+[source,java,numbered]
+----
+package org.superbiz.injection.jpa;
+
+import junit.framework.TestCase;
+
+import jakarta.ejb.embeddable.EJBContainer;
+import javax.naming.Context;
+import java.util.List;
+import java.util.Properties;
+
+public class MoviesTest extends TestCase {
+
+    public void test() throws Exception {
+
+        final Properties p = new Properties();
+        p.put("movieDatabase", "new://Resource?type=DataSource");
+        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
+        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
+
+        final Context context = EJBContainer.createEJBContainer(p).getContext();
+
+        Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies");
+
+        movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
+        movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
+        movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));
+
+        List<Movie> list = movies.getMovies();
+        assertEquals("List.size()", 3, list.size());
+
+        for (Movie movie : list) {
+            movies.deleteMovie(movie);
+        }
+
+        assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
+    }
+}
+----
+
+= Executando
+
+Quando executamos nosso caso de teste, devemos ver uma saída semelhante à seguinte.
+
+[source,console]
+----
+-------------------------------------------------------
+ T E S T S
+-------------------------------------------------------
+Running org.superbiz.injection.jpa.MoviesTest
+Apache OpenEJB 4.0.0-beta-1    build: 20111002-04:06
+http://tomee.apache.org/
+INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager
+INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager
+INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true'
+INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
+INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
+INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
+INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes
+INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager
+INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
+INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
+INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
+INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container)
+INFO - Configuring PersistenceUnit(name=movie-unit)
+INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'.
+INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase)
+INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged'
+INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded.
+INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager
+INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies")
+INFO - Jndi(name="java:global/injection-of-entitymanager/Movies")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest")
+INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest")
+INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
+INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container)
+INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager)
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec
+
+Results :
+
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+----
diff --git a/src/test/resources/SeeLinksTest/noDuplicates/after.java b/src/test/resources/ExampleLinksTest/finalClass/after.java
similarity index 93%
copy from src/test/resources/SeeLinksTest/noDuplicates/after.java
copy to src/test/resources/ExampleLinksTest/finalClass/after.java
index 75f3b52..e91e524 100644
--- a/src/test/resources/SeeLinksTest/noDuplicates/after.java
+++ b/src/test/resources/ExampleLinksTest/finalClass/after.java
@@ -27,9 +27,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  * entity class.
  *
  * @since Java Persistence 1.0
- * @see <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
  */
-public interface Entity {
+final public interface Entity {
 
         /**
          * (Optional) The entity name. Defaults to the unqualified
diff --git a/src/test/resources/SeeLinksTest/noDuplicates/before.java b/src/test/resources/ExampleLinksTest/finalClass/before.java
similarity index 97%
copy from src/test/resources/SeeLinksTest/noDuplicates/before.java
copy to src/test/resources/ExampleLinksTest/finalClass/before.java
index 5ffc69c..eeee40d 100644
--- a/src/test/resources/SeeLinksTest/noDuplicates/before.java
+++ b/src/test/resources/ExampleLinksTest/finalClass/before.java
@@ -28,7 +28,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  *
  * @since Java Persistence 1.0
  */
-public interface Entity {
+final public interface Entity {
 
         /**
          * (Optional) The entity name. Defaults to the unqualified
diff --git a/src/test/resources/SeeLinksTest/hasAnnotations/after.java b/src/test/resources/ExampleLinksTest/hasAnnotations/after.java
similarity index 95%
rename from src/test/resources/SeeLinksTest/hasAnnotations/after.java
rename to src/test/resources/ExampleLinksTest/hasAnnotations/after.java
index f5a3706..ceefe62 100644
--- a/src/test/resources/SeeLinksTest/hasAnnotations/after.java
+++ b/src/test/resources/ExampleLinksTest/hasAnnotations/after.java
@@ -23,7 +23,7 @@ import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
- * @see <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
  */
 @Documented
 @Target(TYPE)
diff --git a/src/test/resources/SeeLinksTest/hasAnnotations/before.java b/src/test/resources/ExampleLinksTest/hasAnnotations/before.java
similarity index 100%
rename from src/test/resources/SeeLinksTest/hasAnnotations/before.java
rename to src/test/resources/ExampleLinksTest/hasAnnotations/before.java
diff --git a/src/test/resources/SeeLinksTest/noDuplicates/after.java b/src/test/resources/ExampleLinksTest/insertHref/after.java
similarity index 95%
rename from src/test/resources/SeeLinksTest/noDuplicates/after.java
rename to src/test/resources/ExampleLinksTest/insertHref/after.java
index 75f3b52..ef26259 100644
--- a/src/test/resources/SeeLinksTest/noDuplicates/after.java
+++ b/src/test/resources/ExampleLinksTest/insertHref/after.java
@@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  * entity class.
  *
  * @since Java Persistence 1.0
- * @see <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
  */
 public interface Entity {
 
diff --git a/src/test/resources/SeeLinksTest/noDuplicates/before.java b/src/test/resources/ExampleLinksTest/insertHref/before.java
similarity index 100%
rename from src/test/resources/SeeLinksTest/noDuplicates/before.java
rename to src/test/resources/ExampleLinksTest/insertHref/before.java
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/after1.java b/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
similarity index 92%
rename from src/test/resources/SeeLinksTest/multipleInserts/after1.java
rename to src/test/resources/ExampleLinksTest/multipleInserts/after1.java
index 13ae94a..0aa811d 100644
--- a/src/test/resources/SeeLinksTest/multipleInserts/after1.java
+++ b/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
@@ -17,7 +17,7 @@
 package javax.persistence;
 
 /**
- * @see <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/after2.java b/src/test/resources/ExampleLinksTest/multipleInserts/after2.java
similarity index 86%
rename from src/test/resources/SeeLinksTest/multipleInserts/after2.java
rename to src/test/resources/ExampleLinksTest/multipleInserts/after2.java
index d673789..7471d5e 100644
--- a/src/test/resources/SeeLinksTest/multipleInserts/after2.java
+++ b/src/test/resources/ExampleLinksTest/multipleInserts/after2.java
@@ -17,8 +17,8 @@
 package javax.persistence;
 
 /**
- * @see <a href="http://example.org/orange.html">Orange Example</a>
- * @see <a href="http://example.org/red.html">Red Sample</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/red.html">Red Sample</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/after3.java b/src/test/resources/ExampleLinksTest/multipleInserts/after3.java
similarity index 81%
rename from src/test/resources/SeeLinksTest/multipleInserts/after3.java
rename to src/test/resources/ExampleLinksTest/multipleInserts/after3.java
index a7f36e1..5eb5e0d 100644
--- a/src/test/resources/SeeLinksTest/multipleInserts/after3.java
+++ b/src/test/resources/ExampleLinksTest/multipleInserts/after3.java
@@ -17,9 +17,9 @@
 package javax.persistence;
 
 /**
- * @see <a href="http://example.org/orange.html">Orange Example</a>
- * @see <a href="http://example.org/red.html">Red Sample</a>
- * @see <a href="http://example.org/yellow.html">yellow</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/red.html">Red Sample</a>
+ * @example <a href="http://example.org/yellow.html">yellow</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/before.java b/src/test/resources/ExampleLinksTest/multipleInserts/before.java
similarity index 100%
rename from src/test/resources/SeeLinksTest/multipleInserts/before.java
rename to src/test/resources/ExampleLinksTest/multipleInserts/before.java
diff --git a/src/test/resources/SeeLinksTest/insertHref/after.java b/src/test/resources/ExampleLinksTest/noDuplicates/after.java
similarity index 95%
rename from src/test/resources/SeeLinksTest/insertHref/after.java
rename to src/test/resources/ExampleLinksTest/noDuplicates/after.java
index 75f3b52..ef26259 100644
--- a/src/test/resources/SeeLinksTest/insertHref/after.java
+++ b/src/test/resources/ExampleLinksTest/noDuplicates/after.java
@@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  * entity class.
  *
  * @since Java Persistence 1.0
- * @see <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
  */
 public interface Entity {
 
diff --git a/src/test/resources/SeeLinksTest/insertHref/before.java b/src/test/resources/ExampleLinksTest/noDuplicates/before.java
similarity index 100%
rename from src/test/resources/SeeLinksTest/insertHref/before.java
rename to src/test/resources/ExampleLinksTest/noDuplicates/before.java
diff --git a/src/test/resources/SeeLinksTest/noJavadoc/after.java b/src/test/resources/ExampleLinksTest/noJavadoc/after.java
similarity index 94%
rename from src/test/resources/SeeLinksTest/noJavadoc/after.java
rename to src/test/resources/ExampleLinksTest/noJavadoc/after.java
index da7abb7..9ed617c 100644
--- a/src/test/resources/SeeLinksTest/noJavadoc/after.java
+++ b/src/test/resources/ExampleLinksTest/noJavadoc/after.java
@@ -17,7 +17,7 @@
 package javax.persistence;
 
 /**
- * @see <a href="http://example.org/orange.html">Orange Example</a>
+ * @example <a href="http://example.org/orange.html">Orange Example</a>
  */
 public @interface Entity {
 
diff --git a/src/test/resources/SeeLinksTest/noJavadoc/before.java b/src/test/resources/ExampleLinksTest/noJavadoc/before.java
similarity index 100%
rename from src/test/resources/SeeLinksTest/noJavadoc/before.java
rename to src/test/resources/ExampleLinksTest/noJavadoc/before.java


[tomee-site-generator] 11/11: Enable linking for all Javadoc/APIs (Jakarta, MicroProfile, TomEE)

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 5094a05d37556055561d5c30b6d5e3b3b9b2910c
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 18:58:24 2020 -0700

    Enable linking for all Javadoc/APIs (Jakarta, MicroProfile, TomEE)
---
 src/main/java/org/apache/tomee/website/LearningLinks.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/org/apache/tomee/website/LearningLinks.java b/src/main/java/org/apache/tomee/website/LearningLinks.java
index aafff09..a125e80 100644
--- a/src/main/java/org/apache/tomee/website/LearningLinks.java
+++ b/src/main/java/org/apache/tomee/website/LearningLinks.java
@@ -78,7 +78,6 @@ public class LearningLinks {
      * @see Configuration for the full list of Sources that will be seen here
      */
     public void prepare(final Source source) {
-        if (!source.getName().contains("jakarta")) return;
         final Map<String, JavadocSource> sources = getJavadocSources(source.stream());
 
         final List<Example> examples = sort(this.examples.getExamples());


[tomee-site-generator] 07/11: Support multiple languages in @example javadoc tags

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 17d681ddaef73b953a32aa033d4a25055780d472
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 16:10:47 2020 -0700

    Support multiple languages in @example javadoc tags
---
 .../java/org/apache/tomee/website/Example.java     | 34 ++++++++++++++++-----
 .../org/apache/tomee/website/ExampleLinks.java     | 29 +++++++++++-------
 .../java/org/apache/tomee/website/Javadocs.java    |  6 +++-
 .../org/apache/tomee/website/LearningLinks.java    |  5 +++-
 .../org/apache/tomee/website/ExampleLinksTest.java | 35 +++++++++++++++++-----
 .../ExampleLinksTest/finalClass/after.java         |  2 +-
 .../ExampleLinksTest/hasAnnotations/after.java     |  2 +-
 .../ExampleLinksTest/insertHref/after.java         |  2 +-
 .../ExampleLinksTest/multipleInserts/after1.java   |  2 +-
 .../ExampleLinksTest/multipleInserts/after2.java   |  4 +--
 .../ExampleLinksTest/multipleInserts/after3.java   |  6 ++--
 .../after1.java                                    |  2 +-
 .../after2.java                                    |  4 +--
 .../after3.java                                    |  6 ++--
 .../after1.java => multipleLanguages/before.java}  |  3 --
 .../ExampleLinksTest/noDuplicates/after.java       |  2 +-
 .../ExampleLinksTest/noJavadoc/after.java          |  2 +-
 17 files changed, 99 insertions(+), 47 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/Example.java b/src/main/java/org/apache/tomee/website/Example.java
index 92560d6..b235728 100644
--- a/src/main/java/org/apache/tomee/website/Example.java
+++ b/src/main/java/org/apache/tomee/website/Example.java
@@ -56,14 +56,12 @@ public class Example {
     public void updateDestination(final File examplesDir) { //target/jbake/<tomeeBranch>
 
 
-
-
-        if (this.language.equalsIgnoreCase("")) {
+        if (this.language.equalsIgnoreCase("") || this.language.equalsIgnoreCase("en")) {
             File languageDir = new File(examplesDir + File.separator + "examples");
             if (!languageDir.exists()) {
                 languageDir.mkdirs();    //tomee8.0/examples
             }
-            this.setDestReadme(new File(examplesDir+File.separator+"examples", this.getName() + "." + this.getExt()));
+            this.setDestReadme(new File(examplesDir + File.separator + "examples", this.getName() + "." + this.getExt()));
         } else {
 
             File languageDir = new File(examplesDir + File.separator + getLanguage() + File.separator + "examples");
@@ -108,10 +106,22 @@ public class Example {
         final String exampleName = readme.getParentFile().getName();
         final String language = getLanguage(readme);
 
-        if (exampleName.equalsIgnoreCase("")) {
-            return new Example(readme, exampleName, ext, exampleName + ".html", "Example");
-        } else {
+        if (language.equalsIgnoreCase("") || language.equalsIgnoreCase("en")) {
+
+            return new Example(readme, exampleName, ext, exampleName + ".html", "Examples", "en");
+
+        } else if (language.equalsIgnoreCase("es")) {
+
             return new Example(readme, exampleName, ext, exampleName + ".html", "Ejemplos", language);
+
+        } else if (language.equalsIgnoreCase("pt")) {
+
+            return new Example(readme, exampleName, ext, exampleName + ".html", "Exemplos", language);
+
+        } else {
+
+            return new Example(readme, exampleName, ext, exampleName + ".html", "Examples", language);
+
         }
     }
 
@@ -128,4 +138,14 @@ public class Example {
     public static String getExtension(final File readme) {
         return readme.getName().replaceFirst("[^.]+\\.", "");
     }
+
+    @Override
+    public String toString() {
+        return "Example{" +
+                "name='" + name + '\'' +
+                ", language='" + language + '\'' +
+                ", category='" + category + '\'' +
+                ", destReadme=" + destReadme +
+                '}';
+    }
 }
diff --git a/src/main/java/org/apache/tomee/website/ExampleLinks.java b/src/main/java/org/apache/tomee/website/ExampleLinks.java
index 0044a7a..126b51a 100644
--- a/src/main/java/org/apache/tomee/website/ExampleLinks.java
+++ b/src/main/java/org/apache/tomee/website/ExampleLinks.java
@@ -23,6 +23,7 @@ import org.tomitribe.util.Join;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Stream;
 
 /**
  * Utility class to insert additional @example links into java source code.
@@ -33,16 +34,16 @@ import java.util.List;
  */
 public class ExampleLinks {
 
-    public static String insertHref(final String source, final String link, final String linkText) {
+    public static String insertHref(final String source, final String link, final String linkText, final String language) {
         final int start = Math.max(source.lastIndexOf("\nimport "), source.indexOf("\npackage "));
         final int end = min(min(source.indexOf("\npublic "), source.indexOf("\n@")), source.indexOf("\nfinal"));
 
         final String header = source.substring(start, end);
 
         if (header.contains("/**")) {
-            return updateComment(source, link, linkText, header);
+            return updateComment(source, link, linkText, language, header);
         } else {
-            return addComment(source, link, linkText, header);
+            return addComment(source, link, linkText, language, header);
         }
     }
 
@@ -55,17 +56,17 @@ public class ExampleLinks {
         return Math.min(a, b);
     }
 
-    private static String addComment(final String source, final String link, final String linkText, final String header) {
-        final String href = href(link, linkText);
+    private static String addComment(final String source, final String link, final String linkText, final String language, final String header) {
+        final String href = href(link, linkText, language);
         final String comment = header + "\n/**\n" + href + "\n */";
         return source.replace(header, comment);
     }
 
-    private static String updateComment(final String source, final String link, final String linkText, final String header) {
+    private static String updateComment(final String source, final String link, final String linkText, final String language, final String header) {
         /*
          * If we already have a link to this example, don't add it again
          */
-        if (header.contains(String.format(">%s</a>", linkText))) return source;
+        if (exists(linkText, language, header)) return source;
 
         final StreamLexer lexer = new StreamLexer(IO.read(header));
         final String comment;
@@ -75,7 +76,7 @@ public class ExampleLinks {
             throw new IllegalStateException(e);
         }
 
-        final String href = href(link, linkText);
+        final String href = href(link, linkText, language);
 
         final List<String> lines = new ArrayList<>(Arrays.asList(comment.split("\n")));
         lines.add(lines.size() - 1, href);
@@ -86,8 +87,16 @@ public class ExampleLinks {
         return source.replace(comment, updatedComment);
     }
 
-    private static String href(final String link, final String linkText) {
-        final String href = String.format(" * @example <a href=\"%s\">%s</a>", link, linkText);
+    private static boolean exists(final String linkText, final String language, final String header) {
+        final long count = Stream.of(header.split("\n"))
+                .filter(s -> s.contains("@example." + language))
+                .filter(s -> s.contains(">" + linkText + "<"))
+                .count();
+        return count > 0;
+    }
+
+    private static String href(final String link, final String linkText, final String language) {
+        final String href = String.format(" * @example.%s <a href=\"%s\">%s</a>", language, link, linkText);
         return href;
     }
 }
diff --git a/src/main/java/org/apache/tomee/website/Javadocs.java b/src/main/java/org/apache/tomee/website/Javadocs.java
index ae187d9..01226d8 100644
--- a/src/main/java/org/apache/tomee/website/Javadocs.java
+++ b/src/main/java/org/apache/tomee/website/Javadocs.java
@@ -93,7 +93,11 @@ public class Javadocs {
             final ProcessBuilder cmd = new ProcessBuilder(
                     getJavadocCommand().getAbsolutePath(),
                     "-tag",
-                    "example:a:Examples:",
+                    "example.en:a:Examples (en):",
+                    "-tag",
+                    "example.es:a:Examples (es):",
+                    "-tag",
+                    "example.pt:a:Examples (pt):",
                     "-sourcepath",
                     javaSources.getAbsolutePath(),
                     "-d",
diff --git a/src/main/java/org/apache/tomee/website/LearningLinks.java b/src/main/java/org/apache/tomee/website/LearningLinks.java
index aa0f488..aafff09 100644
--- a/src/main/java/org/apache/tomee/website/LearningLinks.java
+++ b/src/main/java/org/apache/tomee/website/LearningLinks.java
@@ -98,6 +98,9 @@ public class LearningLinks {
                 addSeeLink(sources.get(api), example);
             }
 
+            // Don't add any links if the source format is markdown
+            if (!example.getSrcReadme().getName().endsWith(".adoc")) continue;
+
             // Add APIs Used links to Example
             addApisUsed(example, apisUsed, sources, source);
 
@@ -211,7 +214,7 @@ public class LearningLinks {
 
 
             // Update the source contents to include an href link
-            final String modified = ExampleLinks.insertHref(content, link, name);
+            final String modified = ExampleLinks.insertHref(content, link, name, example.getLanguage());
 
             // Overwrite the source with the newly linked version
             IO.copy(IO.read(modified), javadocSource.getSourceFile());
diff --git a/src/test/java/org/apache/tomee/website/ExampleLinksTest.java b/src/test/java/org/apache/tomee/website/ExampleLinksTest.java
index 3b15094..5b53d1d 100644
--- a/src/test/java/org/apache/tomee/website/ExampleLinksTest.java
+++ b/src/test/java/org/apache/tomee/website/ExampleLinksTest.java
@@ -36,7 +36,7 @@ public class ExampleLinksTest {
 
         final String input = scenario.get("before.java");
 
-        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example", "en");
 
         assertEquals(scenario.get("after.java"), actual);
     }
@@ -50,7 +50,7 @@ public class ExampleLinksTest {
 
         final String input = scenario.get("before.java");
 
-        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example", "en");
 
         assertEquals(scenario.get("after.java"), actual);
     }
@@ -64,13 +64,32 @@ public class ExampleLinksTest {
 
         final String input = scenario.get("before.java");
 
-        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example", "en");
         assertEquals(scenario.get("after1.java"), after1);
 
-        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/red.html", "Red Sample");
+        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/red.html", "Red Sample", "en");
         assertEquals(scenario.get("after2.java"), after2);
 
-        final String after3 = ExampleLinks.insertHref(after2, "http://example.org/yellow.html", "yellow");
+        final String after3 = ExampleLinks.insertHref(after2, "http://example.org/yellow.html", "yellow", "en");
+        assertEquals(scenario.get("after3.java"), after3);
+    }
+
+    /**
+     * Test we can insert several @see links into the same javadoc
+     */
+    @Test
+    public void multipleLanguages() throws IOException {
+        final Scenario scenario = scenario(ExampleLinksTest.class, "multipleLanguages");
+
+        final String input = scenario.get("before.java");
+
+        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example", "en");
+        assertEquals(scenario.get("after1.java"), after1);
+
+        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/es/orange.html", "Orange Example", "es");
+        assertEquals(scenario.get("after2.java"), after2);
+
+        final String after3 = ExampleLinks.insertHref(after2, "http://example.org/pt/orange.html", "Orange Example", "pt");
         assertEquals(scenario.get("after3.java"), after3);
     }
 
@@ -83,11 +102,11 @@ public class ExampleLinksTest {
 
         final String input = scenario.get("before.java");
 
-        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String after1 = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example", "en");
         assertEquals(scenario.get("after.java"), after1);
 
         // The second insert should be ignored as it has the same title "Orange Example"
-        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/foo.html", "Orange Example");
+        final String after2 = ExampleLinks.insertHref(after1, "http://example.org/foo.html", "Orange Example", "en");
         assertEquals(scenario.get("after.java"), after2);
     }
 
@@ -100,7 +119,7 @@ public class ExampleLinksTest {
 
         final String input = scenario.get("before.java");
 
-        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        final String actual = ExampleLinks.insertHref(input, "http://example.org/orange.html", "Orange Example", "en");
         assertEquals(scenario.get("after.java"), actual);
     }
 
diff --git a/src/test/resources/ExampleLinksTest/finalClass/after.java b/src/test/resources/ExampleLinksTest/finalClass/after.java
index e91e524..de8c953 100644
--- a/src/test/resources/ExampleLinksTest/finalClass/after.java
+++ b/src/test/resources/ExampleLinksTest/finalClass/after.java
@@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  * entity class.
  *
  * @since Java Persistence 1.0
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 final public interface Entity {
 
diff --git a/src/test/resources/ExampleLinksTest/hasAnnotations/after.java b/src/test/resources/ExampleLinksTest/hasAnnotations/after.java
index ceefe62..e0e296d 100644
--- a/src/test/resources/ExampleLinksTest/hasAnnotations/after.java
+++ b/src/test/resources/ExampleLinksTest/hasAnnotations/after.java
@@ -23,7 +23,7 @@ import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 @Documented
 @Target(TYPE)
diff --git a/src/test/resources/ExampleLinksTest/insertHref/after.java b/src/test/resources/ExampleLinksTest/insertHref/after.java
index ef26259..7f9fa3b 100644
--- a/src/test/resources/ExampleLinksTest/insertHref/after.java
+++ b/src/test/resources/ExampleLinksTest/insertHref/after.java
@@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  * entity class.
  *
  * @since Java Persistence 1.0
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 public interface Entity {
 
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after1.java b/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
index 0aa811d..f5c8299 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
+++ b/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
@@ -17,7 +17,7 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after2.java b/src/test/resources/ExampleLinksTest/multipleInserts/after2.java
index 7471d5e..f28915a 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after2.java
+++ b/src/test/resources/ExampleLinksTest/multipleInserts/after2.java
@@ -17,8 +17,8 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
- * @example <a href="http://example.org/red.html">Red Sample</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/red.html">Red Sample</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after3.java b/src/test/resources/ExampleLinksTest/multipleInserts/after3.java
index 5eb5e0d..c332478 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after3.java
+++ b/src/test/resources/ExampleLinksTest/multipleInserts/after3.java
@@ -17,9 +17,9 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
- * @example <a href="http://example.org/red.html">Red Sample</a>
- * @example <a href="http://example.org/yellow.html">yellow</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/red.html">Red Sample</a>
+ * @example.en <a href="http://example.org/yellow.html">yellow</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after1.java b/src/test/resources/ExampleLinksTest/multipleLanguages/after1.java
similarity index 92%
copy from src/test/resources/ExampleLinksTest/multipleInserts/after1.java
copy to src/test/resources/ExampleLinksTest/multipleLanguages/after1.java
index 0aa811d..f5c8299 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
+++ b/src/test/resources/ExampleLinksTest/multipleLanguages/after1.java
@@ -17,7 +17,7 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after2.java b/src/test/resources/ExampleLinksTest/multipleLanguages/after2.java
similarity index 85%
copy from src/test/resources/ExampleLinksTest/multipleInserts/after2.java
copy to src/test/resources/ExampleLinksTest/multipleLanguages/after2.java
index 7471d5e..fec0104 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after2.java
+++ b/src/test/resources/ExampleLinksTest/multipleLanguages/after2.java
@@ -17,8 +17,8 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
- * @example <a href="http://example.org/red.html">Red Sample</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.es <a href="http://example.org/es/orange.html">Orange Example</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after3.java b/src/test/resources/ExampleLinksTest/multipleLanguages/after3.java
similarity index 79%
copy from src/test/resources/ExampleLinksTest/multipleInserts/after3.java
copy to src/test/resources/ExampleLinksTest/multipleLanguages/after3.java
index 5eb5e0d..5c6c19e 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after3.java
+++ b/src/test/resources/ExampleLinksTest/multipleLanguages/after3.java
@@ -17,9 +17,9 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
- * @example <a href="http://example.org/red.html">Red Sample</a>
- * @example <a href="http://example.org/yellow.html">yellow</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.es <a href="http://example.org/es/orange.html">Orange Example</a>
+ * @example.pt <a href="http://example.org/pt/orange.html">Orange Example</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/ExampleLinksTest/multipleInserts/after1.java b/src/test/resources/ExampleLinksTest/multipleLanguages/before.java
similarity index 91%
copy from src/test/resources/ExampleLinksTest/multipleInserts/after1.java
copy to src/test/resources/ExampleLinksTest/multipleLanguages/before.java
index 0aa811d..9321f32 100644
--- a/src/test/resources/ExampleLinksTest/multipleInserts/after1.java
+++ b/src/test/resources/ExampleLinksTest/multipleLanguages/before.java
@@ -16,9 +16,6 @@
  */
 package javax.persistence;
 
-/**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
- */
 public enum Shapes {
     CIRCLE,
     TRIANGLE,
diff --git a/src/test/resources/ExampleLinksTest/noDuplicates/after.java b/src/test/resources/ExampleLinksTest/noDuplicates/after.java
index ef26259..7f9fa3b 100644
--- a/src/test/resources/ExampleLinksTest/noDuplicates/after.java
+++ b/src/test/resources/ExampleLinksTest/noDuplicates/after.java
@@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
  * entity class.
  *
  * @since Java Persistence 1.0
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 public interface Entity {
 
diff --git a/src/test/resources/ExampleLinksTest/noJavadoc/after.java b/src/test/resources/ExampleLinksTest/noJavadoc/after.java
index 9ed617c..86498dd 100644
--- a/src/test/resources/ExampleLinksTest/noJavadoc/after.java
+++ b/src/test/resources/ExampleLinksTest/noJavadoc/after.java
@@ -17,7 +17,7 @@
 package javax.persistence;
 
 /**
- * @example <a href="http://example.org/orange.html">Orange Example</a>
+ * @example.en <a href="http://example.org/orange.html">Orange Example</a>
  */
 public @interface Entity {
 


[tomee-site-generator] 03/11: Merge branch 'master' of github.com:apache/tomee-site-generator

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit b9f71d62cd45360ed10ebb1e8715df9ab02fe0bd
Merge: b5405cf 166066d
Author: David Blevins <da...@gmail.com>
AuthorDate: Sat Aug 8 16:14:30 2020 -0700

    Merge branch 'master' of github.com:apache/tomee-site-generator

 src/main/jbake/content/download-archive.adoc | 27 ++++++++++++++++++
 src/main/jbake/content/download-ng.adoc      | 42 ++++++++++++++--------------
 2 files changed, 48 insertions(+), 21 deletions(-)


[tomee-site-generator] 09/11: Re-add previous versions

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 44a6c56275885793c33145529b97fb9d6df11dc6
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 18:56:37 2020 -0700

    Re-add previous versions
---
 src/main/java/org/apache/tomee/website/Configuration.java | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/Configuration.java b/src/main/java/org/apache/tomee/website/Configuration.java
index a182043..1b90fac 100644
--- a/src/main/java/org/apache/tomee/website/Configuration.java
+++ b/src/main/java/org/apache/tomee/website/Configuration.java
@@ -92,12 +92,12 @@ public class Configuration {
         return new Source[]{
 //                new Source("https://github.com/apache/tomee.git", "master", "tomee-8.0"),
                 new Source("https://github.com/apache/tomee.git", "master", "tomee-9.0").label("milestone").related(microProfile2).related(jakartaEE9).javadoc("^org.apache.(openejb|tomee).*"),
-//                new Source("https://github.com/apache/tomee.git", "master", "tomee-8.0", true).related(microProfile2).related(jakartaEE8).javadoc("^org.apache.(openejb|tomee).*"),
-//                new Source("https://github.com/apache/tomee.git", "tomee-7.1.0", "tomee-7.1").javadoc("^org.apache.(openejb|tomee).*"),
-//                new Source("https://github.com/apache/tomee.git", "tomee-7.0.5", "tomee-7.0").javadoc("^org.apache.(openejb|tomee).*"),
-//                new Source("https://github.com/apache/tomee.git", "master", "master").javadoc("^org.apache.(openejb|tomee).*"),
-//                new Source("https://github.com/eclipse/microprofile-bom.git", "master", "microprofile-2.0").related(microProfile2).javadoc("^org.eclipse.microprofile.*"),
-//                new Source("https://github.com/eclipse-ee4j/jakartaee-platform.git", "v8", "jakartaee-8.0").related(jakartaEE8).javadoc("^javax.*"),
+                new Source("https://github.com/apache/tomee.git", "master", "tomee-8.0", true).related(microProfile2).related(jakartaEE8).javadoc("^org.apache.(openejb|tomee).*"),
+                new Source("https://github.com/apache/tomee.git", "tomee-7.1.0", "tomee-7.1").javadoc("^org.apache.(openejb|tomee).*"),
+                new Source("https://github.com/apache/tomee.git", "tomee-7.0.5", "tomee-7.0").javadoc("^org.apache.(openejb|tomee).*"),
+                new Source("https://github.com/apache/tomee.git", "master", "master").javadoc("^org.apache.(openejb|tomee).*"),
+                new Source("https://github.com/eclipse/microprofile-bom.git", "master", "microprofile-2.0").related(microProfile2).javadoc("^org.eclipse.microprofile.*"),
+                new Source("https://github.com/eclipse-ee4j/jakartaee-platform.git", "v8", "jakartaee-8.0").related(jakartaEE8).javadoc("^javax.*"),
                 new Source("https://github.com/eclipse-ee4j/jakartaee-platform.git", "master", "jakartaee-9.0").related(jakartaEE9).javadoc("^jakarta.*")
         };
     }


[tomee-site-generator] 04/11: Ability to insert links into javadoc

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 28c0ed841b2d6082a6699401dd48cacc4f6dbead
Author: David Blevins <da...@gmail.com>
AuthorDate: Sat Aug 8 18:05:27 2020 -0700

    Ability to insert links into javadoc
---
 .../java/org/apache/tomee/website/SeeLinks.java    | 50 +++++++++++++++++++++-
 .../org/apache/tomee/website/SeeLinksTest.java     | 17 ++++++++
 .../SeeLinksTest/multipleInserts/after3.java       |  2 +-
 .../after3.java => noDuplicates/after.java}        | 25 ++++++++---
 .../after3.java => noDuplicates/before.java}       | 26 ++++++++---
 5 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/SeeLinks.java b/src/main/java/org/apache/tomee/website/SeeLinks.java
index a7231c8..9979361 100644
--- a/src/main/java/org/apache/tomee/website/SeeLinks.java
+++ b/src/main/java/org/apache/tomee/website/SeeLinks.java
@@ -16,6 +16,9 @@
  */
 package org.apache.tomee.website;
 
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * Utility class to insert additional @see links into java source code.
  * If no Javadoc exists at the class level, some will be added.
@@ -23,7 +26,52 @@ package org.apache.tomee.website;
 public class SeeLinks {
 
     public static String insertHref(final String source, final String link, final String linkText) {
+        final int start = Math.max(source.lastIndexOf("\nimport "), source.indexOf("\npackage "));
+        final int end = min(source.indexOf("\npublic "), source.indexOf("\n@"));
+
+        final String header = source.substring(start, end);
+
+        if (header.contains("/**")) {
+            return updateComment(source, link, linkText, header);
+        } else {
+            return addComment(source, link, linkText, header);
+        }
+    }
+
+    private static int min(final int a, final int b) {
+        if (a == -1) return b;
+        if (b == -1) return a;
+        return Math.min(a, b);
+    }
+
+    private static String addComment(final String source, final String link, final String linkText, final String header) {
+        final String href = href(link, linkText);
+        final String comment = header + "\n/**" + href + "\n */";
+        return source.replace(header, comment);
+    }
+
+    private static String updateComment(final String source, final String link, final String linkText, final String header) {
+        /*
+         * If we already have a link to this example, don't add it again
+         */
+        if (header.contains(String.format(">%s</a>", linkText))) return source;
+
+        final Pattern commentPattern = Pattern.compile("/\\*\\*(.*\n*)*?\n *\\*/");
+        final Matcher matcher = commentPattern.matcher(header);
+        if (!matcher.find()) return source;
+
+        final String comment = matcher.group(0);
+
+        final String href = href(link, linkText);
+
+        final String updatedComment = comment.replaceFirst("(\n *\\*/)", href + "$1");
+
         // TODO
-        return source;
+        return source.replace(comment, updatedComment);
+    }
+
+    private static String href(final String link, final String linkText) {
+        final String href = String.format("\n * @see <a href=\"%s\">%s</a>", link, linkText);
+        return href;
     }
 }
diff --git a/src/test/java/org/apache/tomee/website/SeeLinksTest.java b/src/test/java/org/apache/tomee/website/SeeLinksTest.java
index 64bc931..e740239 100644
--- a/src/test/java/org/apache/tomee/website/SeeLinksTest.java
+++ b/src/test/java/org/apache/tomee/website/SeeLinksTest.java
@@ -78,6 +78,23 @@ public class SeeLinksTest {
      * Test we can insert several @see links into the same javadoc
      */
     @Test
+    public void noDuplicates() throws IOException {
+        final Scenario scenario = scenario(SeeLinksTest.class, "noDuplicates");
+
+        final String input = scenario.get("before.java");
+
+        final String after1 = SeeLinks.insertHref(input, "http://example.org/orange.html", "Orange Example");
+        assertEquals(scenario.get("after.java"), after1);
+
+        // The second insert should be ignored as it has the same title "Orange Example"
+        final String after2 = SeeLinks.insertHref(after1, "http://example.org/foo.html", "Orange Example");
+        assertEquals(scenario.get("after.java"), after2);
+    }
+
+    /**
+     * Test we can insert several @see links into the same javadoc
+     */
+    @Test
     public void hasAnnotations() throws IOException {
         final Scenario scenario = scenario(SeeLinksTest.class, "hasAnnotations");
 
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/after3.java b/src/test/resources/SeeLinksTest/multipleInserts/after3.java
index 932c0cc..a7f36e1 100644
--- a/src/test/resources/SeeLinksTest/multipleInserts/after3.java
+++ b/src/test/resources/SeeLinksTest/multipleInserts/after3.java
@@ -19,7 +19,7 @@ package javax.persistence;
 /**
  * @see <a href="http://example.org/orange.html">Orange Example</a>
  * @see <a href="http://example.org/red.html">Red Sample</a>
- * @see <a href="http://example.org/red.html">yellow</a>
+ * @see <a href="http://example.org/yellow.html">yellow</a>
  */
 public enum Shapes {
     CIRCLE,
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/after3.java b/src/test/resources/SeeLinksTest/noDuplicates/after.java
similarity index 56%
copy from src/test/resources/SeeLinksTest/multipleInserts/after3.java
copy to src/test/resources/SeeLinksTest/noDuplicates/after.java
index 932c0cc..75f3b52 100644
--- a/src/test/resources/SeeLinksTest/multipleInserts/after3.java
+++ b/src/test/resources/SeeLinksTest/noDuplicates/after.java
@@ -16,13 +16,26 @@
  */
 package javax.persistence;
 
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Documented;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
+ * Specifies that the class is an entity. This annotation is applied to the
+ * entity class.
+ *
+ * @since Java Persistence 1.0
  * @see <a href="http://example.org/orange.html">Orange Example</a>
- * @see <a href="http://example.org/red.html">Red Sample</a>
- * @see <a href="http://example.org/red.html">yellow</a>
  */
-public enum Shapes {
-    CIRCLE,
-    TRIANGLE,
-    SQUARE
+public interface Entity {
+
+        /**
+         * (Optional) The entity name. Defaults to the unqualified
+         * name of the entity class. This name is used to refer to the
+         * entity in queries. The name must not be a reserved literal
+         * in the Java Persistence query language.
+         */
+        String name();
 }
\ No newline at end of file
diff --git a/src/test/resources/SeeLinksTest/multipleInserts/after3.java b/src/test/resources/SeeLinksTest/noDuplicates/before.java
similarity index 54%
copy from src/test/resources/SeeLinksTest/multipleInserts/after3.java
copy to src/test/resources/SeeLinksTest/noDuplicates/before.java
index 932c0cc..5ffc69c 100644
--- a/src/test/resources/SeeLinksTest/multipleInserts/after3.java
+++ b/src/test/resources/SeeLinksTest/noDuplicates/before.java
@@ -16,13 +16,25 @@
  */
 package javax.persistence;
 
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Documented;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
- * @see <a href="http://example.org/orange.html">Orange Example</a>
- * @see <a href="http://example.org/red.html">Red Sample</a>
- * @see <a href="http://example.org/red.html">yellow</a>
+ * Specifies that the class is an entity. This annotation is applied to the
+ * entity class.
+ *
+ * @since Java Persistence 1.0
  */
-public enum Shapes {
-    CIRCLE,
-    TRIANGLE,
-    SQUARE
+public interface Entity {
+
+        /**
+         * (Optional) The entity name. Defaults to the unqualified
+         * name of the entity class. This name is used to refer to the
+         * entity in queries. The name must not be a reserved literal
+         * in the Java Persistence query language.
+         */
+        String name();
 }
\ No newline at end of file


[tomee-site-generator] 02/11: Checks for the Asciidoc content

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit b5405cfea9d2c65cc5673e129bbb28ed540f10c3
Author: David Blevins <da...@gmail.com>
AuthorDate: Sat Aug 8 16:14:11 2020 -0700

    Checks for the Asciidoc content
---
 .../tomee/website/AddAsciidocCodeblocks.java       | 20 +++++++++-
 .../tomee/website/audit/JbakeHeaderHasNoSpace.java | 46 ++++++++++++++++++++++
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/AddAsciidocCodeblocks.java b/src/main/java/org/apache/tomee/website/AddAsciidocCodeblocks.java
index bb5fa3c..6856dc2 100644
--- a/src/main/java/org/apache/tomee/website/AddAsciidocCodeblocks.java
+++ b/src/main/java/org/apache/tomee/website/AddAsciidocCodeblocks.java
@@ -21,6 +21,7 @@ import org.apache.openejb.util.Join;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -35,16 +36,31 @@ public class AddAsciidocCodeblocks {
 
     public static void main(String[] args) throws Exception {
 
-        final File docs = new File("repos/tomee-8.0/docs/");
+        final File docs = new File("repos/master/examples/");
 
         Files.walk(docs.toPath())
                 .map(Path::toFile)
                 .filter(File::isFile)
                 .filter(path -> path.getName().endsWith(".adoc"))
-                .forEach(AddAsciidocCodeblocks::process);
+                .peek(AddAsciidocCodeblocks::process)
+                .forEach(AddAsciidocCodeblocks::fixLanguage);
+        ;
 
     }
 
+    private static void fixLanguage(final File file) {
+        try {
+            String contents = IO.slurp(file);
+
+            contents = contents.replace("[source,java]\n----\n<", "[source,xml]\n----\n<");
+            contents = contents.replace("[source,java]\n----\n----", "[source,console]\n----\n----");
+
+            IO.copy(IO.read(contents), file);
+        } catch (IOException e) {
+            throw new UncheckedIOException("Failed to process file: " + file.getAbsolutePath(), e);
+        }
+    }
+
     public static void process(final File destReadme) {
         final AddAsciidocCodeblocks fix = new AddAsciidocCodeblocks();
 
diff --git a/src/main/java/org/apache/tomee/website/audit/JbakeHeaderHasNoSpace.java b/src/main/java/org/apache/tomee/website/audit/JbakeHeaderHasNoSpace.java
new file mode 100644
index 0000000..61a00be
--- /dev/null
+++ b/src/main/java/org/apache/tomee/website/audit/JbakeHeaderHasNoSpace.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tomee.website.audit;
+
+import org.apache.openejb.loader.IO;
+import org.tomitribe.tio.Dir;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * The Jbake header in asciidoc form cannot have a space
+ * after the title.
+ */
+public class JbakeHeaderHasNoSpace {
+
+    public static void main(String[] args) throws IOException {
+        final Dir dir = Dir.from(new File("/Users/dblevins/work/apache/tomee-site-generator/repos/master"));
+        final List<File> files = dir.searchFiles()
+                .filter(file -> file.getName().endsWith(".adoc"))
+                .collect(Collectors.toList());
+        for (final File file : files) {
+            final String contents = IO.slurp(file);
+            final String[] lines = contents.split("\n");
+            if ("".equals(lines[1])) {
+                System.out.println(file.getAbsolutePath());
+            }
+        }
+    }
+}


[tomee-site-generator] 08/11: Use colored top bar Remove transitions Bold section titles

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit 4a5b45abb09b438da7767db120a19c020ad5e694
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Aug 9 18:55:52 2020 -0700

    Use colored top bar
    Remove transitions
    Bold section titles
---
 src/main/jbake/assets/css/cardio.css | 103 +++++++++++++++++------------------
 1 file changed, 50 insertions(+), 53 deletions(-)

diff --git a/src/main/jbake/assets/css/cardio.css b/src/main/jbake/assets/css/cardio.css
index b354ba1..366b5cf 100755
--- a/src/main/jbake/assets/css/cardio.css
+++ b/src/main/jbake/assets/css/cardio.css
@@ -102,12 +102,6 @@ header .typed-cursor {
   display: inline-block;
   margin: 0 10px;
   color: #80287a;
-  -webkit-animation-name: flash;
-  animation-name: flash;
-  -webkit-animation-duration: 1s;
-  animation-duration: 1s;
-  -webkit-animation-iteration-count: infinite;
-  animation-iteration-count: infinite;
 }
 
 ul, ol {
@@ -144,7 +138,7 @@ h1, .h1, h2, .h2, h3, .h3, h4, .h4 {
 }
 
 h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
-  font-weight: 300;
+  font-weight: 500;
 }
 
 h5, .h5, h6, .h6 {
@@ -176,33 +170,65 @@ li {
 /*}*/
 /* Navigation Bar ( Navbar ) */
 
-nav.navbar {
-  position: absolute;
-  z-index: 9500;
-  width: 100%;
-  width: 100vw;
-  -webkit-transition: all 0.3s ease;
-  transition: all 0.3s ease;
-}
+/*nav.navbar {*/
+/*  position: absolute;*/
+/*  z-index: 9500;*/
+/*  width: 100%;*/
+/*  width: 100vw;*/
+/*  -webkit-transition: all 0.3s ease;*/
+/*  transition: all 0.3s ease;*/
+/*}*/
 
 nav.navbar .navbar-nav li.active a:not(.btn) {
   color: #80287a !important;
 }
 
 nav.navbar-fixed-top {
+  background-image: linear-gradient(90deg,#f59423,#e2632a,#ca2136,#832778);
   z-index: 9499;
   top: 0;
   padding-top: 10px;
   padding-bottom: 10px;
   opacity: 1;
-  background: white;
-  box-shadow: 0 4px 3px rgba(0, 0, 0, 0.05);
 }
 
-nav.navbar-fixed-top .navbar-nav > li > a:not(.btn) {
-  color: #bbb;
+.navbar .button, .nav > li:last-child {
+    display: inline-flex;
+    align-items: center;
+    background: #fff;
+    border: 1px solid #e1e1e1;
+    border-radius: 0.25rem;
+    height: 31px;
+    padding: 0 6px;
+    margin-top: 6px;
+    margin-left: 15px;
 }
 
+nav.navbar-fixed-top .navbar-nav > li > a:not(.btn) {
+    color: #ffffff;
+    font-family: Roboto,sans-serif;
+    font-size: 16px;
+    font-weight: 400;
+    -webkit-font-smoothing: auto;
+}
+
+nav.navbar-fixed-top .navbar-nav > li:last-child > a:not(.btn) {
+    display: inline-flex;
+    color: #222;
+    padding: 6px;
+    white-space: nowrap;
+    cursor: pointer;
+}
+.navbar-brand {
+    float: left;
+    height: 100%;
+    padding: 0px 15px;
+    font-size: 22px;
+    line-height: 20px;
+    color: #fff;
+    font-family: Roboto,sans-serif;
+    -webkit-font-smoothing: auto;
+}
 .icon-bar {
   background: #bbb;
 }
@@ -217,8 +243,8 @@ nav.navbar-fixed-top .navbar-nav > li > a:not(.btn) {
   border: 2px solid transparent;
   border-radius: 2px;
   background: transparent;
-  -webkit-transition: all 0.3s ease;
-  transition: all 0.3s ease;
+  /*-webkit-transition: all 0.3s ease;*/
+  /*transition: all 0.3s ease;*/
 }
 
 .btn:hover,
@@ -282,7 +308,7 @@ nav.navbar-fixed-top .navbar-nav > li > a:not(.btn) {
 
 .navbar {
   top: 50px;
-  height: 70px;
+  height: 63px;
 }
 
 .container {
@@ -464,8 +490,8 @@ section h5 {
   height: 50px;
   border-radius: 50%;
   background: #80287a;
-  -webkit-animation: ripple-animation 2s;
-  animation: ripple-animation 2s;
+  /*-webkit-animation: ripple-animation 2s;*/
+  /*animation: ripple-animation 2s;*/
 }
 
 @-webkit-keyframes ripple-animation {
@@ -712,35 +738,6 @@ footer .trial-button {
   margin: 40px 0;
 }
 
-footer .open-blink {
-  content: ' ';
-  position: relative;
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  margin: 0 20px;
-  border-radius: 50%;
-  background-color: #4caf50;
-  -webkit-animation-name: flash;
-  animation-name: flash;
-  -webkit-animation-duration: 1s;
-  animation-duration: 1s;
-  -webkit-animation-iteration-count: infinite;
-  animation-iteration-count: infinite;
-}
-
-footer .open-blink:before {
-  content: ' ';
-  position: absolute;
-  top: -8px;
-  left: -8px;
-  display: inline-block;
-  width: 30px;
-  height: 30px;
-  opacity: 0.1;
-  border-radius: 50%;
-  background-color: #4caf50;
-}
 
 footer .social-footer {
   padding: 0;


[tomee-site-generator] 01/11: Reformat code

Posted by db...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-site-generator.git

commit ddab6430f7cd3fd726628022bedc2355e64a18c7
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun Jul 5 13:10:48 2020 -0700

    Reformat code
---
 .../org/apache/tomee/website/GroupedIndex.java     | 68 ++++++++++++----------
 1 file changed, 38 insertions(+), 30 deletions(-)

diff --git a/src/main/java/org/apache/tomee/website/GroupedIndex.java b/src/main/java/org/apache/tomee/website/GroupedIndex.java
index ab309a7..45bdab6 100644
--- a/src/main/java/org/apache/tomee/website/GroupedIndex.java
+++ b/src/main/java/org/apache/tomee/website/GroupedIndex.java
@@ -27,7 +27,15 @@ import java.io.IOException;
 import java.io.PrintStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 public class GroupedIndex {
@@ -67,22 +75,22 @@ public class GroupedIndex {
         final Map<String, List<Doc>> sections = new HashMap<>();
 
         //filtering only documents with the same language for: target/jbake/<tomeeBranch>/docs
-        if(this.type.equalsIgnoreCase("docsindex")){
+        if (this.type.equalsIgnoreCase("docsindex")) {
 
             for (Doc doc1 : docs) {
                 if (doc1.language.equalsIgnoreCase(language)) {
                     sections.computeIfAbsent(doc1.getGroup(), k -> new ArrayList<>()).add(doc1);
                 }
             }
-        }else{
+        } else {
 
-            if(this.type.equalsIgnoreCase("examplesindex")){
+            if (this.type.equalsIgnoreCase("examplesindex")) {
                 for (Doc doc1 : docs) { //filtering only documents with the same language for: target/jbake/<tomeeBranch> and type = examplesindex
                     if (doc1.language.equalsIgnoreCase(language) && doc1.source.getParentFile().getName().equalsIgnoreCase("examples")) {
                         sections.computeIfAbsent(doc1.getGroup(), k -> new ArrayList<>()).add(doc1);
                     }
                 }
-            }else{//any type (used in GroupedIndexTest.java
+            } else {//any type (used in GroupedIndexTest.java
                 for (Doc doc1 : docs) {
                     if (doc1.language.equalsIgnoreCase(language)) {
                         sections.computeIfAbsent(doc1.getGroup(), k -> new ArrayList<>()).add(doc1);
@@ -156,9 +164,9 @@ public class GroupedIndex {
                         out.printf("        </div>\n");
 
                         final ListIterator<Doc> iterator = entry.getValue().stream()
-                                                                .sorted()
-                                                                .collect(Collectors.toList())
-                                                                .listIterator();
+                                .sorted()
+                                .collect(Collectors.toList())
+                                .listIterator();
 
                         final int i = (int) Math.ceil(entry.getValue().size() / 3f);
 
@@ -190,17 +198,17 @@ public class GroupedIndex {
         try {
             File fileParentFolder = null;
 
-            if(type.equalsIgnoreCase("docsindex")){
+            if (type.equalsIgnoreCase("docsindex")) {
                 fileParentFolder = new File(directory);
-            }else {
-                if(type.equalsIgnoreCase("examplesindex")){
-                    if(language.equalsIgnoreCase("en")){
-                        fileParentFolder = new File(directory +  File.separator + "examples");
-                    }else{
-                         fileParentFolder = new File(directory +  File.separator + language + File.separator + "examples");
+            } else {
+                if (type.equalsIgnoreCase("examplesindex")) {
+                    if (language.equalsIgnoreCase("en")) {
+                        fileParentFolder = new File(directory + File.separator + "examples");
+                    } else {
+                        fileParentFolder = new File(directory + File.separator + language + File.separator + "examples");
 
                     }
-                }else{
+                } else {
                     fileParentFolder = new File(directory);
                 }
             }
@@ -214,24 +222,24 @@ public class GroupedIndex {
     public List<Doc> list(final File directory) {//target/jbake/<tomeeBranch>
         try {
             return Files.walk(directory.toPath())
-                        .map(Path::toFile)
-                        .filter(File::isFile)
-                        .filter(Docs::isRendered)
-                        .map(this::parse)
-                        .collect(Collectors.toList());
+                    .map(Path::toFile)
+                    .filter(File::isFile)
+                    .filter(Docs::isRendered)
+                    .map(this::parse)
+                    .collect(Collectors.toList());
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 
     private static String getLanguageFromPath(File file, String type) { //target/jbake/<tomeeBranch>/fr/examples/index.html
-        if(type.equalsIgnoreCase("docsindex")){ //ToDo: this needs to be updated when we are going to proccess docs internationalization too.
+        if (type.equalsIgnoreCase("docsindex")) { //ToDo: this needs to be updated when we are going to proccess docs internationalization too.
             return "";
-        }else { //examplesindex
+        } else { //examplesindex
 
-            if(file.getParentFile().getParentFile().getName().length() > 3){  // target/jbake/<tomeeBranchLengthIsGratherThan3>/examples/index.html
+            if (file.getParentFile().getParentFile().getName().length() > 3) {  // target/jbake/<tomeeBranchLengthIsGratherThan3>/examples/index.html
                 return "en";
-            }else{
+            } else {
                 return file.getParentFile().getParentFile().getName();  // target/jbake/<tomeeBranch>/fr/examples/index.html
             }
 
@@ -260,12 +268,12 @@ public class GroupedIndex {
 
          */
         if (type.equalsIgnoreCase("examplesindex") && file.getParentFile().getName().equalsIgnoreCase("examples")) {
-            String detectedLanguage = getLanguageFromPath(file,this.type);
+            String detectedLanguage = getLanguageFromPath(file, this.type);
 
-            if(detectedLanguage.equalsIgnoreCase("en")){
-                return new Doc(group, title, Docs.href(new File (directory + File.separator + "examples"), file), file, detectedLanguage);
-            }else{
-                return new Doc(group, title, Docs.href(new File (directory + File.separator + detectedLanguage + File.separator + "examples"), file), file, detectedLanguage);
+            if (detectedLanguage.equalsIgnoreCase("en")) {
+                return new Doc(group, title, Docs.href(new File(directory + File.separator + "examples"), file), file, detectedLanguage);
+            } else {
+                return new Doc(group, title, Docs.href(new File(directory + File.separator + detectedLanguage + File.separator + "examples"), file), file, detectedLanguage);
             }
 
         } else {