You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2026/06/10 14:18:37 UTC
(juneau) branch master updated: test: suppress Eclipse/SonarLint warnings on migrated TODO-160 tail tests
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 685d0b571f test: suppress Eclipse/SonarLint warnings on migrated TODO-160 tail tests
685d0b571f is described below
commit 685d0b571f561f2dbd9d422838708e1020188abf
Author: James Bognar <ja...@apache.org>
AuthorDate: Wed Jun 10 10:18:24 2026 -0400
test: suppress Eclipse/SonarLint warnings on migrated TODO-160 tail tests
---
README.md | 11 +-
.../juneau/commons/function/Function2_Test.java | 1 -
.../juneau/commons/function/Function3_Test.java | 1 -
.../juneau/commons/function/Function4_Test.java | 1 -
.../juneau/commons/function/Function5_Test.java | 1 -
.../juneau/commons/utils/AssertionUtils_Test.java | 1 -
.../juneau/commons/utils/CollectionUtils_Test.java | 1 -
.../juneau/commons/utils/FileUtils_Test.java | 1 -
.../commons/utils/ResourceBundleUtils_Test.java | 2 +-
.../test/java/org/apache/juneau/BeanMap_Test.java | 3 +-
.../EncoderSet_OverridingBeanStore_Test.java | 3 +
.../org/apache/juneau/utils/ParserReaderTest.java | 3 +
juneau-distrib/pom.xml | 17 +-
.../juneau-examples-rest-jetty-ftest/.gitignore | 7 -
.../logs/.gitignore | 1 -
.../src/main/java/empty.txt | 0
.../juneau/examples/rest/ContentComboTestBase.java | 116 --------
.../apache/juneau/examples/rest/RestTestcase.java | 40 ---
.../juneau/examples/rest/RootContentTest.java | 124 ---------
.../juneau/examples/rest/RootResourcesTest.java | 120 --------
.../juneau/examples/rest/SamplesMicroservice.java | 134 ---------
.../org/apache/juneau/examples/rest/TestUtils.java | 250 -----------------
.../apache/juneau/examples/rest/_TestSuite.java | 49 ----
.../juneau-examples-rest-jetty/.gitignore | 7 -
.../build-overlay/pom.xml | 167 -----------
.../juneau-examples-rest-jetty.cfg | 209 --------------
.../juneau-examples-rest-jetty.launch | 17 --
.../juneau-examples-rest-jetty/logs/.gitignore | 1 -
.../juneau-examples-rest-jetty/logs/empty.txt | 0
.../src/assembly/bin.xml | 62 -----
.../juneau-examples-rest-springboot/.gitignore | 7 -
.../build-overlay/Procfile | 1 -
.../build-overlay/app.json | 4 -
.../build-overlay/pom.xml | 157 -----------
.../juneau-examples-rest-springboot.launch | 22 --
.../juneau-examples-rest-springboot/settings.xml | 50 ----
.../juneau/examples/rest/springboot/App.java | 92 ------
.../examples/rest/springboot/RootResources.java | 84 ------
.../src/main/resources/juneau.cfg | 70 -----
juneau-examples/juneau-examples-rest/.gitignore | 6 -
juneau-examples/juneau-examples-rest/pom.xml | 118 --------
.../src/main/java/META-INF/MANIFEST.MF | 3 -
.../apache/juneau/examples/rest/AdminGuard.java | 32 ---
.../juneau/examples/rest/HelloWorldResource.java | 52 ----
.../juneau/examples/rest/HtmlBeansResource.java | 145 ----------
.../juneau/examples/rest/PhotosResource.java | 172 ------------
.../juneau/examples/rest/RequestEchoResource.java | 89 ------
.../juneau/examples/rest/SseDemoResource.java | 131 ---------
.../juneau/examples/rest/UtilityBeansResource.java | 155 -----------
.../juneau/examples/rest/command/EchoCommand.java | 45 ---
.../juneau/examples/rest/dto/AtomFeedResource.java | 142 ----------
.../juneau/examples/rest/dto/DtoExamples.java | 67 -----
.../examples/rest/dto/JsonSchemaResource.java | 118 --------
.../examples/rest/AtomFeedResource_example.json | 86 ------
.../examples/rest/JsonSchemaResource_example.json | 35 ---
.../org/apache/juneau/examples/rest/htdocs/ok.png | Bin 455 -> 0 bytes
.../apache/juneau/examples/rest/htdocs/severe.png | Bin 335 -> 0 bytes
.../apache/juneau/examples/rest/htdocs/warning.png | Bin 444 -> 0 bytes
.../petstore/rest/AddOrderMenuItem_beforeShow.js | 32 ---
.../rest/petstore/rest/PetStoreResource.json | 75 -----
.../rest/petstore/rest/htdocs/background.jpg | Bin 105889 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/bird.png | Bin 1925 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/cat.png | Bin 1878 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/dog.png | Bin 1980 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/fish.png | Bin 2198 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/mouse.png | Bin 1551 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/rabbit.png | Bin 1603 -> 0 bytes
.../examples/rest/petstore/rest/htdocs/snake.png | Bin 1824 -> 0 bytes
.../examples/rest/petstore/rest/photos/cat.jpg | Bin 105889 -> 0 bytes
juneau-examples/pom.xml | 4 -
.../juneau-petstore-core}/pom.xml | 85 ++++--
.../petstore/auth/StubBearerTokenValidator.java | 75 +++++
.../apache/juneau/petstore/auth}/package-info.java | 11 +-
.../java/org/apache/juneau/petstore/dto/Order.java | 115 ++++++++
.../apache/juneau/petstore/dto/OrderStatus.java | 21 +-
.../java/org/apache/juneau/petstore/dto/Pet.java | 180 ++++++++++++
.../org/apache/juneau/petstore/dto/PetStatus.java | 21 +-
.../org/apache/juneau/petstore/dto/Species.java | 33 ++-
.../java/org/apache/juneau/petstore/dto/User.java | 181 ++++++++++++
.../org/apache/juneau/petstore/dto/UserStatus.java | 18 +-
.../apache/juneau/petstore/dto}/package-info.java | 9 +-
.../org/apache/juneau/petstore/package-info.java | 34 +--
.../petstore/rest/PetFreemarkerViewResource.java | 82 ++++++
.../petstore/rest/PetMustacheViewResource.java | 91 ++++++
.../juneau/petstore/rest/PetSecureResource.java | 135 +++++++++
.../juneau/petstore/rest/PetStoreResource.java | 292 +++++++++++++++++++
.../juneau/petstore/rest/PetstoreUiResource.java | 51 ++++
.../apache/juneau/petstore/rest}/package-info.java | 8 +-
.../apache/juneau/petstore/service/PetStore.java | 308 +++++++++++++++++++++
.../service/PetstoreNotFoundException.java | 22 +-
.../juneau/petstore/service}/package-info.java | 9 +-
.../src/main/resources/htdocs/petstore-ui.html | 104 +++++++
.../src/main/resources/petstore-templates/pet.ftlh | 36 +--
.../main/resources/petstore-templates/pet.mustache | 37 ++-
.../src/main/resources}/petstore/init/Orders.json | 0
.../src/main/resources}/petstore/init/Pets.json | 0
.../src/main/resources}/petstore/init/Users.json | 0
.../rest/PetFreemarkerViewResource_Test.java | 48 ++++
.../rest/PetMustacheViewResource_Test.java | 48 ++++
.../petstore/rest/PetStoreResource_Test.java | 143 ++++++++++
.../petstore/rest/PetstoreUiResource_Test.java | 48 ++++
.../juneau/petstore/service/PetStore_Test.java | 150 ++++++++++
.../juneau-petstore-jetty.cfg | 266 ++++++++----------
.../juneau-petstore-jetty}/pom.xml | 87 ++++--
.../juneau-petstore-jetty}/src/assembly/bin.xml | 28 +-
.../org/apache/juneau/petstore}/jetty/App.java | 21 +-
.../juneau/petstore/jetty}/RootResources.java | 51 ++--
.../juneau/petstore}/jetty/package-info.java | 11 +-
.../src/main/resources/jetty.xml | 56 ++--
.../microservice/MicroserviceTestFixture.java | 199 +++++++++++++
.../juneau/petstore/jetty/PetstoreJetty_Test.java | 245 ++++++++++++++++
.../testing/annotations/JettyMicroserviceTest.java | 19 +-
.../juneau-petstore-springboot}/pom.xml | 82 +++---
.../org/apache/juneau/petstore/springboot/App.java | 98 +++++++
.../petstore/springboot/HelloMessageProvider.java | 17 +-
.../juneau/petstore/springboot/HelloResource.java | 40 ++-
.../juneau/petstore/springboot/RootResources.java | 88 ++++++
.../juneau/petstore/springboot}/package-info.java | 12 +-
.../src/main/resources/application.properties | 0
.../springboot/PetstoreSpringboot_Test.java | 241 ++++++++++++++++
.../juneau/testing/annotations/SpringbootTest.java | 19 +-
{juneau-examples => juneau-petstore}/pom.xml | 19 +-
juneau-release.sh | 9 +-
.../apache/juneau/mstat/MethodExecStore_Test.java | 3 +
.../org/apache/juneau/mstat/ThrownStore_Test.java | 4 +-
.../org/apache/juneau/utils/MethodInvokerTest.java | 3 +
.../juneau-sc-server/juneau-server-config.cfg | 2 +-
juneau-sc/juneau-sc-server/pom.xml | 2 +-
pom.xml | 1 +
scripts/apply-eclipse-prefs.py | 155 +++++++----
.../source-prefs/org.eclipse.jdt.core.prefs | 117 ++++++++
.../source-prefs/org.eclipse.jdt.ui.prefs | 5 +
.../test-prefs/org.eclipse.jdt.core.prefs | 117 ++++++++
.../test-prefs/org.eclipse.jdt.ui.prefs | 5 +
scripts/release.py | 6 +-
...mples-rest-jetty.py => start-petstore-jetty.py} | 65 ++---
...-springboot.py => start-petstore-springboot.py} | 61 ++--
137 files changed, 3947 insertions(+), 3946 deletions(-)
diff --git a/README.md b/README.md
index ba37f8c725..cd838f5131 100644
--- a/README.md
+++ b/README.md
@@ -38,9 +38,7 @@
* **[Framework Comparisons](https://juneau.apache.org/docs/topics/FrameworkComparisons)** - Compare Juneau with Jackson, Spring Boot, and JAX-RS
* **[Examples](https://juneau.apache.org/docs/topics/JuneauExamplesCore)** - Code examples and tutorials
* [juneau-examples-core](https://juneau.apache.org/docs/topics/JuneauExamplesCore) - Core serialization examples
- * [juneau-examples-rest](https://juneau.apache.org/docs/topics/JuneauExamplesRest) - REST API examples
- * [juneau-examples-rest-jetty](https://juneau.apache.org/docs/topics/JuneauExamplesRestJetty) - Jetty microservice examples
- * [juneau-examples-rest-springboot](https://juneau.apache.org/docs/topics/JuneauExamplesRestSpringboot) - Spring Boot examples
+ * [juneau-petstore](https://juneau.apache.org/docs/topics/JuneauPetstoreOverview) - Canonical petstore showcase application (deployed under both Jetty/Microservice and Spring Boot)
* **[Test Reports](https://juneau.apache.org/site/surefire.html)** - JUnit test execution results
* **[Dependencies](https://juneau.apache.org/site/dependency-info.html)** - Project dependency analysis
* **[Project Reports](https://juneau.apache.org/site/project-reports.html)** - Complete Maven site reports
@@ -288,10 +286,9 @@ Apache Juneau™ is a single cohesive Java ecosystem consisting of the following
* **juneau-microservice** - Microservice API.
* **juneau-microservice-jetty** - Jetty microservice API.
* **juneau-examples-core** - Core code examples.
-* **juneau-examples-rest** - REST code examples.
-* **juneau-examples-rest-jetty** - Jetty microservice examples.
-* **juneau-examples-rest-springboot** - Spring Boot examples.
-* **juneau-petstore** - Complete REST application example.
+* **juneau-petstore-core** - Shared petstore domain + REST resources.
+* **juneau-petstore-jetty** - Jetty/Microservice deployment of the petstore.
+* **juneau-petstore-springboot** - Spring Boot deployment of the petstore.
* **juneau-shaded** - Shaded (uber) JARs combining multiple Juneau modules for simplified dependency management, especially useful for Bazel builds.
Questions via email to dev@juneau.apache.org are always welcome.
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function2_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function2_Test.java
index 5a7a03f4e5..433a644134 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function2_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function2_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.function;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.function.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function3_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function3_Test.java
index a1a2961807..bfa2f8e04b 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function3_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function3_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.function;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.function.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function4_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function4_Test.java
index 238dabfe9e..bf59f23be7 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function4_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function4_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.function;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.function.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function5_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function5_Test.java
index c5a2e65d43..d5ccf200d9 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function5_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/function/Function5_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.function;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.function.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
index 89c975526d..7cc535d3c5 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.utils;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.apache.juneau.commons.utils.AssertionUtils.*;
import static org.apache.juneau.commons.utils.CollectionUtils.*;
import static org.junit.jupiter.api.Assertions.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
index a020b758e4..fae658e761 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.utils;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.apache.juneau.commons.utils.CollectionUtils.*;
import static org.apache.juneau.commons.TestAssertions.*;
import static org.junit.jupiter.api.Assertions.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/FileUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/FileUtils_Test.java
index 84120a9429..bb96e5996c 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/FileUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/FileUtils_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.utils;
-import static org.apache.juneau.commons.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import java.io.*;
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ResourceBundleUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ResourceBundleUtils_Test.java
index 1061e91589..f643ca388b 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ResourceBundleUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ResourceBundleUtils_Test.java
@@ -224,7 +224,7 @@ class ResourceBundleUtils_Test extends TestBase {
assertNotNull(direct);
assertNotNull(utils);
assertEquals(direct.getString("key1"), utils.getString("key1"));
- } catch (MissingResourceException e) {
+ } catch (@SuppressWarnings("unused") MissingResourceException e) {
fail("Direct call should not throw for existing bundle");
}
}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/BeanMap_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/BeanMap_Test.java
index 8d8ff651eb..b721ce02f7 100755
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/BeanMap_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/BeanMap_Test.java
@@ -42,7 +42,8 @@ import org.junit.jupiter.api.*;
"serial",
"java:S5961",
"java:S1186",
- "unused" // Parameters retained for method-signature/functional-interface consistency in test fixtures.
+ "unused", // Parameters retained for method-signature/functional-interface consistency in test fixtures.
+ "unlikely-arg-type" // Intentionally tests containsKey() returns false for a wrong-typed key.
})
class BeanMap_Test extends TestBase {
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/encoders/EncoderSet_OverridingBeanStore_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/encoders/EncoderSet_OverridingBeanStore_Test.java
index 184e9b3197..8c037b463c 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/encoders/EncoderSet_OverridingBeanStore_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/encoders/EncoderSet_OverridingBeanStore_Test.java
@@ -29,6 +29,9 @@ import org.junit.jupiter.api.*;
* through to the builder's reflective bean lookups so test-time overrides win over the builder's
* regular bean store entries.
*/
+@SuppressWarnings({
+ "resource" // Closeable resources in tests are intentionally unassigned; closing is handled by test infrastructure.
+})
class EncoderSet_OverridingBeanStore_Test extends TestBase {
interface Marker {
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/ParserReaderTest.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/ParserReaderTest.java
index 081d57ecf4..45d5d8c5ad 100755
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/ParserReaderTest.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/ParserReaderTest.java
@@ -22,6 +22,9 @@ import org.apache.juneau.*;
import org.apache.juneau.marshall.parser.*;
import org.junit.jupiter.api.*;
+@SuppressWarnings({
+ "resource" // Closeable resources in tests are intentionally unassigned; closing is handled by test infrastructure.
+})
class ParserReaderTest extends TestBase {
//====================================================================================================
diff --git a/juneau-distrib/pom.xml b/juneau-distrib/pom.xml
index 25b2362c4d..b41d5e35e1 100644
--- a/juneau-distrib/pom.xml
+++ b/juneau-distrib/pom.xml
@@ -894,26 +894,15 @@
<destFileName>apache-juneau-examples-core-${project.version}.zip</destFileName>
</artifactItem>
- <!-- juneau-examples-rest-jetty -->
+ <!-- juneau-petstore-jetty -->
<artifactItem>
<outputDirectory>${project.build.directory}/bin/projects</outputDirectory>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples-rest-jetty</artifactId>
+ <artifactId>juneau-petstore-jetty</artifactId>
<classifier>bin</classifier>
<type>zip</type>
<version>${project.version}</version>
- <destFileName>apache-juneau-examples-rest-jetty-${project.version}.zip</destFileName>
- </artifactItem>
-
- <!-- juneau-examples-springboot -->
- <artifactItem>
- <outputDirectory>${project.build.directory}/bin/projects</outputDirectory>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples-rest-springboot</artifactId>
- <classifier>bin</classifier>
- <type>zip</type>
- <version>${project.version}</version>
- <destFileName>apache-juneau-examples-rest-springboot-${project.version}.zip</destFileName>
+ <destFileName>apache-juneau-petstore-jetty-${project.version}.zip</destFileName>
</artifactItem>
<!-- juneau-my-springboot-microservice -->
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/.gitignore b/juneau-examples/juneau-examples-rest-jetty-ftest/.gitignore
deleted file mode 100644
index 63826f18d5..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-/target/
-**/.DS_Store
-.classpath
-.project
-/.settings/
-/bin/
-/derby.log
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/logs/.gitignore b/juneau-examples/juneau-examples-rest-jetty-ftest/logs/.gitignore
deleted file mode 100644
index bd317cc138..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/logs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/*log*
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/main/java/empty.txt b/juneau-examples/juneau-examples-rest-jetty-ftest/src/main/java/empty.txt
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java
deleted file mode 100644
index f453b57d3c..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import static org.apache.juneau.commons.utils.CollectionUtils.*;
-import static org.apache.juneau.commons.utils.ThrowableUtils.*;
-import static org.apache.juneau.examples.rest.TestUtils.*;
-import static org.junit.runners.MethodSorters.*;
-
-import java.io.*;
-import java.util.*;
-import java.util.function.*;
-
-import org.apache.juneau.commons.http.*;
-import org.apache.juneau.marshall.csv.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.marshall.json.*;
-import org.apache.juneau.marshall.msgpack.*;
-import org.apache.juneau.marshall.parser.*;
-import org.apache.juneau.marshall.plaintext.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.marshall.uon.*;
-import org.apache.juneau.marshall.urlencoding.*;
-import org.apache.juneau.marshall.xml.*;
-import org.apache.juneau.rest.client.classic.*;
-import org.junit.*;
-
-@FixMethodOrder(NAME_ASCENDING)
-@Ignore("Base class for parameterized tests - not meant to be run directly")
-@SuppressWarnings({
- "java:S3577", // Class name ends with "TestBase" to indicate it's a base class, not a test class itself
- "resource" // RestClient lifecycle managed via the clients map and tearDown(); fluent API chains consume responses internally
-})
-public class ContentComboTestBase extends RestTestcase {
-
- // Reusable RestClients keyed by label that live for the duration of a testcase class.
- private static Map<String,RestClient> clients = map();
-
- protected RestClient getClient(MediaType mediaType) {
- var mt = mediaType.toString();
- return switch (mt) {
- case "text/csv" -> getClient(mt, CsvSerializer.DEFAULT, CsvParser.DEFAULT);
- case "text/html" -> getClient(mt, HtmlSerializer.DEFAULT, HtmlParser.DEFAULT);
- case "application/json" -> getClient(mt, JsonSerializer.DEFAULT, JsonParser.DEFAULT);
- case "octal/msgpack" -> getClient(mt, MsgPackSerializer.DEFAULT, MsgPackParser.DEFAULT, x -> x.queryData("plainText", "true"));
- case "text/plain" -> getClient(mt, PlainTextSerializer.DEFAULT, PlainTextParser.DEFAULT);
- case "text/uon" -> getClient(mt, UonSerializer.DEFAULT, UonParser.DEFAULT);
- case "application/x-www-form-urlencoded" -> getClient(mt, UrlEncodingSerializer.DEFAULT, UrlEncodingParser.DEFAULT);
- case "text/xml" -> getClient(mt, XmlSerializer.DEFAULT, XmlParser.DEFAULT);
- default -> throw rex("Client for mediaType ''{0}'' not found", mt);
- };
- }
-
- @SafeVarargs
- protected final RestClient getClient(String label, Serializer serializer, Parser parser, Consumer<RestClient.Builder<?>>...postApply) {
- if (! clients.containsKey(label)) {
- var b = SamplesMicroservice.client(serializer, parser);
- for (var c : postApply)
- c.accept(b);
- clients.put(label, b.build());
- }
- return clients.get(label);
- }
-
- @AfterClass
- public static void tearDown() {
- clients.values().forEach(rc -> {
- try {
- rc.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- });
- clients.clear();
- }
-
- public static class ComboInput {
- public final String name, url;
- public final MediaType mediaType;
- public final String[] expectedResults;
-
- public ComboInput(String name, String url, MediaType mediaType, String...expectedResults) {
- this.name = name;
- this.url = url;
- this.mediaType = mediaType;
- this.expectedResults = expectedResults;
- }
- }
-
- private final ComboInput comboInput;
-
- public ContentComboTestBase(ComboInput comboInput) {
- this.comboInput = comboInput;
- }
-
- @Test
- public void doTest() throws Exception {
- var rc = getClient(comboInput.mediaType);
- var s = rc.get(comboInput.url).run().getContent().asString();
- assertContains(s, comboInput.expectedResults);
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RestTestcase.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RestTestcase.java
deleted file mode 100644
index 478d97d42c..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RestTestcase.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import org.junit.*;
-
-/**
- * Superclass of REST testcases that start up the REST test microservice before running the tests locally.
- *
- * @author James Bognar (james.bognar@salesforce.com)
- */
-public class RestTestcase {
-
- private static boolean microserviceStarted;
-
- @BeforeClass
- public static void setUp() {
- microserviceStarted = SamplesMicroservice.startMicroservice();
- }
-
- @AfterClass
- public static void tearDown() {
- if (microserviceStarted)
- SamplesMicroservice.stopMicroservice();
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootContentTest.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootContentTest.java
deleted file mode 100644
index c1e3967a85..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootContentTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import static org.apache.juneau.commons.utils.CollectionUtils.*;
-
-import java.util.*;
-
-import org.apache.juneau.commons.http.*;
-import org.junit.runner.*;
-import org.junit.runners.*;
-
-@RunWith(Parameterized.class)
-public class RootContentTest extends ContentComboTestBase {
-
- @Parameterized.Parameters
- public static Collection<Object[]> getParameters() {
- // @formatter:off
- return l(new Object[][] {
- { /* 0 */
- new ComboInput("HTML-stylesheet", "/", MediaType.HTML,
- "@import '/htdocs/themes/dark.css';",
- ".menu-item {"
- )
- },
- { /* 1 */
- new ComboInput("HTML-stylesheet-contnt", "/htdocs/themes/devops.css", MediaType.PLAIN,
- "/** DevOps look-and-feel */"
- )
- },
- { /* 2 */
- new ComboInput("HTML-header", "/", MediaType.HTML,
- "<head>",
- "<h1>Root resources</h1>",
- "<h2>Navigation page</h2>",
- "<img src='/htdocs/images/juneau.png' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/>"
- )
- },
- { /* 3 */
- new ComboInput("HTML-nav", "/", MediaType.HTML,
- "<nav>",
- "<a href='/api'>api</a>",
- "<a onclick='menuClick(this);'>content-type</a>",
- "<a href='https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java'>source</a>"
- )
- },
- { /* 4 */
- new ComboInput("HTML-nav-popup-contentType", "/", MediaType.HTML,
- "<div class='popup-content'>",
- "/?plainText=true&Accept=application%2Fjson"
- )
- },
- { /* 5 */
- new ComboInput("HTML-aside", "/", MediaType.HTML,
- "<aside>",
- "<p>This is an example of a 'router' page that serves as a jumping-off point to child resources.</p>",
- "<p>Other features (such as this aside) are added through annotations.</p>"
- )
- },
- { /* 6 */
- new ComboInput("HTML-footer", "/", MediaType.HTML,
- "<footer>",
- "<img style='float:right;padding-right:20px;height:32px' src='/htdocs/images/asf.png'>"
- )
- },
- { /* 7 */
- new ComboInput("HTML-content-text/html", "/", MediaType.HTML,
- "<a href='/helloWorld'>helloWorld</a>",
- "<td>Hello World</td>"
- )
- },
- { /* 8 */
- new ComboInput("HTML-content-application/json", "/", MediaType.JSON,
- "'name':'helloWorld',",
- "'description':'Hello World'"
- )
- },
- { /* 9 */
- new ComboInput("HTML-content-octal/msgpack", "/", MediaType.MSGPACK,
- "82 A4 6E"
- )
- },
- { /* 10 */
- new ComboInput("HTML-content-text/plain", "/", MediaType.PLAIN,
- "Hello World"
- )
- },
- { /* 11 */
- new ComboInput("HTML-content-text/uon", "/", MediaType.UON,
- "(name=helloWorld,description='Hello World')"
- )
- },
- { /* 12 */
- new ComboInput("HTML-content-application/x-www-form-urlencoded", "/", MediaType.URLENCODING,
- "0=(name=helloWorld,description='Hello+World')"
- )
- },
- { /* 13 */
- new ComboInput("HTML-content-text/xml", "/", MediaType.XML,
- "<name>helloWorld</name><description>Hello World</description>"
- )
- }
- });
- // @formatter:on
- }
-
- public RootContentTest(ComboInput comboInput) {
- super(comboInput);
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
deleted file mode 100644
index 6e3e627c5f..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import static org.junit.Assert.*;
-import static org.junit.runners.MethodSorters.*;
-
-import org.apache.juneau.bean.swagger.*;
-import org.apache.juneau.marshall.collections.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.marshall.json5.*;
-import org.apache.juneau.rest.client.classic.*;
-import org.apache.juneau.rest.server.beans.*;
-import org.junit.*;
-
-@SuppressWarnings({
- "resource" // RestClient lifecycle managed by SamplesMicroservice; fluent API chains consume and close responses internally
-})
-@FixMethodOrder(NAME_ASCENDING)
-public class RootResourcesTest extends RestTestcase {
-
- private static boolean debug;
-
- private RestClient jsonClient = SamplesMicroservice.defaultClient;
-
- //====================================================================================================
- // text/json
- //====================================================================================================
- @Test
- public void testJson() throws Exception {
- var client = SamplesMicroservice.defaultClient;
-
- var x = client.get("").run().getContent().as(ResourceDescription[].class);
- assertEquals("helloWorld", x[0].getName());
- assertEquals("Hello World", x[0].getDescription());
-
- var x2 = jsonClient.get("api").run().getContent().as(JsonMap.class);
- var s = x2.getMap("info").getString("description");
- if (debug)
- System.err.println(s);
- assertTrue(s, s.startsWith("Example of a router resource page"));
- }
-
- //====================================================================================================
- // text/xml
- //====================================================================================================
- @Test
- public void testXml() throws Exception {
- try (var client = SamplesMicroservice.client().xml().build()) {
-
- var x = client.get("").run().getContent().as(ResourceDescription[].class);
- assertEquals("helloWorld", x[0].getName());
- assertEquals("Hello World", x[0].getDescription());
-
- var x2 = jsonClient.get("api").run().getContent().as(JsonMap.class);
- var s = x2.getMap("info").getString("description");
- if (debug)
- System.err.println(s);
- assertTrue(s, s.startsWith("Example of a router resource page"));
- }
- }
-
- //====================================================================================================
- // text/html+stripped
- //====================================================================================================
- @Test
- public void testHtmlStripped() throws Exception {
- try (RestClient client = SamplesMicroservice.client().parsers(HtmlParser.DEFAULT).accept("text/html+stripped").build()) {
-
- var x = client.get("").run().getContent().as(ResourceDescription[].class);
- assertEquals("helloWorld", x[0].getName());
- assertEquals("Hello World", x[0].getDescription());
-
- var x2 = jsonClient.get("api").run().getContent().as(JsonMap.class);
- var s = x2.getMap("info").getString("description");
- if (debug)
- System.err.println(s);
- assertTrue(s, s.startsWith("Example of a router resource page"));
- }
- }
-
- //====================================================================================================
- // application/json+schema
- //====================================================================================================
- @Test
- public void testJsonSchema() throws Exception {
- try (RestClient client = SamplesMicroservice.client().parsers(Json5Parser.DEFAULT).accept("text/json+schema").build()) {
- var m = client.get("").run().getContent().as(JsonMap.class);
- assertNotNull(m);
- if (debug)
- System.err.println(m);
- client.closeQuietly();
- }
- }
-
- //====================================================================================================
- // OPTIONS page
- //====================================================================================================
- @Test
- public void testOptionsPage() throws Exception {
- Swagger o = jsonClient.get("api").run().getContent().as(Swagger.class);
- if (debug)
- System.err.println(o);
- assertEquals("Example of a router resource page.", o.getInfo().getDescription());
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java
deleted file mode 100644
index 9569ac8310..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import java.net.*;
-import java.util.*;
-
-import org.apache.juneau.commons.inject.*;
-import org.apache.juneau.marshall.parser.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.microservice.*;
-import org.apache.juneau.microservice.jetty.*;
-import org.apache.juneau.rest.client.classic.*;
-
-import jakarta.servlet.*;
-
-/**
- * Utility class for starting up the examples microservice.
- */
-@SuppressWarnings({
- "resource" // Closeable resources in tests are intentionally unassigned; closing is handled by test infrastructure.
-})
-public class SamplesMicroservice {
- static volatile Microservice microservice;
- static URI microserviceURI;
-
- // Reusable HTTP clients that get created and shut down with the microservice.
- public static RestClient defaultClient;
- public static RestClient defaultClientPlaintext;
-
- /**
- * Starts the microservice.
- * @return <jk>true</jk> if the service started, <jk>false</jk> if it's already started.
- * If this returns <jk>false</jk> then don't call stopMicroservice()!.
- */
- public static synchronized boolean startMicroservice() {
- if (microservice != null)
- return false;
- try {
- Locale.setDefault(Locale.US);
- microservice = Microservice.create().workingDir("../juneau-examples-rest-jetty").configName("juneau-examples-rest-jetty.cfg").configurations(JettyConfiguration.class, AppConfig.class).build();
- microserviceURI = microservice.start().getBeanStore().getBean(JettyServerComponent.class).orElseThrow().getURI();
- defaultClient = client().json5().build();
- defaultClientPlaintext = client().plainText().build();
- return true;
- } catch (Throwable e) {
- // Probably already started.
- e.printStackTrace();
- System.err.println(e); // NOT DEBUG
- return false;
- }
- }
-
- /**
- * Returns the URI of the microservice.
- * @return The URI of the microservice.
- */
- public static URI getURI() {
- if (microservice == null)
- startMicroservice();
- return microserviceURI;
- }
-
- /**
- * Stops the microservice.
- */
- public static synchronized void stopMicroservice() {
- try {
- microservice.stop();
- microservice = null;
- defaultClient.closeQuietly();
- defaultClientPlaintext.closeQuietly();
- } catch (Exception e) {
- System.err.println(e); // NOT DEBUG
- }
- }
-
- /**
- * Create a new HTTP client.
- */
- public static RestClient.Builder<?> client() {
- try {
- return RestClient.create().rootUrl(microserviceURI);
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * Create a new HTTP client using the specified serializer and parser.
- */
- public static RestClient.Builder<?> client(Serializer s, Parser p) {
- return client().serializer(s).parser(p);
- }
-
- /**
- * Create a new HTTP client using the specified serializer and parser.
- */
- public static RestClient.Builder<?> client(Class<? extends Serializer> s, Class<? extends Parser> p) {
- return client().serializer(s).parser(p);
- }
-
- /**
- * Application configuration contributing the {@link RootResources} servlet.
- */
- @Configuration
- public static class AppConfig {
-
- /**
- * Provides the top-level REST servlet, auto-mounted by {@link JettyServerComponent} at
- * {@link org.apache.juneau.rest.server.Rest#path()}.
- *
- * @return The root servlet.
- */
- @Bean
- public Servlet rootResources() {
- return new RootResources();
- }
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java
deleted file mode 100644
index e46c13285c..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import static org.apache.juneau.commons.utils.IoUtils.*;
-import static org.apache.juneau.commons.utils.StringUtils.*;
-
-import java.io.*;
-import java.util.regex.*;
-
-import org.apache.juneau.marshall.json.*;
-import org.apache.juneau.marshall.json5.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.marshall.xml.*;
-import org.junit.*;
-
-public class TestUtils {
-
- // @formatter:off
- private static JsonSerializer js = Json5Serializer.create()
- .keepNullProperties()
- .build();
-
- private static JsonSerializer jsSorted = Json5Serializer.create()
- .sortCollections()
- .sortMaps()
- .keepNullProperties()
- .build();
-
- private static JsonSerializer js2 = Json5Serializer.create()
- .build();
-
- private static JsonSerializer js3 = Json5Serializer.create()
-
- .build();
- // @formatter:on
-
- /**
- * Verifies that two objects are equivalent.
- * Does this by doing a string comparison after converting both to JSON.
- */
- public static void assertEqualObjects(Object o1, Object o2) throws SerializeException {
- assertEqualObjects(o1, o2, false);
- }
-
- /**
- * Verifies that two objects are equivalent.
- * Does this by doing a string comparison after converting both to JSON.
- * @param sort If <jk>true</jk> sort maps and collections before comparison.
- */
- public static void assertEqualObjects(Object o1, Object o2, boolean sort) throws SerializeException {
- var s = (sort ? jsSorted : js);
- var s1 = s.serialize(o1);
- var s2 = s.serialize(o2);
- if (s1.equals(s2))
- return;
- throw new ComparisonFailure(null, s1, s2);
- }
-
- /**
- * Validates that the whitespace is correct in the specified XML.
- */
- public static void checkXmlWhitespace(String out) throws SerializeException {
- if (out.indexOf('\u0000') != -1) {
- for (var s : out.split("\u0000"))
- checkXmlWhitespace(s);
- return;
- }
-
- int indent = -1;
- var startTag = Pattern.compile("^(\\s*)<[^/>]+(\\s+\\S+=['\"]\\S*['\"])*\\s*>$");
- var endTag = Pattern.compile("^(\\s*)</[^>]+>$");
- var combinedTag = Pattern.compile("^(\\s*)<[^>/]+(\\s+\\S+=['\"]\\S*['\"])*\\s*/>$");
- var contentOnly = Pattern.compile("^(\\s*)[^\\s\\<]+$");
- var tagWithContent = Pattern.compile("^(\\s*)<[^>]+>.*</[^>]+>$");
- var lines = out.split("\n");
- try {
- for (var i = 0; i < lines.length; i++) {
- var line = lines[i];
- var m = startTag.matcher(line);
- if (m.matches()) {
- indent++;
- if (m.group(1).length() != indent)
- throw new SerializeException("Wrong indentation detected on start tag line ''{0}''", i + 1);
- continue;
- }
- m = endTag.matcher(line);
- if (m.matches()) {
- if (m.group(1).length() != indent)
- throw new SerializeException("Wrong indentation detected on end tag line ''{0}''", i + 1);
- indent--;
- continue;
- }
- m = combinedTag.matcher(line);
- if (m.matches()) {
- indent++;
- if (m.group(1).length() != indent)
- throw new SerializeException("Wrong indentation detected on combined tag line ''{0}''", i + 1);
- indent--;
- continue;
- }
- m = contentOnly.matcher(line);
- if (m.matches()) {
- indent++;
- if (m.group(1).length() != indent)
- throw new SerializeException("Wrong indentation detected on content-only line ''{0}''", i + 1);
- indent--;
- continue;
- }
- m = tagWithContent.matcher(line);
- if (m.matches()) {
- indent++;
- if (m.group(1).length() != indent)
- throw new SerializeException("Wrong indentation detected on tag-with-content line ''{0}''", i + 1);
- indent--;
- continue;
- }
- throw new SerializeException("Unmatched whitespace line at line number ''{0}''", i + 1);
- }
- if (indent != -1)
- throw new SerializeException("Possible unmatched tag. indent=''{0}''", indent);
- } catch (SerializeException e) {
- printLines(lines);
- throw e;
- }
- }
-
- private static void printLines(String[] lines) {
- for (var i = 0; i < lines.length; i++)
- System.err.println(String.format("%4s:%s", i + 1, lines[i])); // NOT DEBUG
- }
-
- public static void validateXml(Object o) throws Exception {
- validateXml(o, XmlSerializer.DEFAULT_NS_SQ);
- }
-
- /**
- * Test whitespace and generated schema.
- */
- public static void validateXml(Object o, XmlSerializer s) throws Exception {
- s = s.copy().ws().ns().addNamespaceUrisToRoot().build();
- var xml = s.serialize(o);
-
- try {
- TestUtils.checkXmlWhitespace(xml);
- } catch (Exception e) {
- System.err.println("---XML---"); // NOT DEBUG
- System.err.println(xml); // NOT DEBUG
- throw e;
- }
- }
-
- public static String readFile(String p) throws Exception {
- var is = TestUtils.class.getResourceAsStream(p);
- if (is == null) {
- is = new FileInputStream(p);
- }
- try (InputStream is2 = is) {
- var e = read(is2);
- e = e.replaceAll("\r", "");
- return e;
- }
- }
-
- protected static final char[] hexArray = "0123456789ABCDEF".toCharArray();
-
- public static String toHex(byte b) {
- var c = new char[2];
- var v = b & 0xFF;
- c[0] = hexArray[v >>> 4];
- c[1] = hexArray[v & 0x0F];
- return new String(c);
- }
-
- public static void debugOut(Object o) {
- try {
- System.err.println(decodeHex(Json5Serializer.DEFAULT.serialize(o))); // NOT DEBUG
- } catch (SerializeException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Assert that the object equals the specified string after running it through Json5Serializer.DEFAULT.toString().
- */
- public static void assertObjectEquals(String s, Object o) {
- assertObjectEquals(s, o, js2);
- }
-
- /**
- * Assert that the object equals the specified string after running it through Json5Serializer.DEFAULT.toString().
- */
- public static void assertSortedObjectEquals(String s, Object o) {
- assertObjectEquals(s, o, js3);
- }
-
- /**
- * Assert that the object equals the specified string after running it through ws.toString().
- */
- public static void assertObjectEquals(String s, Object o, WriterSerializer ws) {
- Assert.assertEquals(s, ws.toString(o));
- }
-
- /**
- * Replaces all newlines with pipes, then compares the strings.
- */
- public static void assertTextEquals(String s, Object o) {
- var s2 = o.toString().replaceAll("\\r?\\n", "|");
- Assert.assertEquals(s, s2);
- }
-
- /**
- * Tries to turn the serialized output to a String.
- * If it's a byte[], convert it to a UTF-8 encoded String.
- */
- public static final String toString(Object o) {
- if (o == null)
- return null;
- if (o instanceof String)
- return (String)o;
- if (o instanceof byte[])
- return new String((byte[])o, UTF8);
- return o.toString();
- }
-
- public static final void assertContains(Object value, String...substrings) {
- for (var substring : substrings)
- if (! contains(toString(value), substring)) {
- System.err.println("Text did not contain expected substring: '" + toString(substring) + "'"); // NOT DEBUG
- System.err.println("=== TEXT ==="); // NOT DEBUG
- System.err.println(toString(value)); // NOT DEBUG
- System.err.println("============"); // NOT DEBUG
- throw new ComparisonFailure("Text did not contain expected substring.", toString(substring), toString(value)); // NOT DEBUG
- }
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/_TestSuite.java b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/_TestSuite.java
deleted file mode 100644
index 04f33b0a1b..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/_TestSuite.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import org.junit.*;
-import org.junit.runner.*;
-import org.junit.runners.*;
-import org.junit.runners.Suite.*;
-
-/**
- * Runs all the testcases in this project.
- * Starts a REST service running org.apache.juneau.marshall.examples.rest.RootResources on port 10000.
- * Stops the REST service after running the tests.
- */
-@RunWith(Suite.class)
-// @formatter:off
-@SuiteClasses({
- RootResourcesTest.class,
- RootContentTest.class
-})
-// @formatter:on
-public class _TestSuite {
-
- @BeforeClass
- public static void setUp() {
- double version = Double.parseDouble(System.getProperty("java.specification.version"));
- Assume.assumeFalse("Java version " + version + " detected. Tests will be skipped.", version < 1.8);
- SamplesMicroservice.startMicroservice();
- }
-
- @AfterClass
- public static void tearDown() {
- SamplesMicroservice.stopMicroservice();
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-jetty/.gitignore b/juneau-examples/juneau-examples-rest-jetty/.gitignore
deleted file mode 100644
index 63826f18d5..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-/target/
-**/.DS_Store
-.classpath
-.project
-/.settings/
-/bin/
-/derby.log
diff --git a/juneau-examples/juneau-examples-rest-jetty/build-overlay/pom.xml b/juneau-examples/juneau-examples-rest-jetty/build-overlay/pom.xml
deleted file mode 100644
index 3354f6dffd..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty/build-overlay/pom.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!--
- This project is meant to be used as a starting point for developers to use in creating their own REST microservices.
- It creates a parent REST interface on port 10000 with a single child hello-world resource.
- This POM is likewise meant to be used as a starting point for developers. It creates an uber-jar
- to run the microserice from the command line. Copy the jar as well as the .cfg file and start it
- with java -jar juneau-microservice-template-1.0.0.jar microservice.cfg
- The group/artifact/version information is meant to be overwritten by developers to match their own needs.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.apache.juneau.examples</groupId>
- <artifactId>juneau-examples-rest-jetty</artifactId>
- <name>Apache Juneau REST Examples</name>
- <version>${version}</version>
- <description>Sample code packaged as a microservice.</description>
-
- <properties>
- <encoding>UTF-8</encoding>
- <maven.compiler.source>17</maven.compiler.source>
- <maven.compiler.target>17</maven.compiler.target>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
- <derby.version>${derby.version}</derby.version>
- <springboot.version>${springboot.version}</springboot.version>
- <juneau.version>${version}</juneau.version>
- <junit.version>${junit.version}</junit.version>
- <xml.apis.version>${xml.apis.version}</xml.apis.version>
- </properties>
-
- <dependencies>
-
- <!-- Juneau artifacts -->
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-microservice-jetty</artifactId>
- <version>\${juneau.version}</version>
- </dependency>
-
- <!-- Optional RDF support -->
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-marshall</artifactId>
- <version>\${juneau.version}</version>
- </dependency>
-
- <!-- Used for JPA persistence of beans -->
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>\${derby.version}</version>
- </dependency>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- <version>\${xml.apis.version}</version>
- </dependency>
-
- <!-- Other -->
- <dependency>
- <groupId>org.junit.vintage</groupId>
- <artifactId>junit-vintage-engine</artifactId>
- <version>${junit.version}</version>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
-
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>17</source>
- <target>17</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>3.0.2</version>
- <executions>
- <execution>
- <id>package-config</id>
- <phase>package</phase>
- <goals>
- <goal>copy-resources</goal>
- </goals>
- <configuration>
- <outputDirectory>target</outputDirectory>
- <resources>
- <resource>
- <directory>.</directory>
- <includes>examples.cfg</includes>
- </resource>
- </resources>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifest>
- <mainClass>org.apache.juneau.examples.rest.jetty.App
- </mainClass>
- </manifest>
- </archive>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-shade-plugin</artifactId>
- <configuration>
- <createDependencyReducedPom>false</createDependencyReducedPom>
- </configuration>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <filters>
- <filter>
- <artifact>*:*</artifact>
- <excludes>
- <exclude>META-INF/*.SF</exclude>
- <exclude>META-INF/*.RSA</exclude>
- <exclude>META-INF/*.INF</exclude> <!-- This one may not be required -->
- </excludes>
- </filter>
- </filters>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
- </build>
-
-</project>
diff --git a/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.cfg b/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.cfg
deleted file mode 100755
index f5d4f1ba92..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.cfg
+++ /dev/null
@@ -1,209 +0,0 @@
-# ***************************************************************************************************************************
-# * 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. *
-# ***************************************************************************************************************************
-
-#=======================================================================================================================
-# Basic configuration file for SaaS microservices
-# Subprojects can use this as a starting point.
-#=======================================================================================================================
-
-
-#=======================================================================================================================
-# Jetty settings
-#=======================================================================================================================
-[Jetty]
-
-# Path of the jetty.xml file used to configure the Jetty server.
-config = files/jetty.xml
-
-# Resolve Juneau variables in the jetty.xml file.
-resolveVars = true
-
-# Port to use for the jetty server.
-# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
-# The resulting available port gets set as the system property "availablePort" which can be referenced in the
-# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).
-port = 10000,0,0,0
-
-#=======================================================================================================================
-# REST settings
-#=======================================================================================================================
-[REST]
-
-# Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @Rest-annotated
-# classes. These are static files that are served up by the servlet under the specified sub-paths.
-# For example, given the following setting...
-# staticFiles = htdocs:my-docs,styles/my-styles
-# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
-# This path can be relative to the working directory, classpath root, or package of your resource class.
-# Used by the BasicRestConfig interface that defines the following value:
-# staticFiles="$C{REST/staticFiles}"
-staticFiles = htdocs:htdocs
-
-# Stylesheet to use for HTML views.
-# Used by the BasicRestConfig interface that defines the following value:
-# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"
-theme = servlet:/htdocs/themes/dark.css
-
-# Various look-and-feel settings used in the BasicRestConfig interface.
-headerIcon = servlet:/htdocs/images/juneau.png
-headerLink = http://juneau.apache.org
-footerIcon = servlet:/htdocs/images/asf.png
-footerLink = http://www.apache.org
-favicon = $C{REST/headerIcon}
-head = <link rel='icon' href='$U{$C{REST/favicon}}'/>
-header =
- <a href='$U{$C{REST/headerLink}}'>
- <img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/>
- </a>
-footer =
- <a href='$U{$C{REST/footerLink}}'>
- <img style='float:right;padding-right:20px;height:32px' src='$U{$C{REST/footerIcon}}'>
- </a>
-
-#=======================================================================================================================
-# Console settings
-#=======================================================================================================================
-[Console]
-
-enabled = true
-
-# List of available console commands.
-# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
-# the console.
-# When listed here, the implementations must provide a no-arg constructor.
-# They can also be provided dynamically by overriding the Microservice.createConsoleCommands() method.
-commands =
- org.apache.juneau.marshall.microservice.console.ExitCommand,
- org.apache.juneau.marshall.microservice.console.RestartCommand,
- org.apache.juneau.marshall.microservice.console.HelpCommand,
- org.apache.juneau.marshall.microservice.console.ConfigCommand,
- org.apache.juneau.marshall.examples.rest.command.EchoCommand
-
-#=======================================================================================================================
-# Logger settings
-#-----------------------------------------------------------------------------------------------------------------------
-# See FileHandler Java class for details.
-#=======================================================================================================================
-[Logging]
-
-# The directory where to create the log file.
-# Default is "."
-logDir = ./target/logs
-
-# The name of the log file to create for the main logger.
-# The logDir and logFile make up the pattern that's passed to the FileHandler
-# constructor.
-# If value is not specified, then logging to a file will not be set up.
-logFile = microservice.%g.log
-
-# Whether to append to the existing log file or create a new one.
-append = false
-
-# The SimpleDateFormat format to use for dates.
-dateFormat = yyyy.MM.dd hh:mm:ss
-
-# The log message format.
-# The value can contain any of the following variables:
-# {date} - The date, formatted per dateFormat.
-# {class} - The class name.
-# {method} - The method name.
-# {logger} - The logger name.
-# {level} - The log level name.
-# {msg} - The log message.
-# {threadid} - The thread ID.
-# {exception} - The localized exception message.
-format = [{date} {level}] {msg}%n
-
-# The maximum log file size.
-# Suffixes available for numbers.
-# See Config.getInt(String,int) for details.
-limit = 1M
-
-# Max number of log files.
-count = 5
-
-# Default log levels.
-# Format is lax-JSON.
-# Keys are logger names.
-# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
-levels =
- {
- '': 'WARNING',
- org.apache.juneau.marshall: 'WARNING',
- org.eclipse.jetty: 'WARNING'
- }
-
-# Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
-# Useful for preventing log files from filling up with duplicate stack traces.
-useStackTraceHashes = true
-
-# The default level for the console logger.
-# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
-consoleLevel = WARNING
-
-# The default level for the file logger.
-# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
-# Default is INFO.
-fileLevel = INFO
-
-#=======================================================================================================================
-# System properties
-#-----------------------------------------------------------------------------------------------------------------------
-# These are arbitrary system properties that can be set during startup.
-#=======================================================================================================================
-[SystemProperties]
-
-# Configure Jetty for StdErrLog Logging
-# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
-
-# Configure Jetty to log using java-util logging
-org.eclipse.jetty.util.log.class = org.apache.juneau.marshall.microservice.jetty.JettyLogger
-
-# Jetty logging level
-org.eclipse.jetty.LEVEL = WARN
-
-derby.stream.error.file = $C{Logging/logDir}/derby-errors.log
-
-# Note that any configuration properties can also be set globally as system properties...
-
-# Disable classpath resource caching.
-# Useful if you're attached using a debugger and you're modifying classpath resources while running.
-RestContext.disableClasspathResourceCaching.b = true
-
-#=======================================================================================================================
-# DockerRegistryResource properties
-#=======================================================================================================================
-[DockerRegistry]
-url = http://docker.apache.org:5000/v1
-
-#=======================================================================================================================
-# SqlQueryResource properties
-#=======================================================================================================================
-[SqlQueryResource]
-driver = org.apache.derby.jdbc.EmbeddedDriver
-directory = target/derby/testDB
-connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true
-allowTempUpdates = true
-includeRowNums = false
-
-#=======================================================================================================================
-# Source code location
-#=======================================================================================================================
-[Source]
-gitHub = https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java
-
-#=======================================================================================================================
-# PetStoreResource properties
-#=======================================================================================================================
-[PetStore]
-headerImage = <a href='http://swagger.io'><img src='$U{servlet:/htdocs/cat.png}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/></a>
diff --git a/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch b/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch
deleted file mode 100644
index 7439aeb75f..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
- <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
- <listEntry value="/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/App.java"/>
- </listAttribute>
- <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
- <listEntry value="1"/>
- </listAttribute>
- <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/>
- <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
- <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
- <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
- <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.juneau.marshall.examples.rest.jetty.App"/>
- <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="juneau-examples-rest-jetty"/>
- <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="juneau-examples-rest-jetty"/>
- <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
-</launchConfiguration>
diff --git a/juneau-examples/juneau-examples-rest-jetty/logs/.gitignore b/juneau-examples/juneau-examples-rest-jetty/logs/.gitignore
deleted file mode 100644
index bd317cc138..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty/logs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/*log*
diff --git a/juneau-examples/juneau-examples-rest-jetty/logs/empty.txt b/juneau-examples/juneau-examples-rest-jetty/logs/empty.txt
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/assembly/bin.xml b/juneau-examples/juneau-examples-rest-jetty/src/assembly/bin.xml
deleted file mode 100644
index af351a1eed..0000000000
--- a/juneau-examples/juneau-examples-rest-jetty/src/assembly/bin.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!--
- This assembly is used to create the template zip file that developers use to import into Eclipse to start their
- own projects.
- -->
-<assembly
- xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 https://maven.apache.org/xsd/assembly-1.1.3.xsd">
- <id>bin</id>
- <formats>
- <format>zip</format>
- </formats>
- <baseDirectory>/</baseDirectory>
- <includeBaseDirectory>true</includeBaseDirectory>
- <fileSets>
- <fileSet>
- <directory>${basedir}/../juneau-examples-rest</directory>
- <outputDirectory>/</outputDirectory>
- <includes>
- <include>src/main/**</include>
- </includes>
- </fileSet>
- <fileSet>
- <useDefaultExcludes>false</useDefaultExcludes>
- <directory>${basedir}</directory>
- <outputDirectory>/</outputDirectory>
- <includes>
- <include>src/main/**</include>
- <include>files/**</include>
- <include>.settings/**</include>
- <include>.project</include>
- <include>.classpath</include>
- <include>*.launch</include>
- <include>*.cfg</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${basedir}/build-overlay</directory>
- <outputDirectory>/</outputDirectory>
- <filtered>true</filtered>
- </fileSet>
- </fileSets>
-
-</assembly>
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-springboot/.gitignore b/juneau-examples/juneau-examples-rest-springboot/.gitignore
deleted file mode 100644
index 63826f18d5..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-/target/
-**/.DS_Store
-.classpath
-.project
-/.settings/
-/bin/
-/derby.log
diff --git a/juneau-examples/juneau-examples-rest-springboot/build-overlay/Procfile b/juneau-examples/juneau-examples-rest-springboot/build-overlay/Procfile
deleted file mode 100644
index 992aac92f1..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/build-overlay/Procfile
+++ /dev/null
@@ -1 +0,0 @@
-web: java -jar target/juneau-examples-rest-springboot-${version}.jar
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-springboot/build-overlay/app.json b/juneau-examples/juneau-examples-rest-springboot/build-overlay/app.json
deleted file mode 100644
index 85040f0b28..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/build-overlay/app.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "Start on Heroku: Juneau REST Examples",
- "description": "Deployable REST examples to Heroku."
-}
diff --git a/juneau-examples/juneau-examples-rest-springboot/build-overlay/pom.xml b/juneau-examples/juneau-examples-rest-springboot/build-overlay/pom.xml
deleted file mode 100644
index 8beafaace1..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/build-overlay/pom.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!--
- This project is meant to be used as a starting point for developers to use in creating their own REST microservices.
- It creates a Spring Boot application on port 5000 populated with the Juneau REST examples.
- This POM is likewise meant to be used as a starting point for developers. It creates an uber-jar
- to run the microservice from the command line.
-
- Copy the jar as well as the my-microservice.cfg and jetty.xml file and start it with:
- java -jar juneau-examples-rest-springboot-1.0.jar
-
- The group/artifact/version information is meant to be overwritten by developers to match their own needs.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.apache.juneau.examples</groupId>
- <artifactId>juneau-examples-rest-springboot</artifactId>
- <name>Apache Juneau REST Examples</name>
- <version>${version}</version>
- <description>REST examples packaged as a Spring Boot microservice.</description>
-
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.4.2</version>
- <relativePath />
- </parent>
-
- <properties>
- <encoding>UTF-8</encoding>
- <maven.compiler.source>17</maven.compiler.source>
- <maven.compiler.target>17</maven.compiler.target>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
- <juneau.version>${version}</juneau.version>
- <springboot.version>2.4.2</springboot.version>
- </properties>
-
- <dependencies>
-
- <!-- Juneau artifacts -->
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-all</artifactId>
- <version>\${juneau.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-marshall</artifactId>
- <version>\${juneau.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-microservice</artifactId>
- <version>\${juneau.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-rest-server-springboot</artifactId>
- <version>\${juneau.version}</version>
- </dependency>
-
- <!-- Spring Boot dependencies-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <!-- Used for JPA persistence of beans -->
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- </dependency>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.5</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.7.5</version>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
-
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <version>${springboot.version}</version>
- <executions>
- <execution>
- <goals>
- <goal>build-info</goal>
- </goals>
- <configuration>
- <additionalProperties>
- <encoding.source>\${project.build.sourceEncoding}</encoding.source>
- <encoding.reporting>\${project.reporting.outputEncoding}</encoding.reporting>
- <java.source>\${maven.compiler.source}</java.source>
- <java.target>\${maven.compiler.target}</java.target>
- </additionalProperties>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifest>
- <mainClass>org.apache.juneau.examples.rest.springboot.App
- </mainClass>
- </manifest>
- </archive>
- </configuration>
- </plugin>
-
- </plugins>
- </build>
-
-</project>
diff --git a/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch b/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch
deleted file mode 100644
index e2e06b7619..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
- <booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
- <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
- <listEntry value="/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java"/>
- </listAttribute>
- <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
- <listEntry value="1"/>
- </listAttribute>
- <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/>
- <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
- <booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/>
- <booleanAttribute key="org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES" value="true"/>
- <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/>
- <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
- <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
- <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-18/"/>
- <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.juneau.marshall.examples.rest.springboot.App"/>
- <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="juneau-examples-rest-springboot"/>
- <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="juneau-examples-rest-springboot"/>
- <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
-</launchConfiguration>
diff --git a/juneau-examples/juneau-examples-rest-springboot/settings.xml b/juneau-examples/juneau-examples-rest-springboot/settings.xml
deleted file mode 100644
index 465f7d0175..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/settings.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
- <profiles>
- <profile>
- <id>apache-snapshots</id>
- <repositories>
- <repository>
- <id>apache.snapshots</id>
- <name>Apache Development Snapshot Repository</name>
- <url>https://repository.apache.org/content/repositories/snapshots/</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- <repository>
- <id>maven1</id>
- <url>https://repo1.maven.org/maven2</url>
- <releases>
- <enabled>true</enabled>
- </releases>
- </repository>
- </repositories>
- </profile>
- </profiles>
-
- <activeProfiles>
- <activeProfile>apache-snapshots</activeProfile>
- </activeProfiles>
-</settings>
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
deleted file mode 100644
index 01149dd055..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.juneau.examples.rest.springboot;
-
-import org.apache.juneau.commons.logging.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.springboot.*;
-import org.springframework.boot.autoconfigure.*;
-import org.springframework.boot.builder.*;
-import org.springframework.boot.web.servlet.*;
-import org.springframework.context.annotation.*;
-import org.springframework.stereotype.*;
-
-/**
- * Entry point for Examples REST application when deployed as a Spring Boot application.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>
- * </ul>
- */
-@SpringBootApplication
-@Controller
-public class App {
-
- /**
- * Entry point method.
- * @param args Command-line arguments.
- */
- @SuppressWarnings({
- "resource" // Spring ApplicationContext managed by Spring framework
- })
- public static void main(String[] args) {
- try {
- new SpringApplicationBuilder(App.class).run(args);
- Logger.getLogger(App.class).info("Initialized. App available on http://localhost:5000");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Optionally return an injectable message provider for the {@link HelloWorldResource} class.
- *
- * @return The message provider for the hello-world REST bean.
- */
- @Bean
- public HelloWorldMessageProvider getHelloWorldMessageProvider() { return new HelloWorldMessageProvider("Hello Spring injection user!"); }
-
- /**
- * Optionally return the {@link HelloWorldResource} object as an injectable bean.
- *
- * @return The hello-world REST bean.
- */
- @Bean
- public HelloWorldResource getHelloWorldResource() { return new HelloWorldResource(); }
-
- /**
- * Our root REST bean.
- * <p>
- * Note that this must extend from {@link SpringRestServlet} so that child resources can be resolved as Spring
- * beans.
- * <p>
- * All REST objects are attached to this bean using the {@link Rest#children()} annotation.
- *
- * @return The root resources REST bean.
- */
- @Bean
- public RootResources getRootResources() { return new RootResources(); }
-
- /**
- * @param rootResources The root REST resource servlet
- * @return The servlet registration mapped to "/*".
- */
- @Bean
- public ServletRegistrationBean<jakarta.servlet.Servlet> getRootServlet(RootResources rootResources) {
- return new ServletRegistrationBean<>(rootResources, "/*");
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java
deleted file mode 100644
index 685da679da..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.juneau.examples.rest.springboot;
-
-import org.apache.juneau.examples.rest.*;
-import org.apache.juneau.examples.rest.dto.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.microservice.resources.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.springboot.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample REST resource showing how to implement a "router" resource page.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>
-
- * </ul>
- *
- * @serial exclude
- */
-@Rest(
- title="Root resources",
- description="Example of a router resource page.",
- children={
- HelloWorldResource.class,
- DtoExamples.class,
- UtilityBeansResource.class,
- HtmlBeansResource.class,
- ConfigResource.class,
- ShutdownResource.class
- }
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "api: servlet:/api",
- "stats: servlet:/stats",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
- },
- aside={
- "<div class='text'>",
- "\t<p>This is an example of a 'router' page that serves as a jumping-off point to child resources.</p>",
- "\t<p>Resources can be nested arbitrarily deep through router pages.</p>",
- "\t<p>Note the <span class='link'>API</span> link provided that lets you see the generated swagger doc for this page.</p>",
- "\t<p>Also note the <span class='link'>STATS</span> link that provides basic usage statistics.</p>",
- "\t<p>Also note the <span class='link'>SOURCE</span> link on these pages to view the source code for the page.</p>",
- "\t<p>All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.</p>",
- "\t<p>Other features (such as this aside) are added through annotations.</p>",
- "</div>"
- },
- asideFloat="RIGHT"
-)
-@SerializerConfig(
- // For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
- // String comparisons.
- // You can apply any of the Serializer/Parser/MarshallingContext settings this way.
- quoteChar="'"
-)
-@SuppressWarnings({
- "java:S110" // Inheritance depth acceptable for example/demo code
-})
-public class RootResources extends BasicSpringRestServletGroup {
- private static final long serialVersionUID = 1L;
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/juneau.cfg b/juneau-examples/juneau-examples-rest-springboot/src/main/resources/juneau.cfg
deleted file mode 100755
index 6932e4b86d..0000000000
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/juneau.cfg
+++ /dev/null
@@ -1,70 +0,0 @@
-# ***************************************************************************************************************************
-# * 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. *
-# ***************************************************************************************************************************
-
-#=======================================================================================================================
-# REST settings
-#=======================================================================================================================
-[REST]
-
-# Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @Rest-annotated
-# classes. These are static files that are served up by the servlet under the specified sub-paths.
-# For example, given the following setting...
-# staticFiles = htdocs:my-docs,styles/my-styles
-# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
-# This path can be relative to the working directory, classpath root, or package of your resource class.
-# Used by the BasicRestConfig interface that defines the following value:
-# staticFiles="$C{REST/staticFiles}"
-staticFiles = htdocs:htdocs
-
-# Stylesheet to use for HTML views.
-# Used by the BasicRestConfig interface that defines the following value:
-# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"
-theme = servlet:/htdocs/themes/dark.css
-
-# Various look-and-feel settings used in the BasicRestConfig interface.
-headerIcon = servlet:/htdocs/images/juneau.png
-headerLink = http://juneau.apache.org
-footerIcon = servlet:/htdocs/images/asf.png
-footerLink = http://www.apache.org
-favicon = $C{REST/headerIcon}
-head = <link rel='icon' href='$U{$C{REST/favicon}}'/>
-header =
- <a href='$U{$C{REST/headerLink}}'>
- <img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/>
- </a>
-footer =
- <a href='$U{$C{REST/footerLink}}'>
- <img style='float:right;padding-right:20px;height:32px' src='$U{$C{REST/footerIcon}}'>
- </a>
-
-#=======================================================================================================================
-# SqlQueryResource properties
-#=======================================================================================================================
-[SqlQueryResource]
-driver = org.apache.derby.jdbc.EmbeddedDriver
-directory = target/derby/testDB
-connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true
-allowTempUpdates = true
-includeRowNums = false
-
-#=======================================================================================================================
-# Source code location
-#=======================================================================================================================
-[Source]
-gitHub = https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java
-
-#=======================================================================================================================
-# PetStoreResource properties
-#=======================================================================================================================
-[PetStore]
-headerImage = <a href='http://swagger.io'><img src='$U{servlet:/htdocs/cat.png}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/></a>
diff --git a/juneau-examples/juneau-examples-rest/.gitignore b/juneau-examples/juneau-examples-rest/.gitignore
deleted file mode 100644
index 34acf885cb..0000000000
--- a/juneau-examples/juneau-examples-rest/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/target/
-**/.DS_Store
-.classpath
-.project
-/.settings/
-/bin/
diff --git a/juneau-examples/juneau-examples-rest/pom.xml b/juneau-examples/juneau-examples-rest/pom.xml
deleted file mode 100644
index 449f4c846e..0000000000
--- a/juneau-examples/juneau-examples-rest/pom.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples</artifactId>
- <version>10.0.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>juneau-examples-rest</artifactId>
- <name>Apache Juneau REST Examples</name>
- <description>Apache Juneau REST Examples</description>
- <packaging>bundle</packaging>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <encoding>UTF-8</encoding>
- </properties>
-
- <dependencies>
- <!-- Juneau dependencies -->
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-microservice-jetty</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-rest-server</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples-core</artifactId>
- <version>${project.version}</version>
- </dependency>
-
- <!-- Needed for JPA persistence of PetStore beans -->
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.17.1.0</version>
- </dependency>
-
- <dependency>
- <groupId>jakarta.servlet</groupId>
- <artifactId>jakarta.servlet-api</artifactId>
- <version>6.1.0</version>
- <scope>compile</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <supportIncrementalBuild>true</supportIncrementalBuild>
- </configuration>
- <executions>
- <execution>
- <id>bundle-manifest</id>
- <phase>process-classes</phase>
- <goals>
- <goal>manifest</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-source-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-sources</id>
- <phase>verify</phase>
- <goals>
- <goal>jar-no-fork</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- This runs the _TestSuite class. You must run within the testsuite
- so the REST microservice is started for the tests. -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/_TestSuite.java</include>
- </includes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/META-INF/MANIFEST.MF b/juneau-examples/juneau-examples-rest/src/main/java/META-INF/MANIFEST.MF
deleted file mode 100644
index 5e9495128c..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Class-Path:
-
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AdminGuard.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AdminGuard.java
deleted file mode 100644
index 930b99cc89..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AdminGuard.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.guard.*;
-
-/**
- * Sample guard that only lets administrators through.
- *
- */
-public class AdminGuard extends RestGuard {
-
- @Override /* RestGuard */
- public boolean isRequestAllowed(RestRequest req) {
- return true;
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/HelloWorldResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/HelloWorldResource.java
deleted file mode 100644
index b5e53afe01..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/HelloWorldResource.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.servlet.*;
-
-/**
- * Sample REST resource that prints out a simple "Hello world!" message.
- *
- */
-@Rest(
- title="Hello World",
- description="An example of the simplest-possible resource",
- path="/helloWorld"
-)
-@HtmlDocConfig(
- aside={
- "<div style='max-width:400px' class='text'>",
- "\t<p>This page shows a resource that simply response with a 'Hello world!' message</p>",
- "\t<p>The POJO serialized is a simple String.</p>",
- "</div>"
- }
-)
-public class HelloWorldResource extends BasicRestResource {
-
- /**
- * [HTTP GET /helloworld]
- * Returns a simple string message.
- *
- * @return A simple Hello-World message.
- */
- @RestGet(path = "/*", summary = "Responds with \"Hello world!\"")
- public String sayHello() {
- return "Hello world!";
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/HtmlBeansResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/HtmlBeansResource.java
deleted file mode 100644
index 5705441560..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/HtmlBeansResource.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import static org.apache.juneau.bean.html5.HtmlBuilder.*;
-
-import org.apache.juneau.bean.html5.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.beans.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample resource that allows images to be uploaded and retrieved.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HtmlBeans">Using with HTML Beans</a>
- * </ul>
- */
-@Rest(
- path="/htmlbeans",
- title="HTML bean examples",
- description="Examples of serialized HTML beans."
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "api: servlet:/api",
- "stats: servlet:/stats",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/HtmlBeansResource.java"
- },
- aside={
- "<div class='text'>",
- "\t<p>Examples of serialized HTML beans.</p>",
- "</div>"
- },
- asideFloat="RIGHT"
-)
-public class HtmlBeansResource extends BasicRestResource {
-
- @SuppressWarnings({
- "unused" // serialVersionUID required for Serializable compliance; unused in code paths
- })
- private static final long serialVersionUID = 1L;
-
- /**
- * [HTTP GET /htmlbeans/div]
- * @return An example div tag.
- */
- @RestGet("/div")
- @HtmlDocConfig(
- aside={
- "<div class='text'>",
- "\t<p>Example of serialized div tag.</p>",
- "</div>"
- }
- )
- public HtmlElement aDiv() {
- return div()
- .children(
- p("Juneau supports ", b(i("mixed")), " content!")
- )
- .onmouseover("alert(\"boo!\");");
- }
-
- /**
- * [HTTP GET /htmlbeans/form]
- * @return An example form tag.
- */
- @RestGet("/form")
- @HtmlDocConfig(
- aside={
- "<div class='text'>",
- "\t<p>Example of serialized HTML form.</p>",
- "</div>"
- }
- )
- public Form aForm() {
- return form().action("/submit").method("POST")
- .children(
- "Position (1-10000): ", input("number").name("pos").value(1), br(),
- "Limit (1-10000): ", input("number").name("limit").value(100), br(),
- button("submit", "Submit"),
- button("reset", "Reset")
- );
- }
-
- /**
- * [HTTP GET /htmlbeans/table]
- * @return An example table.
- */
- @RestGet("/table")
- @HtmlDocConfig(
- aside={
- "<div class='text'>",
- "\t<p>Example of serialized table.</p>",
- "</div>"
- }
- )
- public Table aTable() {
- return table(
- tr(
- th("c1"),
- th("c2")
- ),
- tr(
- td("v1"),
- td("v2")
- )
- );
- }
-
- /**
- * [HTTP GET /htmlbeans]
- * @return Descriptive links to the child endpoints.
- */
- @RestGet("/")
- public ResourceDescriptions getChildDescriptions() {
- return ResourceDescriptions
- .create()
- .append("table", "Example of a serialized table")
- .append("div", "Example of a serialized div tag")
- .append("form", "Example of a serialized form");
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
deleted file mode 100644
index c2f77b1d24..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import java.awt.image.*;
-import java.net.*;
-import java.util.*;
-import java.util.concurrent.*;
-
-import org.apache.juneau.examples.parser.*;
-import org.apache.juneau.examples.serializer.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.http.classic.response.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample resource that allows images to be uploaded and retrieved.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a>
- * <li class='jc'>{@link ImageSerializer}
- * <li class='jc'>{@link ImageParser}
- * </ul>
- */
-@Rest(
- path="/photos",
- messages="nls/PhotosResource",
- title="Photo REST service",
- description="Use a tool like Poster to upload and retrieve jpeg and png images."
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "api: servlet:/api",
- "stats: servlet:/stats",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/PhotosResource.java"
- },
- aside={
- "<div class='text'>",
- "\t<p>Examples of serialized beans in the org.apache.juneau.rest.server.utilitybeans package.</p>",
- "</div>"
- },
- asideFloat="RIGHT"
-)
-public class PhotosResource extends BasicRestServlet {
-
- /** Bean class for storing photos */
- public static class Photo {
- private int id;
- BufferedImage image;
-
- Photo(int id, BufferedImage image) {
- this.id = id;
- this.image = image;
- }
-
- /**
- * The photo ID
- *
- * @return The photo ID.
- */
- public int getID() { return id; }
-
- /**
- * The photo URL.
- *
- * @return The photo URL.
- */
- public URI getURI() {
- try {
- return new URI("photos/" + id);
- } catch (URISyntaxException e) {
- throw new IllegalStateException(e); // Shouldn't happen.
- }
- }
- }
-
- private static final long serialVersionUID = 1L;
-
- /** Photo cache. Static - shared by all requests (singleton servlet). */
- private static final Map<Integer,Photo> photos = new ConcurrentHashMap<>();
-
- /**
- * [HTTP PUT /photos/{id}]
- * PUT request handler.
- *
- * @param id The photo ID.
- * @param image The photo image.
- * @return OK.
- */
- @RestPut(path = "/{id}", parsers = ImageParser.class)
- public Ok addPhoto(@Path("id") int id, @Content BufferedImage image) {
- photos.put(id, new Photo(id, image));
- return Ok.OK;
- }
-
- /**
- * [HTTP DELETE /photos/{id}]
- * DELETE request handler
- *
- * @param id The photo ID.
- * @return OK.
- * @throws NotFound If photo not found.
- */
- @RestDelete("/{id}")
- public Ok deletePhoto(@Path("id") int id) throws NotFound {
- var p = photos.remove(id);
- if (p == null)
- throw new NotFound("Photo not found");
- return Ok.OK;
- }
-
- /**
- * [HTTP GET /photos]
- * GET request handler for list of all photos.
- *
- * @return A list of photo beans.
- */
- @RestGet("/")
- public Collection<Photo> getAllPhotos() { return photos.values(); }
-
- /**
- * [HTTP GET /photos/{id}]
- * GET request handler for single photo.
- *
- * @param id The photo ID.
- * @return The photo image.
- * @throws NotFound If photo not found.
- */
- @RestGet(path = "/{id}", serializers = ImageSerializer.class)
- public BufferedImage getPhoto(@Path("id") int id) throws NotFound {
- var p = photos.get(id);
- if (p == null)
- throw new NotFound("Photo not found");
- return p.image;
- }
-
- /**
- * [HTTP POST /photos]
- * POST request handler.
- *
- * @param image The photo image.
- * @return The created photo bean.
- */
- @RestPost(path = "/", parsers = ImageParser.class)
- public Photo setPhoto(@Content BufferedImage image) {
- int id = photos.size();
- var p = new Photo(id, image);
- photos.put(id, p);
- return p;
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
deleted file mode 100644
index eb021737bb..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import org.apache.juneau.commons.*;
-import org.apache.juneau.commons.bean.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.converter.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-import jakarta.servlet.*;
-import jakarta.servlet.http.*;
-
-/**
- * Sample REST resource for echoing HttpServletRequests back to the browser.
- *
- */
-@Rest(
- path="/echo",
- title="Request echo service",
- description="Echos the current HttpServletRequest object back to the browser.",
- swagger=@Swagger(
- contact=@Contact(name="Juneau Developer",email="dev@juneau.apache.org"),
- license=@License(name="Apache 2.0",url="http://www.apache.org/licenses/LICENSE-2.0.html"),
- version="2.0",
- termsOfService="You are on your own.",
- externalDocs=@ExternalDocs(description="Apache Juneau",url="http://juneau.apache.org")
- )
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "api: servlet:/api",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/RequestEchoResource.java"
- },
- aside={
- "<div style='max-width:400px;min-width:200px' class='text'>",
- "\t<p>Shows how even arbitrary POJOs such as <c>HttpServletRequest</c> can be serialized by the framework.</p>",
- "\t<p>Also shows how to specify serializer properties, filters, and swaps at the servlet level to control how POJOs are serialized.</p>",
- "\t<p>Also provides an example of how to use the Traversable and Queryable APIs.</p>",
- "</div>"
- },
- nowrap="false"
-)
-@SerializerConfig(
- maxDepth="5",
- detectRecursions="true"
-)
-@BeanTypeApply(on="HttpServletRequest",value=@BeanType(interfaceClass=HttpServletRequest.class))
-@BeanTypeApply(on="HttpSession",value=@BeanType(interfaceClass=HttpSession.class))
-@BeanTypeApply(on="ServletContext",value=@BeanType(interfaceClass=ServletContext.class))
-public class RequestEchoResource extends BasicRestResource {
-
- /**
- * [HTTP GET /echo/*]
- * GET request handler.
- *
- * @param req The HTTP servlet request.
- * @return The same request to serialize as the response.
- */
- @RestOp(method = "*", path = "/*", converters = { Traversable.class, Queryable.class }, summary = "Serializes the incoming HttpServletRequest object.")
- public HttpServletRequest doGet(RestRequest req) {
- // Just echo the request back as the response.
- return req.getHttpServletRequest();
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SseDemoResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SseDemoResource.java
deleted file mode 100644
index 263dd2036a..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SseDemoResource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import static org.apache.juneau.commons.utils.Utils.*;
-
-import java.io.*;
-import java.time.*;
-import java.time.format.*;
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.*;
-
-import org.apache.juneau.marshall.sse.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.sse.*;
-
-/**
- * Sample REST resource that emits a stream of Server-Sent Events.
- *
- * <p>
- * The {@link #stream()} endpoint returns a lazy {@link Iterable} of {@link SseEvent} objects whose
- * iterator sleeps {@value #SLEEP_MILLIS} milliseconds between calls to {@code next()}. Combined with the
- * per-event {@code Writer.flush()} performed by {@link SseSerializer}, this allows the per-event
- * arrival timing to be observed with a streaming HTTP client such as {@code curl -N}.
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode'>
- * $ curl -N -H 'Accept: text/event-stream' http://localhost:10000/sseDemo/stream
- * event: tick-1
- * data: 2026-05-20T11:08:00.123Z
- *
- * event: tick-2
- * data: 2026-05-20T11:08:00.624Z
- * ...
- * </p>
- */
-@Rest(
- path = "/sseDemo",
- title = "SSE demo",
- description = "Emits a stream of Server-Sent Events with a short delay between events."
-)
-public class SseDemoResource extends BasicRestResource {
-
- private static final int EVENT_COUNT = 10;
- private static final long SLEEP_MILLIS = 500L;
-
- /**
- * Streams {@value #EVENT_COUNT} SSE events with a {@value #SLEEP_MILLIS}-ms delay between
- * successive events. Each event carries a UTC timestamp in its {@code data:} field so that
- * per-event flush behavior is observable from the client's wall clock.
- *
- * @return A lazy iterable of {@link SseEvent} objects.
- */
- @RestGet(path = "/stream", serializers = SseSerializer.class)
- public Iterable<SseEvent> stream() {
- return () -> new Iterator<>() {
- private int i = 0;
-
- @Override
- public boolean hasNext() {
- return i < EVENT_COUNT;
- }
-
- @Override
- public SseEvent next() {
- if (i >= EVENT_COUNT)
- throw new NoSuchElementException();
- if (i > 0) {
- try {
- Thread.sleep(SLEEP_MILLIS);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException("Interrupted while sleeping between SSE events", e);
- }
- }
- i++;
- var ts = DateTimeFormatter.ISO_INSTANT.format(Instant.now());
- return new SseEvent("tick-" + i, ts).setId(String.valueOf(i));
- }
- };
- }
-
- /**
- * Demonstrates server-side broadcaster fan-out with heartbeat comments.
- *
- * @param req The request.
- * @param res The response.
- * @param broadcaster The broadcaster bean.
- * @throws IOException If the response write fails.
- */
- @RestGet(path = "/broadcast", serializers = SseSerializer.class)
- @SuppressWarnings({
- "resource" // Scheduler is explicitly shutdown in finally; subscription/SSE support are closed via try-with-resources.
- })
- public void broadcast(RestRequest req, RestResponse res, SseBroadcaster broadcaster) throws IOException {
- var id = opt(req.getHttpServletRequest().getRequestId()).orElse(UUID.randomUUID().toString());
- var counter = new AtomicInteger();
- var scheduler = Executors.newSingleThreadScheduledExecutor();
- ScheduledFuture<?> task = null;
- try (var subscription = broadcaster.subscribe(id); var sse = res.sse().heartbeat(Duration.ofSeconds(15))) {
- task = scheduler.scheduleAtFixedRate(() -> {
- var i = counter.incrementAndGet();
- var ts = DateTimeFormatter.ISO_INSTANT.format(Instant.now());
- broadcaster.publish(new SseEvent("tick-" + i, ts).setId(String.valueOf(i)));
- if (i >= EVENT_COUNT)
- subscription.close();
- }, 0, SLEEP_MILLIS, TimeUnit.MILLISECONDS);
- sse.sendFrom(subscription);
- } finally {
- if (task != null)
- task.cancel(true);
- scheduler.shutdownNow();
- }
- }
-}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UtilityBeansResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UtilityBeansResource.java
deleted file mode 100644
index e4bc820bc4..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UtilityBeansResource.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.juneau.examples.rest;
-
-import org.apache.juneau.commons.bean.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.beans.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample resource that allows images to be uploaded and retrieved.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/UtilityBeans">Utility Beans</a>
- * </ul>
- */
-@Rest(
- path="/utilitybeans",
- title="Utility beans examples",
- description="Examples of utility bean usage."
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "api: servlet:/api",
- "stats: servlet:/stats",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/UtilityBeansResource.java"
- },
- aside={
- "<div class='text'>",
- "\t<p>Examples of serialized beans in the org.apache.juneau.rest.server.utilitybeans package.</p>",
- "</div>"
- },
- asideFloat="RIGHT"
-)
-public class UtilityBeansResource extends BasicRestResource {
-
- /**
- * Sample address bean used for demonstrating utility bean functionality.
- */
- @SuppressWarnings({
- "java:S1104" // All public fields intentional for direct bean serialization in REST example demonstrations
- })
- @BeanType(p = "street,city,state,zip,isCurrent")
- public static class Address {
-
- /** Street address. */
- public String street;
-
- /** City name. */
- public String city;
-
- /** State abbreviation. */
- public String state;
-
- /** ZIP code. */
- public int zip;
-
- /** Whether this is the current address. */
- public boolean isCurrent;
-
- /** Default constructor. */
- public Address() {
- // No-op: Test helper class - intentionally empty for testing
- }
- }
-
- @SuppressWarnings({
- "unused" // serialVersionUID required for Serializable compliance; unused in code paths
- })
- private static final long serialVersionUID = 1L;
-
- /**
- * [HTTP GET /utilitybeans/BeanDescription]
- * @return Example of serialized org.apache.juneau.rest.server.utilitybeans.ResourceDescriptions bean.
- */
- @RestGet("/BeanDescription")
- @HtmlDocConfig(
- aside={
- "<div class='text'>",
- "\t<p>Example of serialized ResourceDescriptions bean.</p>",
- "</div>"
- }
- )
- public BeanDescription aBeanDescription() {
- return BeanDescription.of(Address.class);
- }
-
- /**
- * [HTTP GET /utilitybeans/Hyperlink]
- * @return Example of serialized org.apache.juneau.rest.server.utilitybeans.Hyperlink bean.
- */
- @RestGet("/Hyperlink")
- @HtmlDocConfig(
- aside={
- "<div class='text'>",
- "\t<p>Example of serialized Hyperlink bean.</p>",
- "</div>"
- }
- )
- public Hyperlink aHyperlink() {
- return Hyperlink.create("/utilitybeans", "Back to /utilitybeans");
- }
-
- /**
- * [HTTP GET /utilitybeans/SeeOtherRoot]
- * @return Example of serialized SeeOtherRoot bean.
- * This just redirects back to the servlet root.
- */
- @RestGet("/SeeOtherRoot")
- @HtmlDocConfig(
- aside={
- "<div class='text'>",
- "\t<p>Example of serialized org.apache.juneau.rest.server.utilitybeans.SeeOtherRoot bean.</p>",
- "</div>"
- }
- )
- public SeeOtherRoot aSeeOtherRoot() {
- return SeeOtherRoot.INSTANCE;
- }
-
- /**
- * [HTTP GET /utilitybeans]
- * @return Descriptive links to the child endpoints.
- */
- @RestGet("/")
- public ResourceDescriptions getChildDescriptions() {
- return ResourceDescriptions
- .create()
- .append("BeanDescription", "Example of BeanDescription bean")
- .append("Hyperlink", "Example of Hyperlink bean")
- .append("SeeOtherRoot", "Example of SeeOtherRoot bean");
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/EchoCommand.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/EchoCommand.java
deleted file mode 100644
index cc4aea56b8..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/EchoCommand.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.juneau.examples.rest.command;
-
-import java.io.*;
-import java.util.*;
-
-import org.apache.juneau.commons.runtime.*;
-import org.apache.juneau.microservice.console.*;
-
-/**
- * Implements an 'echo' console command that simply returns the command arguments as a comma-delimited list.
- *
- */
-public class EchoCommand extends ConsoleCommand {
-
- @Override /* ConsoleCommand */
- public boolean execute(Scanner in, PrintWriter out, Args args) {
- out.println("positional=" + args.positional() + ", options=" + args.asMap());
- return false;
- }
-
- @Override /* ConsoleCommand */
- public String getDescription() { return "Simply prints the positional arguments and named options of the command."; }
-
- @Override /* ConsoleCommand */
- public String getInfo() { return "Echo command"; }
-
- @Override /* ConsoleCommand */
- public String getName() { return "echo"; }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/AtomFeedResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/AtomFeedResource.java
deleted file mode 100644
index 03bd29bd05..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/AtomFeedResource.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.juneau.examples.rest.dto;
-
-import static org.apache.juneau.bean.atom.AtomBuilder.*;
-
-import java.net.*;
-
-import org.apache.juneau.bean.atom.*;
-import org.apache.juneau.commons.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.http.Content;
-import org.apache.juneau.marshall.encoders.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample resource that shows how to generate ATOM feeds.
- *
- *
- * @serial exclude
- */
-@Rest(
- path="/atom",
- title="Sample ATOM feed resource",
- description="Sample resource that shows how to render ATOM feeds",
- encoders=GzipEncoder.class,
- swagger=@Swagger(
- contact=@Contact(name="Juneau Developer",email="dev@juneau.apache.org"),
- license=@License(name="Apache 2.0",url="http://www.apache.org/licenses/LICENSE-2.0.html"),
- version="2.0",
- termsOfService="You are on your own.",
- externalDocs=@ExternalDocs(description="Apache Juneau",url="http://juneau.apache.org")
- )
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "api: servlet:/api",
- "stats: servlet:/stats",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/dto/AtomFeedResource.java"
- }
-)
-@SerializerConfig(
- quoteChar="'"
-)
-@SuppressWarnings({
- "java:S115" // Constants use UPPER_snakeCase convention (e.g., CONST_timestamp)
-})
-public class AtomFeedResource extends BasicRestServlet {
- private static final long serialVersionUID = 1L;
-
- private static final String CONST_timestamp = "2016-12-31T05:02:03Z";
- private static final String EXAMPLE_URL_FOO_ORG = "http://foo.org/";
- private static final String EXAMPLE_URL_WWW_FOO_ORG = "http://www.foo.org/";
-
- private transient Feed feed; // The root resource object
-
- /**
- * [HTTP GET /dto/atom]
- * Get the sample ATOM feed
- *
- * @return The sample ATOM feed.
- */
- @RestGet(summary = "Get the sample ATOM feed")
- public Feed get() {
- return feed;
- }
-
- @Override /* Servlet */
- public void init() {
- try {
- feed =
- feed("tag:foo.org", "Title", CONST_timestamp)
- .setSubtitle(text("html").setText("Subtitle"))
- .setLinks(
- link("alternate", "text/html", EXAMPLE_URL_FOO_ORG).setHreflang("en"),
- link("self", "application/atom+xml", "http://foo.org/feed.atom")
- )
- .setGenerator(
- generator("Example Toolkit").setUri(EXAMPLE_URL_WWW_FOO_ORG).setVersion("1.0")
- )
- .setEntries(
- entry("tag:foo.org", "Title", CONST_timestamp)
- .setLinks(
- link("alternate", "text/html", "http://foo.org/2005/04/02/atom"),
- link("enclosure", "audio/mpeg", "http://foo.org/audio/foobar.mp3").setLength(1337)
- )
- .setPublished(CONST_timestamp)
- .setAuthors(
- person("John Smith").setUri(new URI(EXAMPLE_URL_FOO_ORG)).setEmail("foo@foo.org")
- )
- .setContributors(
- person("John Smith"),
- person("Jane Smith")
- )
- .setContent(
- content("xhtml")
- .setLang("en")
- .setBase(EXAMPLE_URL_FOO_ORG)
- .setText("<div><p><i>[Sample content]</i></p></div>")
- )
- );
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * [HTTP PUT /dto/atom]
- * Overwrite the sample ATOM feed
- *
- * @param feed The new ATOM feed.
- * @return The updated ATOM feed.
- */
- @RestPut(summary = "Overwrite the sample ATOM feed", description = "Replaces the feed with the specified content, and then mirrors it as the response.")
- public Feed put(@Content Feed feed) {
- this.feed = feed;
- return feed;
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/DtoExamples.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/DtoExamples.java
deleted file mode 100644
index d44a6a7362..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/DtoExamples.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.juneau.examples.rest.dto;
-
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.marshall.serializer.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample REST resource showing how to implement a nested "router" resource page.
- *
- *
- * @serial exclude
- */
-@Rest(
- path="/dto",
- title="DTO examples",
- description="Example serialization of predefined Data Transfer Objects.",
- children={
- AtomFeedResource.class,
- JsonSchemaResource.class
- }
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "api: servlet:/api",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/dto/DtoExamples.java"
- },
- aside={
- "<div style='max-width:400px' class='text'>",
- "\t<p>This is an example of a nested 'router' page that serves as a jumping-off point to other child resources.</p>",
- "</div>"
- }
-)
-@SerializerConfig(
- // For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
- // String comparisons.
- // You can apply any of the Serializer/Parser/MarshallingContext settings this way.
- quoteChar="'"
-)
-@SuppressWarnings({
- "java:S110" // Inheritance depth acceptable for example/demo code
-})
-public class DtoExamples extends BasicRestServletGroup {
- private static final long serialVersionUID = 1L;
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/JsonSchemaResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/JsonSchemaResource.java
deleted file mode 100644
index 842fdd3f50..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/JsonSchemaResource.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.juneau.examples.rest.dto;
-
-import org.apache.juneau.bean.jsonschema.*;
-import org.apache.juneau.commons.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.html.*;
-import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.servlet.*;
-import org.apache.juneau.rest.server.widget.*;
-
-/**
- * Sample resource that shows how to serialize JSON-Schema documents.
- *
- *
- * @serial exclude
- */
-@Rest(
- path="/jsonSchema",
- messages="nls/JsonSchemaResource",
- title="Sample JSON-Schema document",
- description="Sample resource that shows how to generate JSON-Schema documents",
- swagger=@Swagger(
- contact=@Contact(name="Juneau Developer",email="dev@juneau.apache.org"),
- license=@License(name="Apache 2.0",url="http://www.apache.org/licenses/LICENSE-2.0.html"),
- version="2.0",
- termsOfService="You are on your own.",
- externalDocs=@ExternalDocs(description="Apache Juneau",url="http://juneau.apache.org")
- )
-)
-@HtmlDocConfig(
- widgets={
- ContentTypeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "api: servlet:/api",
- "stats: servlet:/stats",
- "$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/dto/JsonSchemaResource.java"
- },
- aside={
- "<div style='min-width:200px' class='text'>",
- "\t<p>Shows how to produce JSON-Schema documents in a variety of languages using the JSON-Schema DTOs.</p>",
- "</div>"
- }
-)
-@MarshalledApply(on="Schema",value=@Marshalled(example="$F{JsonSchemaResource_example.json}"))
-public class JsonSchemaResource extends BasicRestServlet {
- private static final long serialVersionUID = 1L;
-
- private transient JsonSchema schema; // The schema document
-
- /**
- * [HTTP GET /dto/jsonSchema]
- * Get the JSON-Schema document.
- *
- * @return The JSON-Schema document.
- */
- @RestGet(summary = "Get the JSON-Schema document")
- public JsonSchema get() {
- return schema;
- }
-
- @SuppressWarnings({
- "removal" // Uses deprecated Schema annotation for example compatibility
- })
- @Override /* Servlet */
- public void init() {
-
- try {
- schema = new JsonSchema()
- .setId("http://example.com/sample-schema#")
- .setSchemaVersionUri("http://json-schema.org/draft-04/schema#")
- .setTitle("Example Schema")
- .setType(JsonType.OBJECT)
- .addProperties(
- new JsonSchemaProperty("firstName", JsonType.STRING),
- new JsonSchemaProperty("lastName", JsonType.STRING),
- new JsonSchemaProperty("age", JsonType.INTEGER)
- .setDescription("Age in years")
- .setMinimum(0)
- )
- .addRequired("firstName", "lastName");
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * [HTTP PUT /dto/jsonSchema]
- * Overwrite the JSON-Schema document
- *
- * @param schema The new schema document.
- * @return The updated schema document.
- */
- @RestPut(summary = "Overwrite the JSON-Schema document", description = "Replaces the schema document with the specified content, and then mirrors it as the response.")
- public JsonSchema put(@Content JsonSchema schema) {
- this.schema = schema;
- return schema;
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/AtomFeedResource_example.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/AtomFeedResource_example.json
deleted file mode 100644
index e4c0e51262..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/AtomFeedResource_example.json
+++ /dev/null
@@ -1,86 +0,0 @@
-// ***************************************************************************************************************************
-// * 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. *
-// ***************************************************************************************************************************
-{
- id: {
- text: 'tag:juneau.sample.com,2013:1'
- },
- title: {
- text: 'Juneau ATOM specification'
- },
- links: [
- {
- type: 'text/html',
- href: 'http://www.sample.com/',
- hreflang: 'en',
- rel: 'alternate'
- },
- {
- type: 'application/atom+xml',
- href: 'http://www.sample.com/feed.atom',
- rel: 'self'
- }
- ],
- updated: '2013-05-08T12:29:29Z',
- entries: [
- {
- id: {
- text: 'tag:juneau.sample.com,2013:1.2345'
- },
- title: {
- text: 'Juneau ATOM specification snapshot'
- },
- links: [
- {
- type: 'text/html',
- href: 'http://www.sample.com/2012/05/08/juneau.atom',
- rel: 'alternate'
- },
- {
- type: 'audio/mpeg',
- length: 1337,
- href: 'http://www.sample.com/audio/juneau_podcast.mp3',
- rel: 'enclosure'
- }
- ],
- authors: [
- {
- name: 'James Bognar',
- uri: 'http://www.sample.com/',
- email: 'jamesbognar@apache.org'
- }
- ],
- contributors: [
- {
- name: 'Barry M. Caceres'
- }
- ],
- updated: '2013-05-08T12:29:29Z',
- content: {
- base: 'http://www.apache.org/',
- lang: 'en',
- type: 'xhtml',
- text: '<div><p>[Update: Juneau supports ATOM.]</p></div>'
- },
- published: '2013-05-08T12:29:29Z'
- }
- ],
- generator: {
- version: '1.0',
- uri: 'http://juneau.apache.org/',
- text: 'Juneau'
- },
- subtitle: {
- type: 'html',
- text: 'A <em>lot</em> of effort went into making this effortless'
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/JsonSchemaResource_example.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/JsonSchemaResource_example.json
deleted file mode 100644
index d5bdc9527a..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/JsonSchemaResource_example.json
+++ /dev/null
@@ -1,35 +0,0 @@
-// ***************************************************************************************************************************
-// * 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. *
-// ***************************************************************************************************************************
-{
- id: 'http://example.com/sample-schema#',
- '$schema': 'http://json-schema.org/draft-04/schema#',
- title: 'Example Schema',
- type: 'object',
- properties: {
- firstName: {
- type: 'string'
- },
- lastName: {
- type: 'string'
- },
- age: {
- description: 'Age in years',
- type: 'integer',
- minimum: 0
- }
- },
- required: [
- 'firstName',
- 'lastName'
- ]
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png
deleted file mode 100644
index 31d84f728a..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/ok.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png
deleted file mode 100644
index 7b71e143fa..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/severe.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png
deleted file mode 100644
index 7a8ab4909c..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/warning.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem_beforeShow.js b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem_beforeShow.js
deleted file mode 100644
index bb7d703852..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem_beforeShow.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- ***************************************************************************************************************************
- * 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. *
- ***************************************************************************************************************************
-*/
-
-/* Populates the list of pets on the add-order menu item. */
-const xhr = new XMLHttpRequest();
-xhr.open('GET', '/petstore/pet?s=status=AVAILABLE&v=id,name', true);
-xhr.setRequestHeader('Accept', 'application/json');
-xhr.onload = function() {
- const pets = JSON.parse(xhr.responseText);
- const select = document.getElementById('addPet_names');
- select.innerHTML = '';
- for (const i in pets) {
- const pet = pets[i];
- const opt = document.createElement('option');
- opt.value = pet.id;
- opt.innerHTML = pet.name;
- select.appendChild(opt);
- }
-}
-xhr.send();
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/PetStoreResource.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/PetStoreResource.json
deleted file mode 100644
index 780c654151..0000000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/PetStoreResource.json
+++ /dev/null
@@ -1,75 +0,0 @@
-// ***************************************************************************************************************************
-// * 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. *
-// ***************************************************************************************************************************
-
-{
- "swagger": "2.0",
- "info": {
- "version": "1.0.0",
- "title": "Swagger Petstore",
- "termsOfService": "You are on your own.",
- "contact": {
- "name": "Juneau Development Team",
- "email": "dev@juneau.apache.org",
- "url": "http://juneau.apache.org"
- },
- "license": {
- "name": "Apache 2.0",
- "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
- }
- },
- "externalDocs": {
- "description": "Find out more about Juneau",
- "url": "http://juneau.apache.org"
- },
- "tags": [
- {
- "name": "pet",
- "description": "Everything about your Pets",
- "externalDocs": {
- "description": "Find out more",
- "url": "http://juneau.apache.org"
- }
- },
- {
- "name": "store",
- "description": "Access to Petstore orders"
- },
- {
- "name": "user",
- "description": "Operations about user",
- "externalDocs": {
- "description": "Find out more about our store",
- "url": "http://juneau.apache.org"
- }
- }
- ],
- "schemes": [
- "http"
- ],
- "securityDefinitions": {
- "petstore_auth": {
- "type": "oauth2",
- "authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
- "flow": "implicit",
- "scopes": {
- "write:pets": "modify pets in your account",
- "read:pets": "read your pets"
- }
- },
- "api_key": {
- "type": "apiKey",
- "name": "api_key",
- "in": "header"
- }
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/background.jpg b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/background.jpg
deleted file mode 100644
index d75bcf13b6..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/background.jpg and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/bird.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/bird.png
deleted file mode 100644
index 636ecf81dc..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/bird.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/cat.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/cat.png
deleted file mode 100644
index 917abc616a..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/cat.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/dog.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/dog.png
deleted file mode 100644
index e100eb269e..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/dog.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/fish.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/fish.png
deleted file mode 100644
index ca76a46af9..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/fish.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/mouse.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/mouse.png
deleted file mode 100644
index 53080064c0..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/mouse.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/rabbit.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/rabbit.png
deleted file mode 100644
index f0134703da..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/rabbit.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/snake.png b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/snake.png
deleted file mode 100644
index 7f176609ce..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/htdocs/snake.png and /dev/null differ
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/photos/cat.jpg b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/photos/cat.jpg
deleted file mode 100644
index d75bcf13b6..0000000000
Binary files a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/rest/photos/cat.jpg and /dev/null differ
diff --git a/juneau-examples/pom.xml b/juneau-examples/pom.xml
index 0a316e6a73..44e4b9176e 100644
--- a/juneau-examples/pom.xml
+++ b/juneau-examples/pom.xml
@@ -32,10 +32,6 @@
<modules>
<module>juneau-examples-core</module>
- <module>juneau-examples-rest</module>
- <module>juneau-examples-rest-jetty</module>
- <module>juneau-examples-rest-springboot</module>
- <module>juneau-examples-rest-jetty-ftest</module>
</modules>
<build>
diff --git a/juneau-examples/juneau-examples-rest-jetty-ftest/pom.xml b/juneau-petstore/juneau-petstore-core/pom.xml
similarity index 52%
rename from juneau-examples/juneau-examples-rest-jetty-ftest/pom.xml
rename to juneau-petstore/juneau-petstore-core/pom.xml
index d9d79dce26..902784401a 100644
--- a/juneau-examples/juneau-examples-rest-jetty-ftest/pom.xml
+++ b/juneau-petstore/juneau-petstore-core/pom.xml
@@ -21,30 +21,54 @@
<parent>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples</artifactId>
+ <artifactId>juneau-petstore</artifactId>
<version>10.0.0-SNAPSHOT</version>
</parent>
- <artifactId>juneau-examples-rest-jetty-ftest</artifactId>
- <name>Apache Juneau REST Jetty Functional Tests</name>
- <description>Apache Juneau REST Example Function Tests</description>
+ <artifactId>juneau-petstore-core</artifactId>
+ <name>Apache Juneau Petstore Core</name>
+ <description>Apache Juneau Petstore - shared domain model and REST resources</description>
+ <packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
-
<dependencies>
<dependency>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples-rest-jetty</artifactId>
+ <artifactId>juneau-rest-server</artifactId>
<version>${project.version}</version>
</dependency>
+
+ <!--
+ View-engine bridges (pure-classpath: render identically under Jetty AND Spring Boot's
+ embedded container, giving the petstore deployment-parity for the view-demo surface).
+ Bridge modules only ship engine APIs in `provided` scope, so each engine dep is declared
+ explicitly here.
+ -->
<dependency>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-rest-server</artifactId>
+ <artifactId>juneau-rest-server-view-mustache</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.github.spullara.mustache.java</groupId>
+ <artifactId>compiler</artifactId>
+ <version>0.9.14</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-rest-server-view-freemarker</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.34</version>
+ </dependency>
+
+ <!-- Test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
@@ -52,9 +76,28 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.junit.vintage</groupId>
- <artifactId>junit-vintage-engine</artifactId>
- <version>${junit.version}</version>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-junit5</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-rest-mock</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-bct</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
</dependency>
</dependencies>
@@ -62,14 +105,20 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>
- **/_TestSuite.java
- </include>
- </includes>
- </configuration>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/auth/StubBearerTokenValidator.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/auth/StubBearerTokenValidator.java
new file mode 100644
index 0000000000..3fa399f9d8
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/auth/StubBearerTokenValidator.java
@@ -0,0 +1,75 @@
+/*
+ * 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.juneau.petstore.auth;
+
+import java.security.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.apache.juneau.rest.server.auth.*;
+
+/**
+ * Stub {@link TokenValidator} for the petstore demo — recognises an in-memory map of opaque bearer tokens.
+ *
+ * <p>
+ * <b>NOT FOR PRODUCTION USE.</b> This is a sample/demo validator that maps fixed token strings to fixed user
+ * principals. Real deployments should plug in {@code JwtTokenValidator} from {@code juneau-rest-server-auth-jwt}
+ * (signed JWTs against a JWKS), an opaque-token store backed by a database, or RFC 7662 introspection.
+ *
+ * <p>
+ * Default token table:
+ * <ul>
+ * <li>{@code petstore-user} → principal {@code "alice"}
+ * <li>{@code petstore-admin} → principal {@code "admin"}
+ * </ul>
+ *
+ * <p>
+ * Other token strings throw {@link AuthenticationException} carrying a {@code WWW-Authenticate: Bearer realm="petstore"}
+ * challenge — the {@code AuthFilterChain} in turn returns {@code 401}.
+ */
+public class StubBearerTokenValidator implements TokenValidator {
+
+ /** Default in-memory token table. */
+ public static final Map<String,String> DEFAULT_TOKENS = Map.of(
+ "petstore-user", "alice",
+ "petstore-admin", "admin"
+ );
+
+ private final Map<String,String> tokenToUser;
+
+ /** Constructor using the {@link #DEFAULT_TOKENS} table. */
+ public StubBearerTokenValidator() {
+ this(DEFAULT_TOKENS);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param tokenToUser Map of token string to principal name. Copied defensively.
+ */
+ public StubBearerTokenValidator(Map<String,String> tokenToUser) {
+ this.tokenToUser = new ConcurrentHashMap<>(Objects.requireNonNull(tokenToUser, "tokenToUser"));
+ }
+
+ @Override
+ public Principal validate(String token) throws AuthenticationException {
+ var name = tokenToUser.get(token);
+ if (name == null)
+ throw new AuthenticationException("Unknown bearer token").wwwAuthenticate("Bearer realm=\"petstore\"");
+ return () -> name;
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/auth/package-info.java
old mode 100755
new mode 100644
similarity index 62%
copy from juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/auth/package-info.java
index 0ba233d284..34727536f3
--- a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/auth/package-info.java
@@ -15,11 +15,12 @@
* limitations under the License.
*/
/**
- * REST Jetty Examples
+ * Petstore auth helpers — stub validators and other glue used by the deployment-side
+ * {@code AuthFilterChain} configurations.
*
* <p>
- * Example classes demonstrating how to deploy Juneau REST servers using Jetty.
- * These examples show various Jetty-based REST API deployment scenarios.
- * </p>
+ * The core ships only deployment-agnostic validators (e.g. {@link org.apache.juneau.petstore.auth.StubBearerTokenValidator}).
+ * Each deployment ({@code juneau-petstore-jetty}, {@code juneau-petstore-springboot}) wires its own
+ * {@code AuthFilterChain} bean composing these validators with the appropriate filter mounts.
*/
-package org.apache.juneau.examples.rest.jetty;
+package org.apache.juneau.petstore.auth;
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Order.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Order.java
new file mode 100644
index 0000000000..9cb4344f15
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Order.java
@@ -0,0 +1,115 @@
+/*
+ * 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.juneau.petstore.dto;
+
+/**
+ * Order domain bean.
+ *
+ * <p>
+ * Represents an order placed against a {@link Pet}.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+public class Order {
+
+ private long id;
+ private long petId;
+ private String shipDate;
+ private OrderStatus status;
+
+ /**
+ * Returns the order ID.
+ *
+ * @return The order ID.
+ */
+ public long getId() {
+ return id;
+ }
+
+ /**
+ * Sets the order ID.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Order setId(long value) {
+ id = value;
+ return this;
+ }
+
+ /**
+ * Returns the ID of the pet being ordered.
+ *
+ * @return The ID of the pet being ordered.
+ */
+ public long getPetId() {
+ return petId;
+ }
+
+ /**
+ * Sets the ID of the pet being ordered.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Order setPetId(long value) {
+ petId = value;
+ return this;
+ }
+
+ /**
+ * Returns the shipping date as an ISO 8601 string.
+ *
+ * @return The shipping date as an ISO 8601 string. Can be <jk>null</jk>.
+ */
+ public String getShipDate() {
+ return shipDate;
+ }
+
+ /**
+ * Sets the shipping date.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public Order setShipDate(String value) {
+ shipDate = value;
+ return this;
+ }
+
+ /**
+ * Returns the lifecycle status of the order.
+ *
+ * @return The lifecycle status of the order.
+ */
+ public OrderStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the lifecycle status of the order.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Order setStatus(OrderStatus value) {
+ status = value;
+ return this;
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java
old mode 100755
new mode 100644
similarity index 74%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java
index dd83076900..f4715ad3b7
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java
@@ -14,12 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.petstore.dto;
+
/**
- * REST Command Examples
- *
- * <p>
- * Example classes demonstrating how to use command pattern with Juneau's REST server.
- * These examples show various command-based REST API scenarios.
- * </p>
+ * Lifecycle status of an {@link Order}.
*/
-package org.apache.juneau.examples.rest.command;
+public enum OrderStatus {
+
+ /** Order has been placed but not yet approved. */
+ PLACED,
+
+ /** Order has been approved for shipment. */
+ APPROVED,
+
+ /** Order has been delivered. */
+ DELIVERED
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Pet.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Pet.java
new file mode 100644
index 0000000000..322472c5ba
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Pet.java
@@ -0,0 +1,180 @@
+/*
+ * 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.juneau.petstore.dto;
+
+import java.util.*;
+
+/**
+ * Pet domain bean.
+ *
+ * <p>
+ * Represents a pet for sale in the petstore.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+public class Pet {
+
+ private long id;
+ private Species species;
+ private String name;
+ private float price;
+ private List<String> tags;
+ private PetStatus status;
+ private String photo;
+
+ /**
+ * Returns the pet ID.
+ *
+ * @return The pet ID.
+ */
+ public long getId() {
+ return id;
+ }
+
+ /**
+ * Sets the pet ID.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Pet setId(long value) {
+ id = value;
+ return this;
+ }
+
+ /**
+ * Returns the species of the pet.
+ *
+ * @return The species of the pet.
+ */
+ public Species getSpecies() {
+ return species;
+ }
+
+ /**
+ * Sets the species of the pet.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Pet setSpecies(Species value) {
+ species = value;
+ return this;
+ }
+
+ /**
+ * Returns the name of the pet.
+ *
+ * @return The name of the pet.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the pet.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Pet setName(String value) {
+ name = value;
+ return this;
+ }
+
+ /**
+ * Returns the price of the pet.
+ *
+ * @return The price of the pet.
+ */
+ public float getPrice() {
+ return price;
+ }
+
+ /**
+ * Sets the price of the pet.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Pet setPrice(float value) {
+ price = value;
+ return this;
+ }
+
+ /**
+ * Returns the tags associated with the pet.
+ *
+ * @return The tags associated with the pet. Can be <jk>null</jk>.
+ */
+ public List<String> getTags() {
+ return tags;
+ }
+
+ /**
+ * Sets the tags associated with the pet.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public Pet setTags(List<String> value) {
+ tags = value;
+ return this;
+ }
+
+ /**
+ * Returns the lifecycle status of the pet.
+ *
+ * @return The lifecycle status of the pet.
+ */
+ public PetStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the lifecycle status of the pet.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public Pet setStatus(PetStatus value) {
+ status = value;
+ return this;
+ }
+
+ /**
+ * Returns the URI of the pet photo.
+ *
+ * @return The URI of the pet photo. Can be <jk>null</jk>.
+ */
+ public String getPhoto() {
+ return photo;
+ }
+
+ /**
+ * Sets the URI of the pet photo.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public Pet setPhoto(String value) {
+ photo = value;
+ return this;
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java
old mode 100755
new mode 100644
similarity index 76%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java
index dd83076900..dff750be91
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java
@@ -14,12 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.petstore.dto;
+
/**
- * REST Command Examples
- *
- * <p>
- * Example classes demonstrating how to use command pattern with Juneau's REST server.
- * These examples show various command-based REST API scenarios.
- * </p>
+ * Lifecycle status of a {@link Pet}.
*/
-package org.apache.juneau.examples.rest.command;
+public enum PetStatus {
+
+ /** Pet is available for purchase. */
+ AVAILABLE,
+
+ /** Pet has a pending order. */
+ PENDING,
+
+ /** Pet has been sold. */
+ SOLD
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Species.java
old mode 100755
new mode 100644
similarity index 75%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/package-info.java
rename to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Species.java
index 24446f8102..171c7d5ccd
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/dto/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/Species.java
@@ -14,12 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.petstore.dto;
+
/**
- * REST DTO Examples
- *
- * <p>
- * Example classes demonstrating how to use Data Transfer Objects (DTOs) with Juneau's REST server.
- * These examples show various DTO serialization and validation scenarios.
- * </p>
+ * Pet species enumeration.
*/
-package org.apache.juneau.examples.rest.dto;
+public enum Species {
+
+ /** Bird. */
+ BIRD,
+
+ /** Cat. */
+ CAT,
+
+ /** Dog. */
+ DOG,
+
+ /** Fish. */
+ FISH,
+
+ /** Mouse. */
+ MOUSE,
+
+ /** Rabbit. */
+ RABBIT,
+
+ /** Snake. */
+ SNAKE
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/User.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/User.java
new file mode 100644
index 0000000000..9cafa22815
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/User.java
@@ -0,0 +1,181 @@
+/*
+ * 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.juneau.petstore.dto;
+
+/**
+ * User domain bean.
+ *
+ * <p>
+ * Represents a registered petstore user. The {@code username} is the primary key.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+public class User {
+
+ private String username;
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String password;
+ private String phone;
+ private UserStatus userStatus;
+
+ /**
+ * Returns the username (primary key).
+ *
+ * @return The username.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Sets the username.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public User setUsername(String value) {
+ username = value;
+ return this;
+ }
+
+ /**
+ * Returns the first name.
+ *
+ * @return The first name. Can be <jk>null</jk>.
+ */
+ public String getFirstName() {
+ return firstName;
+ }
+
+ /**
+ * Sets the first name.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public User setFirstName(String value) {
+ firstName = value;
+ return this;
+ }
+
+ /**
+ * Returns the last name.
+ *
+ * @return The last name. Can be <jk>null</jk>.
+ */
+ public String getLastName() {
+ return lastName;
+ }
+
+ /**
+ * Sets the last name.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public User setLastName(String value) {
+ lastName = value;
+ return this;
+ }
+
+ /**
+ * Returns the email address.
+ *
+ * @return The email address. Can be <jk>null</jk>.
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * Sets the email address.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public User setEmail(String value) {
+ email = value;
+ return this;
+ }
+
+ /**
+ * Returns the password.
+ *
+ * <p>
+ * Stored in plaintext for sample purposes only. Do not use this pattern in production.
+ *
+ * @return The password. Can be <jk>null</jk>.
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public User setPassword(String value) {
+ password = value;
+ return this;
+ }
+
+ /**
+ * Returns the phone number.
+ *
+ * @return The phone number. Can be <jk>null</jk>.
+ */
+ public String getPhone() {
+ return phone;
+ }
+
+ /**
+ * Sets the phone number.
+ *
+ * @param value The new value. Can be <jk>null</jk>.
+ * @return This object.
+ */
+ public User setPhone(String value) {
+ phone = value;
+ return this;
+ }
+
+ /**
+ * Returns the user account status.
+ *
+ * @return The user account status.
+ */
+ public UserStatus getUserStatus() {
+ return userStatus;
+ }
+
+ /**
+ * Sets the user account status.
+ *
+ * @param value The new value.
+ * @return This object.
+ */
+ public User setUserStatus(UserStatus value) {
+ userStatus = value;
+ return this;
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java
old mode 100755
new mode 100644
similarity index 77%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/package-info.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java
index fdfb46d460..11366966c2
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java
@@ -14,12 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.petstore.dto;
+
/**
- * REST Server Examples
- *
- * <p>
- * Example classes demonstrating how to use Juneau's REST server capabilities.
- * These examples show various REST API creation and deployment scenarios.
- * </p>
+ * Lifecycle status of a {@link User}.
*/
-package org.apache.juneau.examples.rest;
+public enum UserStatus {
+
+ /** User account is active. */
+ ACTIVE,
+
+ /** User account is inactive. */
+ INACTIVE
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/package-info.java
old mode 100755
new mode 100644
similarity index 78%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/package-info.java
rename to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/package-info.java
index fdfb46d460..641a08b855
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/dto/package-info.java
@@ -15,11 +15,10 @@
* limitations under the License.
*/
/**
- * REST Server Examples
+ * Petstore domain beans (DTOs).
*
* <p>
- * Example classes demonstrating how to use Juneau's REST server capabilities.
- * These examples show various REST API creation and deployment scenarios.
- * </p>
+ * Plain Juneau beans representing the petstore domain model. Persistence is in-memory; no JPA or database
+ * dependencies.
*/
-package org.apache.juneau.examples.rest;
+package org.apache.juneau.petstore.dto;
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/package-info.java
similarity index 60%
copy from juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/package-info.java
index 665715d937..25b896cd04 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/package-info.java
@@ -14,32 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.juneau.examples.rest.springboot;
-
-import java.util.function.*;
-
/**
- * An example of a Spring bean that can be used for injecting messages into {@link HelloWorldResource}.
+ * Apache Juneau Petstore - shared domain model and REST resources.
+ *
+ * <p>
+ * The {@code juneau-petstore-core} module owns the petstore's deployment-agnostic surface:
+ * domain DTOs ({@code dto}), the in-memory store ({@code service}), and the REST resources
+ * ({@code rest}). It is consumed verbatim by both {@code juneau-petstore-jetty} and
+ * {@code juneau-petstore-springboot} so the two deployments demonstrate an identical REST
+ * surface by construction.
*
* <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
* </ul>
*/
-public class HelloWorldMessageProvider implements Supplier<String> {
-
- private final String message;
-
- /**
- * Constructor.
- *
- * @param message The message to display.
- */
- public HelloWorldMessageProvider(String message) {
- this.message = message;
- }
-
- @Override
- public String get() {
- return message;
- }
-}
\ No newline at end of file
+package org.apache.juneau.petstore;
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetFreemarkerViewResource.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetFreemarkerViewResource.java
new file mode 100644
index 0000000000..0633966fcd
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetFreemarkerViewResource.java
@@ -0,0 +1,82 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import org.apache.juneau.commons.inject.Bean;
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.response.*;
+import org.apache.juneau.petstore.service.*;
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.servlet.*;
+import org.apache.juneau.rest.server.view.*;
+import org.apache.juneau.rest.server.view.freemarker.*;
+
+/**
+ * Petstore FreeMarker view demo.
+ *
+ * <p>
+ * Pure-classpath analogue of {@link PetMustacheViewResource}: the FreeMarker bridge is engine-agnostic and
+ * renders identically under both the Jetty and Spring Boot deployments. Resolves
+ * {@code petstore-templates/pet.ftlh} via the configured {@link FreemarkerMixin}.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/FreemarkerViewSupport">FreeMarker View Support</a>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/pet-views/freemarker",
+ title="Pet detail (FreeMarker)",
+ description="Renders a pet detail page through the FreeMarker view-rendering bridge.",
+ responseProcessors={FreemarkerViewRenderer.class}
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetFreemarkerViewResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final PetStore store = new PetStore();
+
+ /**
+ * Provides a {@link FreemarkerMixin} configured to resolve templates under {@code petstore-templates/}.
+ *
+ * @return The freemarker mixin bean.
+ */
+ @Bean
+ public FreemarkerMixin freemarker() {
+ return FreemarkerMixin.create()
+ .basePath("/petstore-templates/")
+ .build();
+ }
+
+ /**
+ * GET /pets/{id}/view — renders a pet detail HTML page through FreeMarker.
+ *
+ * @param id The pet ID.
+ * @return A {@link FreemarkerView} bound to the {@code pet.ftlh} template.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestGet("/pets/{id}/view")
+ public View viewPet(@Path("id") long id) {
+ var pet = store.getPet(id);
+ if (pet == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ return FreemarkerView.of("pet.ftlh").attr("pet", pet);
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetMustacheViewResource.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetMustacheViewResource.java
new file mode 100644
index 0000000000..6ece716f8a
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetMustacheViewResource.java
@@ -0,0 +1,91 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import org.apache.juneau.commons.inject.Bean;
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.response.*;
+import org.apache.juneau.petstore.service.*;
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.servlet.*;
+import org.apache.juneau.rest.server.view.*;
+import org.apache.juneau.rest.server.view.mustache.*;
+
+/**
+ * Petstore Mustache view demo.
+ *
+ * <p>
+ * Demonstrates rendering a templated HTML pet detail page through the {@code juneau-rest-server-view-mustache}
+ * bridge. Lives in {@code juneau-petstore-core} so both the Jetty and Spring Boot deployments inherit it
+ * unchanged — Mustache is a pure-classpath engine and renders identically under either embedded container.
+ *
+ * <p>
+ * The {@code @RestGet("/pets/{id}/view")} method returns {@link MustacheView}; the configured
+ * {@link MustacheViewRenderer} (registered via {@code @Rest(responseProcessors=...)}) detects the return type,
+ * resolves the {@code pet.mustache} template under {@code petstore-templates/} on the classpath, and renders
+ * it directly to the response writer.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MustacheViewSupport">Mustache View Support</a>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/pet-views/mustache",
+ title="Pet detail (Mustache)",
+ description="Renders a pet detail page through the Mustache view-rendering bridge.",
+ responseProcessors={MustacheViewRenderer.class}
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetMustacheViewResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final PetStore store = new PetStore();
+
+ /**
+ * Provides a {@link MustacheMixin} configured to resolve templates under {@code petstore-templates/} with
+ * an implicit {@code .mustache} suffix — so {@code MustacheView.of("pet")} resolves to the classpath
+ * resource {@code petstore-templates/pet.mustache}.
+ *
+ * @return The mustache mixin bean.
+ */
+ @Bean
+ public MustacheMixin mustache() {
+ return MustacheMixin.create()
+ .basePath("/petstore-templates/")
+ .templateSuffix(".mustache")
+ .build();
+ }
+
+ /**
+ * GET /pets/{id}/view — renders a pet detail HTML page through Mustache.
+ *
+ * @param id The pet ID.
+ * @return A {@link MustacheView} bound to the {@code pet} template.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestGet("/pets/{id}/view")
+ public View viewPet(@Path("id") long id) {
+ var pet = store.getPet(id);
+ if (pet == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ return MustacheView.of("pet").attr("pet", pet);
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetSecureResource.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetSecureResource.java
new file mode 100644
index 0000000000..d9ae835f9c
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetSecureResource.java
@@ -0,0 +1,135 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import java.security.*;
+import java.util.*;
+
+import org.apache.juneau.commons.inject.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.response.*;
+import org.apache.juneau.petstore.auth.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.petstore.service.*;
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.auth.*;
+import org.apache.juneau.rest.server.guard.*;
+import org.apache.juneau.rest.server.servlet.*;
+
+/**
+ * Secure analogue of {@link PetStoreResource} demonstrating Juneau's {@link BearerTokenGuard} +
+ * {@link StubBearerTokenValidator} pattern.
+ *
+ * <p>
+ * Mounted at {@code /petstore-secure/*} and gated by a {@link BearerTokenGuard} that delegates to a
+ * {@link StubBearerTokenValidator}. Any request lacking a valid {@code Authorization: Bearer <token>} header
+ * receives {@code 401} with a {@code WWW-Authenticate: Bearer realm="petstore"} challenge. On success, the
+ * resolved {@link Principal} is stashed on the request and surfaces through {@link Auth @Auth Principal} op
+ * parameters — see {@link #whoami(Principal)}.
+ *
+ * <p>
+ * <b>Why guard rather than chain?</b> Juneau also ships an {@code AuthFilterChain} for composing multiple
+ * mechanisms (JWT bearer, API key, OAuth, SAML, OIDC). The chain is fail-open by design — a request that
+ * matches the chain's path pattern but presents no recognised credentials is passed through unchanged so a
+ * downstream guard can decide. For a single-mechanism demo, the op-level {@code BearerTokenGuard} (fail-closed
+ * by default) is the right surface. In a real multi-mechanism deployment you'd compose
+ * {@code AuthFilterChain.create(...).append(filterA, "/secure/*").append(filterB, "/secure/*").build()} and
+ * mount it via {@code @Bean AuthFilterChain} (auto-mounted by {@code JettyServerComponent}) or a Spring
+ * {@code FilterRegistrationBean}, then add this guard for fail-closed enforcement.
+ *
+ * <p>
+ * The CRUD surface is intentionally a thin subset of {@link PetStoreResource} — the demo is the auth gate, not
+ * the surface. If you need richer auth integration (role-based guards, multi-mechanism chains, server-side
+ * OAuth2 / SAML / OIDC-RP), consult the {@code juneau-rest-server-auth-*} modules.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='jc'>{@link BearerTokenGuard}
+ * <li class='jc'>{@link AuthFilterChain}
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/AuthGuards">AuthN Guards</a>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/AuthFilterFramework">AuthN Filter Framework</a>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/petstore-secure",
+ title="Petstore (secure)",
+ description="Auth-gated subset of the petstore CRUD surface; bearer-token-protected via AuthFilterChain."
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetSecureResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final PetStore store = new PetStore();
+
+ /**
+ * Provides the {@link RestGuardList} that gates every op on this resource with a
+ * {@link BearerTokenGuard} — fail-closed bearer-token enforcement.
+ *
+ * @param bs The bean store (Juneau supplies this automatically).
+ * @return The guard list applied to all ops on this resource.
+ */
+ @Bean
+ public RestGuardList guards(BeanStore bs) {
+ return RestGuardList.create(bs)
+ .append(
+ BearerTokenGuard.create()
+ .realm("petstore")
+ .validator(new StubBearerTokenValidator())
+ .build())
+ .build();
+ }
+
+ /**
+ * Lists all pets. Accessible only with a valid bearer token.
+ *
+ * @return All pets.
+ */
+ @RestGet("/pets")
+ public Collection<Pet> getPets() {
+ return store.getPets();
+ }
+
+ /**
+ * Retrieves a pet by ID. Accessible only with a valid bearer token.
+ *
+ * @param id The pet ID.
+ * @return The pet.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestGet("/pets/{id}")
+ public Pet getPet(@Path("id") long id) {
+ var pet = store.getPet(id);
+ if (pet == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ return pet;
+ }
+
+ /**
+ * Returns the name of the authenticated principal — the simplest possible "auth worked" probe.
+ *
+ * @param caller The principal stashed on the request by the {@code AuthFilterChain}. Never {@code null} —
+ * if no caller is authenticated the chain rejects with {@code 401} before this op runs.
+ * @return A small map carrying the principal's display name.
+ */
+ @RestGet("/whoami")
+ public Map<String,String> whoami(@Auth Principal caller) {
+ return Map.of("name", caller.getName());
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
new file mode 100644
index 0000000000..1c5dc461c6
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java
@@ -0,0 +1,292 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import java.util.*;
+
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.response.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.petstore.service.*;
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.servlet.*;
+
+/**
+ * Petstore CRUD REST resource.
+ *
+ * <p>
+ * Deployment-agnostic. Mounted by both {@code juneau-petstore-jetty} and {@code juneau-petstore-springboot} via
+ * the {@code @Rest(children=...)} of their root router.
+ *
+ * <p>
+ * Endpoints:
+ * <ul>
+ * <li>{@code GET /pets} — list pets
+ * <li>{@code GET /pets/{id}} — get pet
+ * <li>{@code POST /pets} — create pet
+ * <li>{@code PUT /pets/{id}} — update pet
+ * <li>{@code DELETE /pets/{id}} — delete pet
+ * <li>{@code GET /orders} — list orders
+ * <li>{@code GET /orders/{id}} — get order
+ * <li>{@code POST /orders} — create order
+ * <li>{@code PUT /orders/{id}} — update order
+ * <li>{@code DELETE /orders/{id}} — delete order
+ * <li>{@code GET /users} — list users
+ * <li>{@code GET /users/{username}} — get user
+ * <li>{@code POST /users} — create user
+ * <li>{@code PUT /users/{username}} — update user
+ * <li>{@code DELETE /users/{username}} — delete user
+ * </ul>
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/petstore",
+ title="Petstore",
+ description="Apache Juneau petstore sample resource."
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetStoreResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Backing store. Singleton servlet → singleton store, shared across requests. */
+ private final PetStore store = new PetStore();
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Pets
+ //------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Lists all pets.
+ *
+ * @return All pets.
+ */
+ @RestGet("/pets")
+ public Collection<Pet> getPets() {
+ return store.getPets();
+ }
+
+ /**
+ * Retrieves a pet by ID.
+ *
+ * @param id The pet ID.
+ * @return The pet.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestGet("/pets/{id}")
+ public Pet getPet(@Path("id") long id) {
+ var pet = store.getPet(id);
+ if (pet == null)
+ throw new NotFound("Pet not found: id={0}", id);
+ return pet;
+ }
+
+ /**
+ * Creates a new pet.
+ *
+ * @param pet The pet to create.
+ * @return The created pet (with assigned ID).
+ */
+ @RestPost("/pets")
+ public Pet createPet(@Content Pet pet) {
+ return store.createPet(pet);
+ }
+
+ /**
+ * Updates an existing pet.
+ *
+ * @param id The pet ID.
+ * @param pet The replacement pet body.
+ * @return The updated pet.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestPut("/pets/{id}")
+ public Pet updatePet(@Path("id") long id, @Content Pet pet) {
+ pet.setId(id);
+ try {
+ return store.updatePet(pet);
+ } catch (PetstoreNotFoundException e) {
+ throw new NotFound(e.getMessage());
+ }
+ }
+
+ /**
+ * Deletes a pet by ID.
+ *
+ * @param id The pet ID.
+ * @throws NotFound If no pet with the given ID exists.
+ */
+ @RestDelete("/pets/{id}")
+ public void deletePet(@Path("id") long id) {
+ try {
+ store.deletePet(id);
+ } catch (PetstoreNotFoundException e) {
+ throw new NotFound(e.getMessage());
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Orders
+ //------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Lists all orders.
+ *
+ * @return All orders.
+ */
+ @RestGet("/orders")
+ public Collection<Order> getOrders() {
+ return store.getOrders();
+ }
+
+ /**
+ * Retrieves an order by ID.
+ *
+ * @param id The order ID.
+ * @return The order.
+ * @throws NotFound If no order with the given ID exists.
+ */
+ @RestGet("/orders/{id}")
+ public Order getOrder(@Path("id") long id) {
+ var order = store.getOrder(id);
+ if (order == null)
+ throw new NotFound("Order not found: id={0}", id);
+ return order;
+ }
+
+ /**
+ * Creates a new order.
+ *
+ * @param order The order to create.
+ * @return The created order (with assigned ID).
+ */
+ @RestPost("/orders")
+ public Order createOrder(@Content Order order) {
+ return store.createOrder(order);
+ }
+
+ /**
+ * Updates an existing order.
+ *
+ * @param id The order ID.
+ * @param order The replacement order body.
+ * @return The updated order.
+ * @throws NotFound If no order with the given ID exists.
+ */
+ @RestPut("/orders/{id}")
+ public Order updateOrder(@Path("id") long id, @Content Order order) {
+ order.setId(id);
+ try {
+ return store.updateOrder(order);
+ } catch (PetstoreNotFoundException e) {
+ throw new NotFound(e.getMessage());
+ }
+ }
+
+ /**
+ * Deletes an order by ID.
+ *
+ * @param id The order ID.
+ * @throws NotFound If no order with the given ID exists.
+ */
+ @RestDelete("/orders/{id}")
+ public void deleteOrder(@Path("id") long id) {
+ try {
+ store.deleteOrder(id);
+ } catch (PetstoreNotFoundException e) {
+ throw new NotFound(e.getMessage());
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Users
+ //------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Lists all users.
+ *
+ * @return All users.
+ */
+ @RestGet("/users")
+ public Collection<User> getUsers() {
+ return store.getUsers();
+ }
+
+ /**
+ * Retrieves a user by username.
+ *
+ * @param username The username.
+ * @return The user.
+ * @throws NotFound If no user with the given username exists.
+ */
+ @RestGet("/users/{username}")
+ public User getUser(@Path("username") String username) {
+ var user = store.getUser(username);
+ if (user == null)
+ throw new NotFound("User not found: username={0}", username);
+ return user;
+ }
+
+ /**
+ * Creates a new user.
+ *
+ * @param user The user to create. Must carry a non-null username not already in use.
+ * @return The created user.
+ */
+ @RestPost("/users")
+ public User createUser(@Content User user) {
+ return store.createUser(user);
+ }
+
+ /**
+ * Updates an existing user.
+ *
+ * @param username The username.
+ * @param user The replacement user body.
+ * @return The updated user.
+ * @throws NotFound If no user with the given username exists.
+ */
+ @RestPut("/users/{username}")
+ public User updateUser(@Path("username") String username, @Content User user) {
+ user.setUsername(username);
+ try {
+ return store.updateUser(user);
+ } catch (PetstoreNotFoundException e) {
+ throw new NotFound(e.getMessage());
+ }
+ }
+
+ /**
+ * Deletes a user by username.
+ *
+ * @param username The username.
+ * @throws NotFound If no user with the given username exists.
+ */
+ @RestDelete("/users/{username}")
+ public void deleteUser(@Path("username") String username) {
+ try {
+ store.deleteUser(username);
+ } catch (PetstoreNotFoundException e) {
+ throw new NotFound(e.getMessage());
+ }
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetstoreUiResource.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetstoreUiResource.java
new file mode 100644
index 0000000000..86944321a1
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/PetstoreUiResource.java
@@ -0,0 +1,51 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.servlet.*;
+import org.apache.juneau.rest.server.staticfile.*;
+
+/**
+ * Petstore React SPA demo — serves the no-build single-page React UI from the core classpath.
+ *
+ * <p>
+ * Composes {@link StaticFilesMixin} to serve {@code /static/*} from the importer's classpath: the file
+ * {@code static/petstore-ui.html} is reachable at {@code GET /petstore-ui/static/petstore-ui.html}. The HTML
+ * loads React + Babel and uses {@code fetch()} against {@code /petstore/pets} to demonstrate the headless-JSON +
+ * decoupled-SPA pattern alongside the server-rendered HTML-doc UI.
+ *
+ * <p>
+ * Lives in {@code juneau-petstore-core} so both the Jetty and Spring Boot deployments inherit it for free.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+@Rest(
+ path="/petstore-ui",
+ title="Petstore — React SPA demo",
+ description="No-build single-page React UI loaded as static classpath resource; calls /petstore/* over fetch().",
+ mixins=StaticFilesMixin.class
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class PetstoreUiResource extends BasicRestServlet {
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/package-info.java
old mode 100755
new mode 100644
similarity index 77%
copy from juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/package-info.java
index 0ba233d284..e74f6b0492
--- a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/rest/package-info.java
@@ -15,11 +15,9 @@
* limitations under the License.
*/
/**
- * REST Jetty Examples
+ * Petstore REST resources.
*
* <p>
- * Example classes demonstrating how to deploy Juneau REST servers using Jetty.
- * These examples show various Jetty-based REST API deployment scenarios.
- * </p>
+ * Deployment-agnostic Juneau REST resources mounted by both the Jetty and Spring Boot petstore deployments.
*/
-package org.apache.juneau.examples.rest.jetty;
+package org.apache.juneau.petstore.rest;
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/PetStore.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/PetStore.java
new file mode 100644
index 0000000000..447a431f6e
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/PetStore.java
@@ -0,0 +1,308 @@
+/*
+ * 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.juneau.petstore.service;
+
+import static org.apache.juneau.commons.utils.ThrowableUtils.*;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.petstore.dto.*;
+
+/**
+ * In-memory {@link Pet}/{@link Order}/{@link User} store seeded from classpath JSON.
+ *
+ * <p>
+ * Backed by {@link ConcurrentHashMap}s; pet and order IDs auto-assign via {@link AtomicLong} starting from
+ * the highest seeded ID plus one (or {@code 1} if no seeds existed). Seed files live on the classpath at
+ * {@code petstore/init/{Pets,Orders,Users}.json} and are loaded lazily on first access.
+ *
+ * <p>
+ * This is a sample/demo store — there is no persistence, no transactions, and no replication. Restart wipes
+ * state back to the seeded baseline.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+public class PetStore {
+
+ private static final String SEED_PETS = "petstore/init/Pets.json";
+ private static final String SEED_ORDERS = "petstore/init/Orders.json";
+ private static final String SEED_USERS = "petstore/init/Users.json";
+
+ private final Map<Long,Pet> pets = new ConcurrentHashMap<>();
+ private final Map<Long,Order> orders = new ConcurrentHashMap<>();
+ private final Map<String,User> users = new ConcurrentHashMap<>();
+
+ private final AtomicLong nextPetId = new AtomicLong();
+ private final AtomicLong nextOrderId = new AtomicLong();
+
+ /**
+ * Constructor.
+ *
+ * <p>
+ * Eagerly loads the bundled classpath seed data.
+ */
+ public PetStore() {
+ var seededPets = loadList(SEED_PETS, Pet.class);
+ var maxPetId = 0L;
+ for (var p : seededPets) {
+ if (p.getId() == 0L)
+ p.setId(++maxPetId);
+ else
+ maxPetId = Math.max(maxPetId, p.getId());
+ pets.put(p.getId(), p);
+ }
+ nextPetId.set(maxPetId);
+
+ var seededOrders = loadList(SEED_ORDERS, Order.class);
+ var maxOrderId = 0L;
+ for (var o : seededOrders) {
+ if (o.getId() == 0L)
+ o.setId(++maxOrderId);
+ else
+ maxOrderId = Math.max(maxOrderId, o.getId());
+ orders.put(o.getId(), o);
+ }
+ nextOrderId.set(maxOrderId);
+
+ var seededUsers = loadList(SEED_USERS, User.class);
+ for (var u : seededUsers)
+ users.put(u.getUsername(), u);
+ }
+
+ private static <T> List<T> loadList(String resourcePath, Class<T> elementType) {
+ var loader = PetStore.class.getClassLoader();
+ try (var in = loader.getResourceAsStream(resourcePath)) {
+ if (in == null)
+ return new ArrayList<>();
+ try (var reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
+ return Json5Parser.DEFAULT.parse(reader, List.class, elementType);
+ }
+ } catch (Exception e) {
+ throw bex(e, "Failed to load petstore seed resource ''{0}''", resourcePath);
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Pets
+ //------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns all pets.
+ *
+ * @return All pets, in arbitrary order. Never <jk>null</jk>.
+ */
+ public Collection<Pet> getPets() {
+ return pets.values();
+ }
+
+ /**
+ * Returns a pet by ID.
+ *
+ * @param id The pet ID.
+ * @return The pet, or <jk>null</jk> if not found.
+ */
+ public Pet getPet(long id) {
+ return pets.get(id);
+ }
+
+ /**
+ * Creates a new pet.
+ *
+ * <p>
+ * Assigns the next available ID, ignoring any caller-supplied ID.
+ *
+ * @param pet The pet to create. Must not be <jk>null</jk>.
+ * @return The created pet (same instance, with assigned ID).
+ */
+ public Pet createPet(Pet pet) {
+ if (pet == null)
+ throw illegalArg("Pet must not be null");
+ var id = nextPetId.incrementAndGet();
+ pet.setId(id);
+ pets.put(id, pet);
+ return pet;
+ }
+
+ /**
+ * Updates an existing pet.
+ *
+ * @param pet The pet to update. Must not be <jk>null</jk>; must carry an ID matching an existing pet.
+ * @return The updated pet.
+ * @throws PetstoreNotFoundException If no pet with the given ID exists.
+ */
+ public Pet updatePet(Pet pet) {
+ if (pet == null)
+ throw illegalArg("Pet must not be null");
+ if (! pets.containsKey(pet.getId()))
+ throw new PetstoreNotFoundException("Pet not found: id=" + pet.getId());
+ pets.put(pet.getId(), pet);
+ return pet;
+ }
+
+ /**
+ * Deletes a pet by ID.
+ *
+ * @param id The pet ID.
+ * @throws PetstoreNotFoundException If no pet with the given ID exists.
+ */
+ public void deletePet(long id) {
+ if (pets.remove(id) == null)
+ throw new PetstoreNotFoundException("Pet not found: id=" + id);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Orders
+ //------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns all orders.
+ *
+ * @return All orders, in arbitrary order. Never <jk>null</jk>.
+ */
+ public Collection<Order> getOrders() {
+ return orders.values();
+ }
+
+ /**
+ * Returns an order by ID.
+ *
+ * @param id The order ID.
+ * @return The order, or <jk>null</jk> if not found.
+ */
+ public Order getOrder(long id) {
+ return orders.get(id);
+ }
+
+ /**
+ * Creates a new order.
+ *
+ * <p>
+ * Assigns the next available ID, ignoring any caller-supplied ID.
+ *
+ * @param order The order to create. Must not be <jk>null</jk>.
+ * @return The created order (same instance, with assigned ID).
+ */
+ public Order createOrder(Order order) {
+ if (order == null)
+ throw illegalArg("Order must not be null");
+ var id = nextOrderId.incrementAndGet();
+ order.setId(id);
+ orders.put(id, order);
+ return order;
+ }
+
+ /**
+ * Updates an existing order.
+ *
+ * @param order The order to update. Must not be <jk>null</jk>; must carry an ID matching an existing order.
+ * @return The updated order.
+ * @throws PetstoreNotFoundException If no order with the given ID exists.
+ */
+ public Order updateOrder(Order order) {
+ if (order == null)
+ throw illegalArg("Order must not be null");
+ if (! orders.containsKey(order.getId()))
+ throw new PetstoreNotFoundException("Order not found: id=" + order.getId());
+ orders.put(order.getId(), order);
+ return order;
+ }
+
+ /**
+ * Deletes an order by ID.
+ *
+ * @param id The order ID.
+ * @throws PetstoreNotFoundException If no order with the given ID exists.
+ */
+ public void deleteOrder(long id) {
+ if (orders.remove(id) == null)
+ throw new PetstoreNotFoundException("Order not found: id=" + id);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Users
+ //------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns all users.
+ *
+ * @return All users, in arbitrary order. Never <jk>null</jk>.
+ */
+ public Collection<User> getUsers() {
+ return users.values();
+ }
+
+ /**
+ * Returns a user by username.
+ *
+ * @param username The username (primary key).
+ * @return The user, or <jk>null</jk> if not found.
+ */
+ public User getUser(String username) {
+ return users.get(username);
+ }
+
+ /**
+ * Creates a new user.
+ *
+ * @param user The user to create. Must not be <jk>null</jk>; must carry a non-null username not already in use.
+ * @return The created user.
+ * @throws IllegalArgumentException If the username is already in use.
+ */
+ public User createUser(User user) {
+ if (user == null)
+ throw illegalArg("User must not be null");
+ if (user.getUsername() == null)
+ throw illegalArg("User username must not be null");
+ if (users.putIfAbsent(user.getUsername(), user) != null)
+ throw illegalArg("User already exists: username=''{0}''", user.getUsername());
+ return user;
+ }
+
+ /**
+ * Updates an existing user.
+ *
+ * @param user The user to update. Must not be <jk>null</jk>; must carry a username matching an existing user.
+ * @return The updated user.
+ * @throws PetstoreNotFoundException If no user with the given username exists.
+ */
+ public User updateUser(User user) {
+ if (user == null)
+ throw illegalArg("User must not be null");
+ if (! users.containsKey(user.getUsername()))
+ throw new PetstoreNotFoundException("User not found: username=" + user.getUsername());
+ users.put(user.getUsername(), user);
+ return user;
+ }
+
+ /**
+ * Deletes a user by username.
+ *
+ * @param username The username.
+ * @throws PetstoreNotFoundException If no user with the given username exists.
+ */
+ public void deleteUser(String username) {
+ if (users.remove(username) == null)
+ throw new PetstoreNotFoundException("User not found: username=" + username);
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/PetstoreNotFoundException.java
old mode 100755
new mode 100644
similarity index 63%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
copy to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/PetstoreNotFoundException.java
index dd83076900..7911d567ea
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/PetstoreNotFoundException.java
@@ -14,12 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.petstore.service;
+
/**
- * REST Command Examples
+ * Thrown by {@link PetStore} when the requested entity does not exist.
*
* <p>
- * Example classes demonstrating how to use command pattern with Juneau's REST server.
- * These examples show various command-based REST API scenarios.
- * </p>
+ * The REST layer translates this to a {@code 404 Not Found} response.
*/
-package org.apache.juneau.examples.rest.command;
+public class PetstoreNotFoundException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor.
+ *
+ * @param message Detail message describing what was not found.
+ */
+ public PetstoreNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/package-info.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/package-info.java
old mode 100755
new mode 100644
similarity index 75%
rename from juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/package-info.java
rename to juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/package-info.java
index 47ace2c470..2a49b1c62a
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/package-info.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/service/package-info.java
@@ -15,11 +15,10 @@
* limitations under the License.
*/
/**
- * REST Spring Boot Examples
+ * Petstore service layer (in-memory store).
*
* <p>
- * Example classes demonstrating how to integrate Juneau REST servers with Spring Boot.
- * These examples show various Spring Boot-based REST API integration scenarios.
- * </p>
+ * The service is HTTP-agnostic: it throws {@link org.apache.juneau.petstore.service.PetstoreNotFoundException}
+ * which the REST layer translates to a {@code 404 Not Found}.
*/
-package org.apache.juneau.examples.rest.springboot;
+package org.apache.juneau.petstore.service;
diff --git a/juneau-petstore/juneau-petstore-core/src/main/resources/htdocs/petstore-ui.html b/juneau-petstore/juneau-petstore-core/src/main/resources/htdocs/petstore-ui.html
new file mode 100644
index 0000000000..c48c66ae09
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/main/resources/htdocs/petstore-ui.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<!--
+ 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.
+-->
+<!--
+ No-build single-page React demo for the Juneau petstore.
+
+ Demonstrates the "Juneau as a headless JSON backend + decoupled client-side SPA frontend" pattern
+ alongside the built-in server-rendered HTML-doc UI.
+
+ IMPORTANT: This v1 loads React from a CDN to keep the demo simple. For ASF-release-quality, the React/
+ ReactDOM UMD bundles + Babel standalone should be vendored into a /static/vendor/ subdirectory and
+ served from the classpath, with appropriate NOTICE/LICENSE acknowledgements. No Node/npm in the
+ Maven build either way.
+-->
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Juneau Petstore — React UI</title>
+ <style>
+ body { font-family: system-ui, -apple-system, sans-serif; padding: 2em; max-width: 60em; margin: 0 auto; }
+ h1 { border-bottom: 1px solid #ccc; padding-bottom: 0.3em; }
+ table { border-collapse: collapse; width: 100%; }
+ th, td { text-align: left; padding: 0.4em 0.8em; border-bottom: 1px solid #eee; }
+ th { background: #f4f4f4; }
+ .error { color: #b00; padding: 0.5em; background: #fee; border: 1px solid #fcc; border-radius: 3px; }
+ .muted { color: #666; }
+ </style>
+</head>
+<body>
+ <div id="root"></div>
+
+ <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
+ <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
+
+ <script type="text/babel">
+ const { useState, useEffect } = React;
+
+ function PetTable({ pets }) {
+ if (!pets.length) return <p className="muted">No pets.</p>;
+ return (
+ <table>
+ <thead>
+ <tr><th>ID</th><th>Name</th><th>Species</th><th>Price</th><th>Status</th></tr>
+ </thead>
+ <tbody>
+ {pets.map(p => (
+ <tr key={p.id}>
+ <td>{p.id}</td>
+ <td>{p.name}</td>
+ <td>{p.species}</td>
+ <td>{p.price?.toFixed?.(2) ?? p.price}</td>
+ <td>{p.status}</td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ );
+ }
+
+ function App() {
+ const [pets, setPets] = useState([]);
+ const [err, setErr] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ fetch('/petstore/pets', { headers: { 'Accept': 'application/json' } })
+ .then(r => {
+ if (!r.ok) throw new Error('HTTP ' + r.status);
+ return r.json();
+ })
+ .then(data => { setPets(data); setLoading(false); })
+ .catch(e => { setErr(String(e)); setLoading(false); });
+ }, []);
+
+ return (
+ <div>
+ <h1>Juneau Petstore — React UI</h1>
+ <p className="muted">Headless Juneau backend at <code>/petstore/*</code>, rendered by a no-build React SPA.</p>
+ {loading && <p>Loading…</p>}
+ {err && <div className="error">Failed to load pets: {err}</div>}
+ {!loading && !err && <PetTable pets={pets} />}
+ </div>
+ );
+ }
+
+ ReactDOM.createRoot(document.getElementById('root')).render(<App />);
+ </script>
+</body>
+</html>
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/log4j.xml b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore-templates/pet.ftlh
similarity index 56%
copy from juneau-examples/juneau-examples-rest-springboot/src/main/resources/log4j.xml
copy to juneau-petstore/juneau-petstore-core/src/main/resources/petstore-templates/pet.ftlh
index dc5d853829..0912ec9ae2 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/log4j.xml
+++ b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore-templates/pet.ftlh
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
+<#--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
@@ -15,19 +14,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
-
- <appender name="console" class="org.apache.log4j.ConsoleAppender">
- <param name="Target" value="System.out"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
- </layout>
- </appender>
-
- <root>
- <priority value="INFO"/>
- <appender-ref ref="console"/>
- </root>
-
-</log4j:configuration>
\ No newline at end of file
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Pet: ${pet.name}</title>
+ <style>body { font-family: sans-serif; padding: 2em; } dl { display: grid; grid-template-columns: max-content 1fr; gap: 0.5em 1em; }</style>
+</head>
+<body>
+ <h1>${pet.name}</h1>
+ <dl>
+ <dt>ID</dt><dd>${pet.id}</dd>
+ <dt>Species</dt><dd>${pet.species}</dd>
+ <dt>Price</dt><dd>${pet.price?string("0.00")}</dd>
+ <dt>Status</dt><dd>${pet.status}</dd>
+ </dl>
+ <p><em>Rendered via FreeMarker.</em></p>
+</body>
+</html>
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/log4j.xml b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore-templates/pet.mustache
similarity index 56%
rename from juneau-examples/juneau-examples-rest-springboot/src/main/resources/log4j.xml
rename to juneau-petstore/juneau-petstore-core/src/main/resources/petstore-templates/pet.mustache
index dc5d853829..e7dc523f33 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/log4j.xml
+++ b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore-templates/pet.mustache
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
+{{!
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
@@ -14,20 +13,20 @@
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.
--->
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
-
- <appender name="console" class="org.apache.log4j.ConsoleAppender">
- <param name="Target" value="System.out"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
- </layout>
- </appender>
-
- <root>
- <priority value="INFO"/>
- <appender-ref ref="console"/>
- </root>
-
-</log4j:configuration>
\ No newline at end of file
+}}<!DOCTYPE html>
+<html>
+<head>
+ <title>Pet: {{pet.name}}</title>
+ <style>body { font-family: sans-serif; padding: 2em; } dl { display: grid; grid-template-columns: max-content 1fr; gap: 0.5em 1em; }</style>
+</head>
+<body>
+ <h1>{{pet.name}}</h1>
+ <dl>
+ <dt>ID</dt><dd>{{pet.id}}</dd>
+ <dt>Species</dt><dd>{{pet.species}}</dd>
+ <dt>Price</dt><dd>{{pet.price}}</dd>
+ <dt>Status</dt><dd>{{pet.status}}</dd>
+ </dl>
+ <p><em>Rendered via Mustache.</em></p>
+</body>
+</html>
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Orders.json b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Orders.json
similarity index 100%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Orders.json
rename to juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Orders.json
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Pets.json b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Pets.json
similarity index 100%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Pets.json
rename to juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Pets.json
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Users.json b/juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Users.json
similarity index 100%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Users.json
rename to juneau-petstore/juneau-petstore-core/src/main/resources/petstore/init/Users.json
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetFreemarkerViewResource_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetFreemarkerViewResource_Test.java
new file mode 100644
index 0000000000..f777b90fc8
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetFreemarkerViewResource_Test.java
@@ -0,0 +1,48 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.mock.classic.*;
+import org.junit.jupiter.api.*;
+
+class PetFreemarkerViewResource_Test extends TestBase {
+
+ private static final MockRestClient CLIENT = MockRestClient.buildLax(PetFreemarkerViewResource.class);
+
+ @Test void a01_viewPet_rendersTemplateWithPetName() throws Exception {
+ CLIENT.get("/pets/1/view")
+ .run()
+ .assertStatus(200)
+ .assertContent().asString().isContains("Mr. Frisky")
+ .assertContent().asString().isContains("Rendered via FreeMarker.");
+ }
+
+ @Test void a02_viewPet_rendersSpeciesAndStatus() throws Exception {
+ CLIENT.get("/pets/1/view")
+ .run()
+ .assertStatus(200)
+ .assertContent().asString().isContains("CAT")
+ .assertContent().asString().isContains("AVAILABLE");
+ }
+
+ @Test void a03_viewPet_unknownId_404() throws Exception {
+ CLIENT.get("/pets/99999/view")
+ .run()
+ .assertStatus(404);
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetMustacheViewResource_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetMustacheViewResource_Test.java
new file mode 100644
index 0000000000..cfd9cc889c
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetMustacheViewResource_Test.java
@@ -0,0 +1,48 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.mock.classic.*;
+import org.junit.jupiter.api.*;
+
+class PetMustacheViewResource_Test extends TestBase {
+
+ private static final MockRestClient CLIENT = MockRestClient.buildLax(PetMustacheViewResource.class);
+
+ @Test void a01_viewPet_rendersTemplateWithPetName() throws Exception {
+ CLIENT.get("/pets/1/view")
+ .run()
+ .assertStatus(200)
+ .assertContent().asString().isContains("Mr. Frisky")
+ .assertContent().asString().isContains("Rendered via Mustache.");
+ }
+
+ @Test void a02_viewPet_rendersSpeciesAndStatus() throws Exception {
+ CLIENT.get("/pets/1/view")
+ .run()
+ .assertStatus(200)
+ .assertContent().asString().isContains("CAT")
+ .assertContent().asString().isContains("AVAILABLE");
+ }
+
+ @Test void a03_viewPet_unknownId_404() throws Exception {
+ CLIENT.get("/pets/99999/view")
+ .run()
+ .assertStatus(404);
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java
new file mode 100644
index 0000000000..6980e25d89
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetStoreResource_Test.java
@@ -0,0 +1,143 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.petstore.dto.Order;
+import org.apache.juneau.rest.mock.classic.*;
+import org.junit.jupiter.api.*;
+
+class PetStoreResource_Test extends TestBase {
+
+ /**
+ * Builds a JSON-configured MockRestClient: requests carry {@code Content-Type: application/json}, responses
+ * carry {@code Accept: application/json}, and 4xx/5xx responses do not throw.
+ */
+ private static MockRestClient client() {
+ return MockRestClient.buildJsonLax(PetStoreResource.class);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // a — pets
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void a01_getPet_byId() throws Exception {
+ var pet = client().get("/pets/1").run().assertStatus(200).getContent().as(Pet.class);
+ assertBean(pet, "id,name,species,status", "1,Mr. Frisky,CAT,AVAILABLE");
+ }
+
+ @Test void a02_getPet_unknownId_404() throws Exception {
+ client().get("/pets/99999").run().assertStatus(404);
+ }
+
+ @Test void a03_getPets_returnsAllSeeded() throws Exception {
+ var content = client().get("/pets").run().assertStatus(200).getContent().asString();
+ // Seed has 9 pets — confirm the first one's name is in the response.
+ assertNotNull(content);
+ assertTrue(content.contains("Mr. Frisky"), "expected seeded pet name in response: " + content);
+ }
+
+ @Test void a04_createPet_roundTrip() throws Exception {
+ var c = client();
+ var created = c.post("/pets", new Pet()
+ .setName("Wanda")
+ .setSpecies(Species.RABBIT)
+ .setPrice(12.50f)
+ .setStatus(PetStatus.AVAILABLE))
+ .run()
+ .assertStatus(200)
+ .getContent().as(Pet.class);
+ assertNotEquals(0L, created.getId());
+
+ var fetched = c.get("/pets/" + created.getId()).run().assertStatus(200).getContent().as(Pet.class);
+ assertBean(fetched, "name,species,status", "Wanda,RABBIT,AVAILABLE");
+ }
+
+ @Test void a05_updatePet_replaces() throws Exception {
+ var c = client();
+ c.put("/pets/1", new Pet().setName("Renamed").setSpecies(Species.CAT).setStatus(PetStatus.AVAILABLE))
+ .run().assertStatus(200);
+ var fetched = c.get("/pets/1").run().assertStatus(200).getContent().as(Pet.class);
+ assertEquals("Renamed", fetched.getName());
+ }
+
+ @Test void a06_updatePet_unknownId_404() throws Exception {
+ client().put("/pets/99999", new Pet().setName("Ghost").setSpecies(Species.CAT).setStatus(PetStatus.AVAILABLE))
+ .run().assertStatus(404);
+ }
+
+ @Test void a07_deletePet_removes() throws Exception {
+ var c = client();
+ c.delete("/pets/2").run().assertStatus(200);
+ c.get("/pets/2").run().assertStatus(404);
+ }
+
+ @Test void a08_deletePet_unknownId_404() throws Exception {
+ client().delete("/pets/99999").run().assertStatus(404);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // b — orders
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void b01_getOrder_byId() throws Exception {
+ var o = client().get("/orders/101").run().assertStatus(200).getContent().as(Order.class);
+ assertBean(o, "id,petId,shipDate,status", "101,101,2018-01-01,PLACED");
+ }
+
+ @Test void b02_getOrder_unknownId_404() throws Exception {
+ client().get("/orders/99999").run().assertStatus(404);
+ }
+
+ @Test void b03_createOrder_roundTrip() throws Exception {
+ var c = client();
+ var created = c.post("/orders", new Order().setPetId(1L).setStatus(OrderStatus.PLACED))
+ .run().assertStatus(200).getContent().as(Order.class);
+ assertNotEquals(0L, created.getId());
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // c — users
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void c01_getUser_byUsername() throws Exception {
+ var u = client().get("/users/mwatson").run().assertStatus(200).getContent().as(User.class);
+ assertBean(u, "username,firstName,lastName,userStatus", "mwatson,Marie,Watson,ACTIVE");
+ }
+
+ @Test void c02_getUser_unknown_404() throws Exception {
+ client().get("/users/no-such-user").run().assertStatus(404);
+ }
+
+ @Test void c03_createUser_roundTrip() throws Exception {
+ var c = client();
+ c.post("/users", new User().setUsername("newuser").setFirstName("New").setUserStatus(UserStatus.ACTIVE))
+ .run().assertStatus(200);
+ var fetched = c.get("/users/newuser").run().assertStatus(200).getContent().as(User.class);
+ assertBean(fetched, "username,firstName", "newuser,New");
+ }
+
+ @Test void c04_deleteUser_removes() throws Exception {
+ var c = client();
+ c.delete("/users/dvaughn").run().assertStatus(200);
+ c.get("/users/dvaughn").run().assertStatus(404);
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetstoreUiResource_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetstoreUiResource_Test.java
new file mode 100644
index 0000000000..3d84d0ea4f
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/rest/PetstoreUiResource_Test.java
@@ -0,0 +1,48 @@
+/*
+ * 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.juneau.petstore.rest;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.mock.classic.*;
+import org.junit.jupiter.api.*;
+
+class PetstoreUiResource_Test extends TestBase {
+
+ private static final MockRestClient CLIENT = MockRestClient.buildLax(PetstoreUiResource.class);
+
+ @Test void a01_uiHtml_servedFromClasspath() throws Exception {
+ CLIENT.get("/static/petstore-ui.html")
+ .run()
+ .assertStatus(200)
+ .assertContent().asString().isContains("<title>Juneau Petstore — React UI</title>");
+ }
+
+ @Test void a02_uiHtml_referencesPetstoreEndpoint() throws Exception {
+ // Sanity check that the SPA actually points at the right backend route — guards against
+ // accidental rename of /petstore/pets without updating the SPA.
+ CLIENT.get("/static/petstore-ui.html")
+ .run()
+ .assertStatus(200)
+ .assertContent().asString().isContains("/petstore/pets");
+ }
+
+ @Test void a03_unknownStaticFile_404() throws Exception {
+ CLIENT.get("/static/no-such-file.html")
+ .run()
+ .assertStatus(404);
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/service/PetStore_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/service/PetStore_Test.java
new file mode 100644
index 0000000000..f4f2c89aa0
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/service/PetStore_Test.java
@@ -0,0 +1,150 @@
+/*
+ * 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.juneau.petstore.service;
+
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.petstore.dto.*;
+import org.apache.juneau.petstore.dto.Order;
+import org.junit.jupiter.api.*;
+
+class PetStore_Test extends TestBase {
+
+ //------------------------------------------------------------------------------------------------------------------
+ // a — seed loading
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void a01_seededPetsLoaded() {
+ var s = new PetStore();
+ assertEquals(9, s.getPets().size());
+ }
+
+ @Test void a02_seededOrdersLoaded() {
+ var s = new PetStore();
+ assertEquals(3, s.getOrders().size());
+ }
+
+ @Test void a03_seededUsersLoaded() {
+ var s = new PetStore();
+ assertEquals(3, s.getUsers().size());
+ }
+
+ @Test void a04_seededPetByIdHasCorrectShape() {
+ var s = new PetStore();
+ // First seeded pet — id auto-assigned to 1.
+ assertBean(s.getPet(1L), "name,species,price,status", "Mr. Frisky,CAT,39.99,AVAILABLE");
+ }
+
+ @Test void a05_seededOrderById() {
+ var s = new PetStore();
+ assertBean(s.getOrder(101L), "id,petId,shipDate,status", "101,101,2018-01-01,PLACED");
+ }
+
+ @Test void a06_seededUserByUsername() {
+ var s = new PetStore();
+ assertBean(s.getUser("mwatson"), "username,firstName,lastName,userStatus", "mwatson,Marie,Watson,ACTIVE");
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // b — pets CRUD
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void b01_createPet_assignsId() {
+ var s = new PetStore();
+ var p = s.createPet(new Pet().setName("Newpet").setSpecies(Species.DOG).setPrice(10f).setStatus(PetStatus.AVAILABLE));
+ assertNotEquals(0L, p.getId());
+ assertEquals(p, s.getPet(p.getId()));
+ }
+
+ @Test void b02_updatePet_replacesContent() {
+ var s = new PetStore();
+ var p = s.getPet(1L).setName("Renamed");
+ s.updatePet(p);
+ assertEquals("Renamed", s.getPet(1L).getName());
+ }
+
+ @Test void b03_updatePet_unknownId_throws() {
+ var s = new PetStore();
+ var ghost = new Pet().setId(99999L).setName("Ghost").setSpecies(Species.CAT).setStatus(PetStatus.AVAILABLE);
+ assertThrows(PetstoreNotFoundException.class, () -> s.updatePet(ghost));
+ }
+
+ @Test void b04_deletePet_removes() {
+ var s = new PetStore();
+ s.deletePet(1L);
+ assertNull(s.getPet(1L));
+ }
+
+ @Test void b05_deletePet_unknownId_throws() {
+ var s = new PetStore();
+ assertThrows(PetstoreNotFoundException.class, () -> s.deletePet(99999L));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // c — orders CRUD
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void c01_createOrder_assignsId() {
+ var s = new PetStore();
+ var o = s.createOrder(new Order().setPetId(1L).setStatus(OrderStatus.PLACED));
+ assertNotEquals(0L, o.getId());
+ assertTrue(o.getId() > 103L); // greater than highest seeded id
+ }
+
+ @Test void c02_updateOrder_replacesContent() {
+ var s = new PetStore();
+ var o = s.getOrder(101L).setStatus(OrderStatus.DELIVERED);
+ s.updateOrder(o);
+ assertEquals(OrderStatus.DELIVERED, s.getOrder(101L).getStatus());
+ }
+
+ @Test void c03_deleteOrder_removes() {
+ var s = new PetStore();
+ s.deleteOrder(101L);
+ assertNull(s.getOrder(101L));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // d — users CRUD
+ //------------------------------------------------------------------------------------------------------------------
+
+ @Test void d01_createUser_byUsername() {
+ var s = new PetStore();
+ s.createUser(new User().setUsername("newuser").setFirstName("New").setUserStatus(UserStatus.ACTIVE));
+ assertNotNull(s.getUser("newuser"));
+ }
+
+ @Test void d02_createUser_duplicate_throws() {
+ var s = new PetStore();
+ assertThrows(IllegalArgumentException.class,
+ () -> s.createUser(new User().setUsername("mwatson").setUserStatus(UserStatus.ACTIVE)));
+ }
+
+ @Test void d03_updateUser_replacesContent() {
+ var s = new PetStore();
+ s.updateUser(s.getUser("mwatson").setFirstName("Mary"));
+ assertEquals("Mary", s.getUser("mwatson").getFirstName());
+ }
+
+ @Test void d04_deleteUser_removes() {
+ var s = new PetStore();
+ s.deleteUser("mwatson");
+ assertNull(s.getUser("mwatson"));
+ }
+}
diff --git a/juneau-sc/juneau-sc-server/juneau-server-config.cfg b/juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg
old mode 100755
new mode 100644
similarity index 51%
copy from juneau-sc/juneau-sc-server/juneau-server-config.cfg
copy to juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg
index a97e0aff3a..d09858b04a
--- a/juneau-sc/juneau-sc-server/juneau-server-config.cfg
+++ b/juneau-petstore/juneau-petstore-jetty/juneau-petstore-jetty.cfg
@@ -1,146 +1,120 @@
-# ***************************************************************************************************************************
-# * 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. *
-# ***************************************************************************************************************************
-
-#=======================================================================================================================
-# Basic configuration file for SaaS microservices
-# Subprojects can use this as a starting point.
-#=======================================================================================================================
-
-
-#=======================================================================================================================
-# Jetty settings
-#=======================================================================================================================
-[Jetty]
-
-# Path of the jetty.xml file used to configure the Jetty server.
-config = files/jetty.xml
-
-# Resolve Juneau variables in the jetty.xml file.
-resolveVars = true
-
-# Port to use for the jetty server.
-# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
-# The resulting available port gets set as the system property "availablePort" which can be referenced in the
-# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).
-port = 10000,0,0,0
-
-#=======================================================================================================================
-# REST settings
-#=======================================================================================================================
-[REST]
-
-# Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @Rest-annotated
-# classes. These are static files that are served up by the servlet under the specified sub-paths.
-# For example, given the following setting...
-# staticFiles = htdocs:my-docs,styles/my-styles
-# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css".
-# This path can be relative to the working directory, classpath root, or package of your resource class.
-# Used by the BasicRestConfig interface that defines the following value:
-# staticFiles="$C{REST/staticFiles}"
-staticFiles = htdocs:htdocs
-
-# Stylesheet to use for HTML views.
-# Used by the BasicRestConfig interface that defines the following value:
-# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}"
-theme = servlet:/htdocs/themes/devops.css
-
-# Various look-and-feel settings used in the BasicRestConfig interface.
-headerIcon = servlet:/htdocs/images/juneau.png
-headerLink = http://juneau.apache.org
-footerIcon = servlet:/htdocs/images/asf.png
-footerLink = http://www.apache.org
-favicon = $C{REST/headerIcon}
-header =
- <a href='$U{$C{REST/headerLink}}'>
- <img src='$U{$C{REST/headerIcon}}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/>
- </a>
-footer =
- <a href='$U{$C{REST/footerLink}}'>
- <img style='float:right;padding-right:20px;height:32px' src='$U{$C{REST/footerIcon}}'>
- </a>
-
-#=======================================================================================================================
-# Console settings
-#=======================================================================================================================
-[Console]
-
-enabled = true
-
-# List of available console commands.
-# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
-# the console.
-# When listed here, the implementations must provide a no-arg constructor.
-# They can also be provided dynamically by overriding the Microservice.createConsoleCommands() method.
-commands =
- org.apache.juneau.marshall.microservice.console.ExitCommand,
- org.apache.juneau.marshall.microservice.console.RestartCommand,
- org.apache.juneau.marshall.microservice.console.HelpCommand,
- org.apache.juneau.marshall.microservice.console.ConfigCommand,
- org.apache.juneau.marshall.examples.rest.command.EchoCommand
-
-#=======================================================================================================================
-# System properties
-#-----------------------------------------------------------------------------------------------------------------------
-# These are arbitrary system properties that can be set during startup.
-#=======================================================================================================================
-[SystemProperties]
-
-# Configure Jetty for StdErrLog Logging
-# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
-
-# Configure Jetty to log using java-util logging
-org.eclipse.jetty.util.log.class = org.apache.juneau.marshall.microservice.jetty.JettyLogger
-
-# Jetty logging level
-org.eclipse.jetty.LEVEL = WARN
-
-derby.stream.error.file = $C{Logging/logDir}/derby-errors.log
-
-# Note that any configuration properties can also be set globally as system properties...
-
-# Disable classpath resource caching.
-# Useful if you're attached using a debugger and you're modifying classpath resources while running.
-RestContext.disableClasspathResourceCaching.b = true
-
-#=======================================================================================================================
-# DockerRegistryResource properties
-#=======================================================================================================================
-[DockerRegistry]
-url = http://docker.apache.org:5000/v1
-
-#=======================================================================================================================
-# SqlQueryResource properties
-#=======================================================================================================================
-[SqlQueryResource]
-driver = org.apache.derby.jdbc.EmbeddedDriver
-directory = target/derby/testDB
-connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true
-allowTempUpdates = true
-includeRowNums = false
-
-#=======================================================================================================================
-# Source code location
-#=======================================================================================================================
-[Source]
-gitHub = https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java
-
-#=======================================================================================================================
-# PetStoreResource properties
-#=======================================================================================================================
-[PetStore]
-headerImage = <a href='http://swagger.io'><img src='$U{servlet:/htdocs/cat.png}' style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/></a>
-
-[GitServer]
-pathLocal = /home/marcelo/desenvolvimento/tmp/juneau-config-test
-gitRemote = https://github.com/marcelosv/juneau-config-test.git
-
+# ***************************************************************************************************************************
+# * 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. *
+# ***************************************************************************************************************************
+
+#=======================================================================================================================
+# juneau-petstore-jetty configuration
+#=======================================================================================================================
+
+
+#=======================================================================================================================
+# Jetty settings
+#=======================================================================================================================
+[Jetty]
+
+# Path of the jetty.xml file used to configure the Jetty server.
+config = files/jetty.xml
+
+# Resolve Juneau variables in the jetty.xml file.
+resolveVars = true
+
+# Port to use for the jetty server.
+# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
+# The resulting available port gets set as the system property "availablePort" which can be referenced in the
+# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).
+port = 10000,0,0,0
+
+
+#=======================================================================================================================
+# Console settings
+#=======================================================================================================================
+[Console]
+
+enabled = true
+
+# List of available console commands.
+# These are classes that implements ConsoleCommand that allow you to submit commands to the microservice via
+# the console.
+commands =
+ org.apache.juneau.marshall.microservice.console.ExitCommand,
+ org.apache.juneau.marshall.microservice.console.RestartCommand,
+ org.apache.juneau.marshall.microservice.console.HelpCommand,
+ org.apache.juneau.marshall.microservice.console.ConfigCommand
+
+
+#=======================================================================================================================
+# Logger settings
+#-----------------------------------------------------------------------------------------------------------------------
+# See FileHandler Java class for details.
+#=======================================================================================================================
+[Logging]
+
+# The directory where to create the log file.
+logDir = ./target/logs
+
+# The name of the log file to create for the main logger.
+logFile = microservice.%g.log
+
+# Whether to append to the existing log file or create a new one.
+append = false
+
+# The SimpleDateFormat format to use for dates.
+dateFormat = yyyy.MM.dd hh:mm:ss
+
+# The log message format.
+format = [{date} {level}] {msg}%n
+
+# The maximum log file size.
+limit = 1M
+
+# Max number of log files.
+count = 5
+
+# Default log levels.
+levels =
+ {
+ '': 'WARNING',
+ org.apache.juneau.marshall: 'WARNING',
+ org.eclipse.jetty: 'WARNING'
+ }
+
+# Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
+useStackTraceHashes = true
+
+# The default level for the console logger.
+consoleLevel = WARNING
+
+# The default level for the file logger.
+fileLevel = INFO
+
+
+#=======================================================================================================================
+# System properties
+#=======================================================================================================================
+[SystemProperties]
+
+# Configure Jetty to log using java-util logging.
+org.eclipse.jetty.util.log.class = org.apache.juneau.marshall.microservice.jetty.JettyLogger
+
+# Jetty logging level.
+org.eclipse.jetty.LEVEL = WARN
+
+# Disable classpath resource caching.
+# Useful if you're attached using a debugger and you're modifying classpath resources while running.
+RestContext.disableClasspathResourceCaching.b = true
+
+
+#=======================================================================================================================
+# Source code location
+#=======================================================================================================================
+[Source]
+gitHub = https://github.com/apache/juneau/blob/master/juneau-petstore/juneau-petstore-jetty/src/main/java
diff --git a/juneau-examples/juneau-examples-rest-jetty/pom.xml b/juneau-petstore/juneau-petstore-jetty/pom.xml
similarity index 57%
rename from juneau-examples/juneau-examples-rest-jetty/pom.xml
rename to juneau-petstore/juneau-petstore-jetty/pom.xml
index 36de70cb6a..e9438a6c1f 100644
--- a/juneau-examples/juneau-examples-rest-jetty/pom.xml
+++ b/juneau-petstore/juneau-petstore-jetty/pom.xml
@@ -21,14 +21,14 @@
<parent>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples</artifactId>
+ <artifactId>juneau-petstore</artifactId>
<version>10.0.0-SNAPSHOT</version>
</parent>
- <artifactId>juneau-examples-rest-jetty</artifactId>
- <name>Apache Juneau REST Jetty Examples</name>
- <description>Apache Juneau REST Examples using Jetty</description>
- <packaging>bundle</packaging>
+ <artifactId>juneau-petstore-jetty</artifactId>
+ <name>Apache Juneau Petstore Jetty</name>
+ <description>Apache Juneau Petstore - Jetty/Microservice deployment</description>
+ <packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -37,7 +37,7 @@
<dependencies>
<dependency>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples-rest</artifactId>
+ <artifactId>juneau-petstore-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -45,27 +45,42 @@
<artifactId>juneau-microservice-jetty</artifactId>
<version>${project.version}</version>
</dependency>
+
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-junit5</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-bct</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-rest-client-classic</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <supportIncrementalBuild>true</supportIncrementalBuild>
- </configuration>
- <executions>
- <execution>
- <id>bundle-manifest</id>
- <phase>process-classes</phase>
- <goals>
- <goal>manifest</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
@@ -79,7 +94,10 @@
</execution>
</executions>
</plugin>
-
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
@@ -93,7 +111,7 @@
<goal>single</goal>
</goals>
<configuration>
- <finalName>juneau-examples-rest-jetty-${project.version}</finalName>
+ <finalName>juneau-petstore-jetty-${project.version}</finalName>
<descriptors>
<descriptor>src/assembly/bin.xml</descriptor>
</descriptors>
@@ -101,6 +119,25 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-prepare-agent</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>default-report</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/assembly/bin.xml b/juneau-petstore/juneau-petstore-jetty/src/assembly/bin.xml
similarity index 72%
rename from juneau-examples/juneau-examples-rest-springboot/src/assembly/bin.xml
rename to juneau-petstore/juneau-petstore-jetty/src/assembly/bin.xml
index af351a1eed..5282bbbf32 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/assembly/bin.xml
+++ b/juneau-petstore/juneau-petstore-jetty/src/assembly/bin.xml
@@ -17,9 +17,10 @@
-->
<!--
- This assembly is used to create the template zip file that developers use to import into Eclipse to start their
- own projects.
- -->
+ Builds a starter zip — sources + classpath resources + petstore .cfg + jetty.xml + pom.xml — that can be
+ imported into an IDE or used as a template for derived petstore projects. Source-template style (not a
+ runnable distribution — no fat jar bundled).
+-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -32,31 +33,22 @@
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
- <directory>${basedir}/../juneau-examples-rest</directory>
- <outputDirectory>/</outputDirectory>
+ <directory>${basedir}/../juneau-petstore-core</directory>
+ <outputDirectory>juneau-petstore-core</outputDirectory>
<includes>
<include>src/main/**</include>
+ <include>pom.xml</include>
</includes>
</fileSet>
<fileSet>
<useDefaultExcludes>false</useDefaultExcludes>
<directory>${basedir}</directory>
- <outputDirectory>/</outputDirectory>
+ <outputDirectory>juneau-petstore-jetty</outputDirectory>
<includes>
<include>src/main/**</include>
- <include>files/**</include>
- <include>.settings/**</include>
- <include>.project</include>
- <include>.classpath</include>
- <include>*.launch</include>
<include>*.cfg</include>
+ <include>pom.xml</include>
</includes>
</fileSet>
- <fileSet>
- <directory>${basedir}/build-overlay</directory>
- <outputDirectory>/</outputDirectory>
- <filtered>true</filtered>
- </fileSet>
</fileSets>
-
-</assembly>
\ No newline at end of file
+</assembly>
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/App.java b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/App.java
similarity index 70%
rename from juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/App.java
rename to juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/App.java
index 6f11a30806..49bd27839b 100644
--- a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/App.java
+++ b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/App.java
@@ -14,29 +14,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.juneau.examples.rest.jetty;
+package org.apache.juneau.petstore.jetty;
import org.apache.juneau.commons.inject.*;
-import org.apache.juneau.examples.rest.*;
import org.apache.juneau.microservice.*;
import org.apache.juneau.microservice.jetty.*;
import jakarta.servlet.*;
/**
- * An example of an extended REST microservice.
+ * Petstore Jetty/Microservice deployment entry point.
*
* <p>
- * The {@link Microservice} class will locate the <c>examples.cfg</c> file in the home directory and initialize
- * the resources and commands defined in that file.
+ * Locates {@code juneau-petstore-jetty.cfg} (in the working directory or on the classpath), wires Jetty via
+ * {@link JettyConfiguration}, and mounts {@link RootResources} as the root servlet.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
*/
public class App {
/**
- * Entry point method.
+ * Entry point.
*
- * @param args Command line arguments.
- * @throws Exception General exception occurred.
+ * @param args Command-line arguments forwarded to {@link Microservice}.
+ * @throws Exception If the microservice fails to start.
*/
public static void main(String[] args) throws Exception {
// @formatter:off
@@ -58,7 +61,7 @@ public class App {
public static class AppConfig {
/**
- * Provides the top-level REST servlet, auto-mounted by {@link JettyServerComponent} at
+ * Provides the top-level REST servlet, auto-mounted by {@code JettyServerComponent} at
* {@link org.apache.juneau.rest.server.Rest#path()}.
*
* @return The root servlet.
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
similarity index 51%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
rename to juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
index 572aa05462..c12e14ab4c 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
+++ b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/RootResources.java
@@ -14,31 +14,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.juneau.examples.rest;
+package org.apache.juneau.petstore.jetty;
-import org.apache.juneau.examples.rest.dto.*;
import org.apache.juneau.marshall.html.*;
import org.apache.juneau.marshall.serializer.*;
import org.apache.juneau.microservice.resources.*;
+import org.apache.juneau.petstore.rest.*;
import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.servlet.*;
import org.apache.juneau.rest.server.widget.*;
/**
- * Sample REST resource showing how to implement a "router" resource page.
+ * Root router resource for the Jetty deployment.
*
+ * <p>
+ * Mounts the deployment-agnostic {@link PetStoreResource} from {@code juneau-petstore-core} and the
+ * Jetty/Microservice-specific admin resources ({@link ConfigResource}, {@link LogsResource},
+ * {@link ShutdownResource}). The admin trio is a documented Jetty-only non-parity feature — the Spring Boot
+ * deployment in {@code juneau-petstore-springboot} does not mount it.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
*
* @serial exclude
*/
@Rest(
- title="Root resources",
- description="Example of a router resource page.",
+ title="Juneau Petstore (Jetty)",
+ description="Apache Juneau petstore sample application running under Jetty/Microservice.",
children={
- HelloWorldResource.class,
- DtoExamples.class,
- UtilityBeansResource.class,
- HtmlBeansResource.class,
- SseDemoResource.class,
+ PetStoreResource.class,
+ PetSecureResource.class,
+ PetMustacheViewResource.class,
+ PetFreemarkerViewResource.class,
+ PetstoreUiResource.class,
ConfigResource.class,
LogsResource.class,
ShutdownResource.class
@@ -52,33 +61,27 @@ import org.apache.juneau.rest.server.widget.*;
"api: servlet:/api",
"stats: servlet:/stats",
"$W{ContentTypeMenuItem}",
- "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/RootResources.java"
+ "source: $C{Source/gitHub}/org/apache/juneau/petstore/jetty/RootResources.java"
},
aside={
"<div class='text'>",
- "\t<p>This is an example of a 'router' page that serves as a jumping-off point to child resources.</p>",
- "\t<p>Resources can be nested arbitrarily deep through router pages.</p>",
- "\t<p>Note the <span class='link'>API</span> link provided that lets you see the generated swagger doc for this page.</p>",
- "\t<p>Also note the <span class='link'>STATS</span> link to view runtime statistics on this page.</p>",
- "\t<p>Also note the <span class='link'>SOURCE</span> link to view the source code for the page.</p>",
- "\t<p>All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.</p>",
- "\t<p>Other features (such as this aside) are added through annotations.</p>",
+ "\t<p>Apache Juneau petstore sample application.</p>",
+ "\t<p>This is a 'router' page that serves as a jumping-off point to the petstore CRUD resource and",
+ "\t the microservice admin endpoints.</p>",
+ "\t<p>Click <span class='link'>API</span> for the generated swagger doc, or <span class='link'>STATS</span>",
+ "\t for runtime statistics.</p>",
"</div>"
},
asideFloat="RIGHT"
)
@SerializerConfig(
- // For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple
- // String comparisons.
- // You can apply any of the Serializer/Parser/MarshallingContext settings this way.
+ // For consistency with other Juneau samples — single quotes simplify HTML/string assertions in tests.
quoteChar="'"
)
@SuppressWarnings({
"java:S110" // Inheritance depth acceptable for example/demo code
})
public class RootResources extends BasicRestServletGroup {
- // IMPORTANT! If you don't need RDF support, change the parent interface to BasicUniversalConfig.
- // It allows you to remove the Jena prerequisite.
private static final long serialVersionUID = 1L;
-}
\ No newline at end of file
+}
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/package-info.java
old mode 100755
new mode 100644
similarity index 63%
copy from juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
copy to juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/package-info.java
index 0ba233d284..3b5647dc5b
--- a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
+++ b/juneau-petstore/juneau-petstore-jetty/src/main/java/org/apache/juneau/petstore/jetty/package-info.java
@@ -15,11 +15,12 @@
* limitations under the License.
*/
/**
- * REST Jetty Examples
+ * Apache Juneau Petstore - Jetty/Microservice deployment.
*
* <p>
- * Example classes demonstrating how to deploy Juneau REST servers using Jetty.
- * These examples show various Jetty-based REST API deployment scenarios.
- * </p>
+ * Provides {@link org.apache.juneau.petstore.jetty.App} (the {@link org.apache.juneau.microservice.Microservice}
+ * bootstrap) and {@link org.apache.juneau.petstore.jetty.RootResources} (the root router that mounts
+ * {@link org.apache.juneau.petstore.rest.PetStoreResource} from {@code juneau-petstore-core} alongside the
+ * Jetty/Microservice admin resources).
*/
-package org.apache.juneau.examples.rest.jetty;
+package org.apache.juneau.petstore.jetty;
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/main/resources/jetty.xml b/juneau-petstore/juneau-petstore-jetty/src/main/resources/jetty.xml
similarity index 64%
rename from juneau-examples/juneau-examples-rest-jetty/src/main/resources/jetty.xml
rename to juneau-petstore/juneau-petstore-jetty/src/main/resources/jetty.xml
index edf7af7a71..78bab32aef 100644
--- a/juneau-examples/juneau-examples-rest-jetty/src/main/resources/jetty.xml
+++ b/juneau-petstore/juneau-petstore-jetty/src/main/resources/jetty.xml
@@ -17,22 +17,22 @@
limitations under the License.
-->
-<Configure id="ExampleServer" class="org.eclipse.jetty.server.Server">
+<Configure id="PetstoreServer" class="org.eclipse.jetty.server.Server">
<Set name="connectors">
<Array type="org.eclipse.jetty.server.Connector">
<Item>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg>
- <Ref refid="ExampleServer" />
+ <Ref refid="PetstoreServer" />
</Arg>
- <Set name="port">$S{availablePort,8080}</Set>
+ <Set name="port">$S{availablePort,10000}</Set>
</New>
</Item>
</Array>
</Set>
- <!-- Juneau adds its servlets in this ServletContextHandler -->
+ <!-- Juneau adds its servlets in this ServletContextHandler -->
<New id="context" class="org.eclipse.jetty.ee11.servlet.ServletContextHandler">
<Set name="contextPath">/</Set>
<Set name="sessionHandler">
@@ -40,28 +40,28 @@
</Set>
</New>
- <!-- Save ServletContextHandler for Juneau -->
- <Call name="setAttribute">
- <Arg>ServletContextHandler</Arg>
- <Arg><Ref refid="context" /></Arg>
- </Call>
-
+ <!-- Save ServletContextHandler for Juneau -->
+ <Call name="setAttribute">
+ <Arg>ServletContextHandler</Arg>
+ <Arg><Ref refid="context" /></Arg>
+ </Call>
+
<Set name="handler">
- <New id="collection" class="org.eclipse.jetty.server.handler.ContextHandlerCollection">
- <Arg>
+ <New id="collection" class="org.eclipse.jetty.server.handler.ContextHandlerCollection">
+ <Arg>
<Array type="org.eclipse.jetty.server.handler.ContextHandler">
- <Item>
- <New class="org.eclipse.jetty.server.handler.ContextHandler">
- <!-- This is setHandler(Supplier) -->
- <Set name="handler"><Ref refid="context" /></Set>
- </New>
- </Item>
<Item>
<New class="org.eclipse.jetty.server.handler.ContextHandler">
- <New class="org.eclipse.jetty.server.handler.DefaultHandler" />
- </New>
+ <!-- This is setHandler(Supplier) -->
+ <Set name="handler"><Ref refid="context" /></Set>
+ </New>
+ </Item>
+ <Item>
+ <New class="org.eclipse.jetty.server.handler.ContextHandler">
+ <New class="org.eclipse.jetty.server.handler.DefaultHandler" />
+ </New>
</Item>
- </Array>
+ </Array>
</Arg>
</New>
</Set>
@@ -81,14 +81,14 @@
<!-- Param 1: String -->
<Arg>
<Get class="org.eclipse.jetty.server.CustomRequestLog" name="EXTENDED_NCSA_FORMAT" />
- </Arg>
+ </Arg>
</New>
</Set>
- <Get name="ThreadPool">
- <Set name="minThreads" type="int">10</Set>
- <Set name="maxThreads" type="int">100</Set>
- <Set name="idleTimeout" type="int">60000</Set>
- <Set name="detailedDump">true</Set>
- </Get>
+ <Get name="ThreadPool">
+ <Set name="minThreads" type="int">10</Set>
+ <Set name="maxThreads" type="int">100</Set>
+ <Set name="idleTimeout" type="int">60000</Set>
+ <Set name="detailedDump">true</Set>
+ </Get>
</Configure>
diff --git a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/microservice/MicroserviceTestFixture.java b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/microservice/MicroserviceTestFixture.java
new file mode 100644
index 0000000000..4696ad2896
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/microservice/MicroserviceTestFixture.java
@@ -0,0 +1,199 @@
+/*
+ * 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.juneau.microservice;
+
+import java.net.*;
+import java.util.*;
+
+import org.apache.juneau.commons.inject.*;
+import org.apache.juneau.microservice.jetty.*;
+import org.eclipse.jetty.ee11.servlet.*;
+import org.eclipse.jetty.server.*;
+import org.junit.jupiter.api.extension.*;
+
+/**
+ * JUnit 5 extension that boots a {@link Microservice} backed by {@link JettyConfiguration} on an ephemeral port for
+ * the duration of a test class.
+ *
+ * <p>
+ * Typical usage:
+ *
+ * <p class='bjava'>
+ * <ja>@RegisterExtension</ja>
+ * <jk>static</jk> MicroserviceTestFixture <jv>fixture</jv> = MicroserviceTestFixture.<jsm>create</jsm>()
+ * .configurations(MyServerConfig.<jk>class</jk>);
+ *
+ * <ja>@Configuration</ja>
+ * <jk>static class</jk> MyServerConfig {{
+ * <ja>@Bean</ja> Servlet myService() {{ <jk>return new</jk> MyRestService(); }}
+ * }}
+ *
+ * <ja>@Test</ja>
+ * <jk>void</jk> exampleTest() {{
+ * <jk>var</jk> rootUrl = <jv>fixture</jv>.getRootUrl();
+ * <jc>// build a client against rootUrl ...</jc>
+ * }}
+ * </p>
+ *
+ * <h5 class='section'>How it works:</h5>
+ * <ul>
+ * <li>The fixture installs {@link JettyConfiguration} plus a private {@link EphemeralJettyServerConfig}
+ * {@code @Configuration} that contributes a Jetty {@link Server} bound to port {@code 0} (OS-assigned
+ * ephemeral port). User-supplied configurations should typically contribute {@code @Bean Servlet} definitions
+ * which {@link JettyServerComponent} auto-mounts at {@code @Rest(path=...)}.
+ * <li>{@link #beforeAll(ExtensionContext) beforeAll} builds and {@link Microservice#start() starts} the service,
+ * then probes the bound port via the {@link Server}'s {@link ServerConnector}.
+ * <li>{@link #afterAll(ExtensionContext) afterAll} calls {@link Microservice#stop() stop()} so the bound port is
+ * released and {@code @PreDestroy} hooks on bean-store beans fire.
+ * </ul>
+ *
+ * <p>
+ * The fixture is intended to amortize Jetty-startup cost across a whole test class — combined with the dynamic
+ * {@link org.apache.juneau.rest.server.RestChildren#addChild RestChildren.addChild} / {@code removeChild} API, individual
+ * test methods can mount and unmount their own child resources against a single long-running server.
+ */
+public final class MicroserviceTestFixture implements BeforeAllCallback, AfterAllCallback {
+
+ private final List<Class<?>> configurations = new ArrayList<>();
+ private Microservice microservice;
+ private URI rootUrl;
+
+ private MicroserviceTestFixture() {}
+
+ /**
+ * Creates a new fixture.
+ *
+ * @return A new fixture instance.
+ */
+ public static MicroserviceTestFixture create() {
+ return new MicroserviceTestFixture();
+ }
+
+ /**
+ * Registers one or more {@code @Configuration} classes whose {@code @Bean Servlet} methods will be auto-mounted
+ * by the microservice. May be called multiple times to append.
+ *
+ * @param cs The configuration classes.
+ * @return This fixture (fluent).
+ */
+ public MicroserviceTestFixture configurations(Class<?>... cs) {
+ Collections.addAll(configurations, cs);
+ return this;
+ }
+
+ /**
+ * Returns the root URI of the running microservice (after {@link #beforeAll(ExtensionContext)} has fired).
+ *
+ * @return The root URI, e.g. {@code http://localhost:54321/}.
+ */
+ public URI getRootUrl() {
+ return rootUrl;
+ }
+
+ /**
+ * Returns the actual port the server is listening on (post-{@code start()}).
+ *
+ * @return The bound port.
+ */
+ public int getPort() {
+ return rootUrl.getPort();
+ }
+
+ /**
+ * Returns the underlying microservice instance, useful for fixture-scoped child-resource mutations.
+ *
+ * @return The microservice.
+ */
+ public Microservice getMicroservice() {
+ return microservice;
+ }
+
+ /**
+ * Returns the {@link JettyServerComponent} bean for the running microservice.
+ *
+ * @return The Jetty server component.
+ */
+ public JettyServerComponent getJettyServerComponent() {
+ return microservice.getBeanStore().getBean(JettyServerComponent.class).orElseThrow();
+ }
+
+ @Override
+ public void beforeAll(ExtensionContext ctx) throws Exception {
+ // The user's configurations come first (so @Bean Servlet methods are visible); EphemeralJettyServerConfig
+ // supplies the Jetty Server bound to port 0; JettyConfiguration wires the lifecycle and remaining defaults.
+ // JettyServerComponent resolves Server from the bean store by type, and BeanStore.getBean(...) returns the
+ // first registered match (so a user-supplied @Bean Server would still win).
+ var classes = new ArrayList<>(configurations);
+ classes.add(EphemeralJettyServerConfig.class);
+ classes.add(JettyConfiguration.class);
+ microservice = Microservice.create()
+ .configurations(classes.toArray(new Class<?>[0]))
+ .build();
+ microservice.start();
+ // JettyServerComponent.getURI() uses InetAddress.getLocalHost().getHostName() (may resolve to a non-loopback
+ // IP on some machines) and ServerConnector.getPort() (returns the configured port = 0, not the bound port).
+ // For test fixtures we want a deterministic loopback URL with the actual bound port.
+ var server = getJettyServerComponent().getServer();
+ var localPort = -1;
+ for (var c : server.getConnectors()) {
+ if (c instanceof ServerConnector sc) {
+ localPort = sc.getLocalPort();
+ break;
+ }
+ }
+ if (localPort <= 0)
+ throw new IllegalStateException("Could not determine local port of ServerConnector after start.");
+ rootUrl = URI.create("http://localhost:" + localPort);
+ }
+
+ @Override
+ public void afterAll(ExtensionContext ctx) throws Exception {
+ if (microservice != null)
+ microservice.stop();
+ }
+
+ /**
+ * Default {@code @Configuration} that supplies a Jetty {@link Server} bound to port {@code 0}.
+ *
+ * <p>
+ * The server has a single {@link ServerConnector} on port 0 (OS-assigned) and a single root
+ * {@link ServletContextHandler} at context path {@code "/"}. {@link JettyServerComponent} discovers the handler
+ * via the {@code "ServletContextHandler"} server attribute (the same convention used by {@code jetty.xml}).
+ */
+ @Configuration
+ public static class EphemeralJettyServerConfig {
+
+ /**
+ * Provides the bean-supplied Jetty {@link Server} that {@link JettyServerComponent} consumes during
+ * {@code onStart()}.
+ *
+ * @return A configured {@link Server} bound to port 0.
+ */
+ @Bean
+ public Server jettyServer() {
+ var server = new Server();
+ var connector = new ServerConnector(server);
+ connector.setPort(0);
+ server.addConnector(connector);
+ var sch = new ServletContextHandler();
+ sch.setContextPath("/");
+ server.setAttribute("ServletContextHandler", sch);
+ server.setHandler(sch);
+ return server;
+ }
+ }
+}
diff --git a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
new file mode 100644
index 0000000000..905bcab0d2
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
@@ -0,0 +1,245 @@
+/*
+ * 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.juneau.petstore.jetty;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.net.*;
+import java.net.http.*;
+import java.net.http.HttpResponse.*;
+import java.time.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.microservice.*;
+import org.apache.juneau.testing.annotations.*;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.*;
+
+/**
+ * Integration test that boots the petstore Jetty deployment on an ephemeral port and exercises the CRUD surface
+ * + content-negotiation through a real HTTP client.
+ *
+ * <p>
+ * Tagged {@code @JettyMicroserviceTest} (which composes {@code @Tag("container")} + {@code @Tag("jetty")}) so it
+ * skips under {@code scripts/test.py --no-container}.
+ */
+@JettyMicroserviceTest
+class PetstoreJetty_Test extends TestBase {
+
+ @RegisterExtension
+ static MicroserviceTestFixture fixture = MicroserviceTestFixture.create()
+ .configurations(App.AppConfig.class);
+
+ private static final HttpClient HTTP = HttpClient.newBuilder()
+ .connectTimeout(Duration.ofSeconds(5))
+ .followRedirects(HttpClient.Redirect.NEVER)
+ .build();
+
+ private static HttpResponse<String> get(String path, String accept) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create(fixture.getRootUrl() + path))
+ .timeout(Duration.ofSeconds(10))
+ .header("Accept", accept)
+ .GET()
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ private static HttpResponse<String> getWithAuth(String path, String accept, String authValue) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create(fixture.getRootUrl() + path))
+ .timeout(Duration.ofSeconds(10))
+ .header("Accept", accept)
+ .header("Authorization", authValue)
+ .GET()
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ private static HttpResponse<String> post(String path, String contentType, String body) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create(fixture.getRootUrl() + path))
+ .timeout(Duration.ofSeconds(10))
+ .header("Content-Type", contentType)
+ .header("Accept", "application/json")
+ .POST(HttpRequest.BodyPublishers.ofString(body))
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ private static HttpResponse<String> delete(String path) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create(fixture.getRootUrl() + path))
+ .timeout(Duration.ofSeconds(10))
+ .DELETE()
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // a — root router page
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void a01_rootRendersHtml() throws Exception {
+ var resp = get("/", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ var body = resp.body();
+ assertTrue(body.contains("petstore"), "expected petstore link on root: " + body);
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // b — petstore CRUD over real HTTP, JSON
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void b01_listPets_jsonContainsSeed() throws Exception {
+ var resp = get("/petstore/pets", "application/json");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ var ct = resp.headers().firstValue("Content-Type").orElse("");
+ assertTrue(ct.startsWith("application/json"), "Content-Type was: " + ct);
+ assertTrue(resp.body().contains("Mr. Frisky"), "expected seeded pet name in response: " + resp.body());
+ }
+
+ @Test void b02_getPet_byId_json() throws Exception {
+ var resp = get("/petstore/pets/1", "application/json");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("\"name\":\"Mr. Frisky\""), resp.body());
+ }
+
+ @Test void b03_getPet_unknown_404() throws Exception {
+ var resp = get("/petstore/pets/99999", "application/json");
+ assertEquals(404, resp.statusCode(), "body: " + resp.body());
+ }
+
+ @Test void b04_createPet_thenGet_roundTrip() throws Exception {
+ var body = "{\"name\":\"Wanda\",\"species\":\"RABBIT\",\"price\":12.50,\"status\":\"AVAILABLE\"}";
+ var post = post("/petstore/pets", "application/json", body);
+ assertEquals(200, post.statusCode(), "post body: " + post.body());
+ // Extract id from posted response (assigned server-side).
+ var id = extractLong(post.body(), "\"id\":");
+ assertNotEquals(0L, id, "server-assigned id missing in: " + post.body());
+
+ var get = get("/petstore/pets/" + id, "application/json");
+ assertEquals(200, get.statusCode(), "get body: " + get.body());
+ assertTrue(get.body().contains("\"name\":\"Wanda\""), get.body());
+ }
+
+ @Test void b05_deletePet_removes() throws Exception {
+ // Seed has pet id=2; delete then verify 404.
+ var del = delete("/petstore/pets/2");
+ assertEquals(200, del.statusCode(), "delete body: " + del.body());
+ var get = get("/petstore/pets/2", "application/json");
+ assertEquals(404, get.statusCode());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // c — content negotiation
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void c01_listPets_xml() throws Exception {
+ var resp = get("/petstore/pets", "text/xml");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ var ct = resp.headers().firstValue("Content-Type").orElse("");
+ assertTrue(ct.startsWith("text/xml"), "Content-Type was: " + ct);
+ assertTrue(resp.body().contains("Mr. Frisky"), resp.body());
+ }
+
+ @Test void c02_listPets_html() throws Exception {
+ var resp = get("/petstore/pets", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ var ct = resp.headers().firstValue("Content-Type").orElse("");
+ assertTrue(ct.startsWith("text/html"), "Content-Type was: " + ct);
+ assertTrue(resp.body().contains("Mr. Frisky"), resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // d — view-engine demos (parity with springboot deployment — both inherit from core)
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void d01_mustacheView_rendersPet() throws Exception {
+ var resp = get("/pet-views/mustache/pets/1/view", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ var ct = resp.headers().firstValue("Content-Type").orElse("");
+ assertTrue(ct.startsWith("text/html"), "Content-Type was: " + ct);
+ assertTrue(resp.body().contains("Mr. Frisky"), "expected pet name in mustache view: " + resp.body());
+ assertTrue(resp.body().contains("Rendered via Mustache."), "expected mustache marker: " + resp.body());
+ }
+
+ @Test void d02_freemarkerView_rendersPet() throws Exception {
+ var resp = get("/pet-views/freemarker/pets/1/view", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ var ct = resp.headers().firstValue("Content-Type").orElse("");
+ assertTrue(ct.startsWith("text/html"), "Content-Type was: " + ct);
+ assertTrue(resp.body().contains("Mr. Frisky"), "expected pet name in freemarker view: " + resp.body());
+ assertTrue(resp.body().contains("Rendered via FreeMarker."), "expected freemarker marker: " + resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // e — AuthFilterChain gating /petstore-secure/* (parity with springboot deployment)
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void e01_secureEndpoint_noAuth_401() throws Exception {
+ var resp = get("/petstore-secure/pets", "application/json");
+ assertEquals(401, resp.statusCode(), "body: " + resp.body());
+ var challenge = resp.headers().firstValue("WWW-Authenticate").orElse("");
+ assertTrue(challenge.contains("Bearer"), "WWW-Authenticate should advertise Bearer scheme: " + challenge);
+ }
+
+ @Test void e02_secureEndpoint_validToken_200() throws Exception {
+ var resp = getWithAuth("/petstore-secure/pets", "application/json", "Bearer petstore-user");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), "body: " + resp.body());
+ }
+
+ @Test void e03_secureEndpoint_unknownToken_401() throws Exception {
+ var resp = getWithAuth("/petstore-secure/pets", "application/json", "Bearer wrong-token");
+ assertEquals(401, resp.statusCode(), "body: " + resp.body());
+ }
+
+ @Test void e04_secureEndpoint_whoami_returnsPrincipalName() throws Exception {
+ var resp = getWithAuth("/petstore-secure/whoami", "application/json", "Bearer petstore-admin");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("\"name\":\"admin\""), "body: " + resp.body());
+ }
+
+ @Test void e05_unsecuredEndpoint_stillOpen() throws Exception {
+ // /petstore/* is NOT in the chain pattern, so anonymous access still works.
+ var resp = get("/petstore/pets/1", "application/json");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // helpers
+ //-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Cheap brittle JSON int extractor — finds the first occurrence of {@code key} (e.g. {@code "id":}) and reads
+ * the integer that follows. Sufficient for the simple CRUD round-trip assertions; we don't pull in a full JSON
+ * parser just for this test class.
+ */
+ private static long extractLong(String body, String key) {
+ var i = body.indexOf(key);
+ if (i < 0)
+ return 0L;
+ i += key.length();
+ var end = i;
+ while (end < body.length() && (Character.isDigit(body.charAt(end)) || body.charAt(end) == '-'))
+ end++;
+ if (end == i)
+ return 0L;
+ return Long.parseLong(body.substring(i, end));
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/testing/annotations/JettyMicroserviceTest.java
old mode 100755
new mode 100644
similarity index 72%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
copy to juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/testing/annotations/JettyMicroserviceTest.java
index dd83076900..a9dd6b690e
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
+++ b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/testing/annotations/JettyMicroserviceTest.java
@@ -14,12 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.testing.annotations;
+
+import java.lang.annotation.*;
+
+import org.junit.jupiter.api.*;
+
/**
- * REST Command Examples
- *
- * <p>
- * Example classes demonstrating how to use command pattern with Juneau's REST server.
- * These examples show various command-based REST API scenarios.
- * </p>
+ * Marker for container-backed Jetty microservice tests.
*/
-package org.apache.juneau.examples.rest.command;
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Tag("container")
+@Tag("jetty")
+public @interface JettyMicroserviceTest {}
diff --git a/juneau-examples/juneau-examples-rest-springboot/pom.xml b/juneau-petstore/juneau-petstore-springboot/pom.xml
similarity index 63%
rename from juneau-examples/juneau-examples-rest-springboot/pom.xml
rename to juneau-petstore/juneau-petstore-springboot/pom.xml
index c08ac1a052..aeb3cd27d0 100644
--- a/juneau-examples/juneau-examples-rest-springboot/pom.xml
+++ b/juneau-petstore/juneau-petstore-springboot/pom.xml
@@ -21,13 +21,14 @@
<parent>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples</artifactId>
+ <artifactId>juneau-petstore</artifactId>
<version>10.0.0-SNAPSHOT</version>
</parent>
- <artifactId>juneau-examples-rest-springboot</artifactId>
- <name>Apache Juneau REST Spring Boot Examples</name>
- <description>Apache Juneau REST Examples using Spring Boot</description>
+ <artifactId>juneau-petstore-springboot</artifactId>
+ <name>Apache Juneau Petstore Spring Boot</name>
+ <description>Apache Juneau Petstore - Spring Boot deployment</description>
+ <packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -36,7 +37,7 @@
<dependencies>
<dependency>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-examples-rest</artifactId>
+ <artifactId>juneau-petstore-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@@ -44,10 +45,37 @@
<artifactId>juneau-rest-server-springboot</artifactId>
<version>${project.version}</version>
</dependency>
+
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-junit5</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.juneau</groupId>
+ <artifactId>juneau-bct</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
+ <artifactId>spring-boot-starter-test</artifactId>
<version>${spring.version}</version>
+ <scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
@@ -72,6 +100,10 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
@@ -85,40 +117,24 @@
</executions>
</plugin>
<plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <configuration>
- <escapeString>\</escapeString>
- </configuration>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
- <id>juneau-assembly</id>
- <phase>package</phase>
+ <id>default-prepare-agent</id>
<goals>
- <goal>single</goal>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>default-report</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>report</goal>
</goals>
- <configuration>
- <finalName>juneau-examples-rest-springboot-${project.version}</finalName>
- <descriptors>
- <descriptor>src/assembly/bin.xml</descriptor>
- </descriptors>
- </configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
-
- <distributionManagement>
- <repository>
- <id>apache.releases.https</id>
- <name>Apache Release Distribution Repository</name>
- <url>https://repository.apache.org/service/local/staging/deploy/maven2</url>
- </repository>
- <snapshotRepository>
- <id>apache.snapshots.https</id>
- <name>Apache Development Snapshot Repository</name>
- <url>https://repository.apache.org/content/repositories/snapshots</url>
- </snapshotRepository>
- </distributionManagement>
-
</project>
diff --git a/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/App.java b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/App.java
new file mode 100644
index 0000000000..cccf059bbd
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/App.java
@@ -0,0 +1,98 @@
+/*
+ * 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.juneau.petstore.springboot;
+
+import org.springframework.boot.autoconfigure.*;
+import org.springframework.boot.builder.*;
+import org.springframework.boot.web.servlet.*;
+import org.springframework.context.annotation.*;
+import org.springframework.stereotype.*;
+
+import jakarta.servlet.*;
+
+/**
+ * Petstore Spring Boot deployment entry point.
+ *
+ * <p>
+ * Boots a Spring Boot embedded servlet container, wires {@link RootResources} as a Spring bean, and mounts it at
+ * {@code /*} via {@link ServletRegistrationBean}.
+ *
+ * <p>
+ * Provides a {@code @Bean HelloMessageProvider} to demonstrate Spring {@code @Autowired} injection into the
+ * companion {@link HelloResource} child — preserving the deployment-glue Spring-injection demo.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ */
+@SpringBootApplication
+@Controller
+public class App {
+
+ /**
+ * Entry point.
+ *
+ * @param args Command-line arguments forwarded to Spring Boot.
+ */
+ @SuppressWarnings({
+ "resource" // ApplicationContext is owned by Spring; not a leak.
+ })
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(App.class).run(args);
+ }
+
+ /**
+ * Spring-injected message provider consumed by {@link HelloResource}.
+ *
+ * @return The hello-message provider bean.
+ */
+ @Bean
+ public HelloMessageProvider helloMessageProvider() {
+ return new HelloMessageProvider("Hello from Spring-injected bean!");
+ }
+
+ /**
+ * Returns {@link HelloResource} as a Spring bean so {@code @Autowired} fields resolve.
+ *
+ * @return The hello-world REST resource.
+ */
+ @Bean
+ public HelloResource helloResource() {
+ return new HelloResource();
+ }
+
+ /**
+ * Returns the root router as a Spring bean so child resources resolve as Spring beans.
+ *
+ * @return The root router REST resource.
+ */
+ @Bean
+ public RootResources rootResources() {
+ return new RootResources();
+ }
+
+ /**
+ * Mounts the root router servlet at {@code /*}.
+ *
+ * @param rootResources The Spring-managed root router.
+ * @return The servlet registration mapped to {@code /*}.
+ */
+ @Bean
+ public ServletRegistrationBean<Servlet> rootServlet(RootResources rootResources) {
+ return new ServletRegistrationBean<>(rootResources, "/*");
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/HelloMessageProvider.java
similarity index 64%
rename from juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
rename to juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/HelloMessageProvider.java
index 665715d937..e043841aa6 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
+++ b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/HelloMessageProvider.java
@@ -14,27 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.juneau.examples.rest.springboot;
+package org.apache.juneau.petstore.springboot;
import java.util.function.*;
/**
- * An example of a Spring bean that can be used for injecting messages into {@link HelloWorldResource}.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>
- * </ul>
+ * Sample Spring bean injected into {@link HelloResource} to demonstrate the {@code @Autowired} pattern under
+ * Juneau {@code SpringRestServlet}-based deployments.
*/
-public class HelloWorldMessageProvider implements Supplier<String> {
+public class HelloMessageProvider implements Supplier<String> {
private final String message;
/**
* Constructor.
*
- * @param message The message to display.
+ * @param message The message to surface from {@link #get()}.
*/
- public HelloWorldMessageProvider(String message) {
+ public HelloMessageProvider(String message) {
this.message = message;
}
@@ -42,4 +39,4 @@ public class HelloWorldMessageProvider implements Supplier<String> {
public String get() {
return message;
}
-}
\ No newline at end of file
+}
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldResource.java b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/HelloResource.java
similarity index 51%
rename from juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldResource.java
rename to juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/HelloResource.java
index cb68020b77..a0fd3aa253 100644
--- a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldResource.java
+++ b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/HelloResource.java
@@ -14,46 +14,42 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.juneau.examples.rest.springboot;
+package org.apache.juneau.petstore.springboot;
-import org.apache.juneau.marshall.html.*;
import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.servlet.*;
import org.springframework.beans.factory.annotation.*;
/**
- * Sample REST resource that prints out a simple "Hello world!" message.
+ * Tiny REST resource that demonstrates Spring {@code @Autowired} injection into a Juneau {@code @Rest} servlet
+ * under a Spring Boot deployment. Mirrors the legacy {@code HelloWorldResource} demo.
+ *
+ * <p>
+ * The {@link HelloMessageProvider} bean is wired by Spring; the {@code GET /hello/*} endpoint surfaces its message.
+ * Resolution of the {@code HelloMessageProvider} bean works because the parent router extends
+ * {@code BasicSpringRestServletGroup} (i.e. {@code SpringRestServlet}), which lets child resources be Spring beans.
*
* <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>
-
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
* </ul>
*/
@Rest(
- title="Hello World",
- description="An example of the simplest-possible resource",
- path="/helloWorld"
-)
-@HtmlDocConfig(
- aside={
- "<div style='max-width:400px' class='text'>",
- "\t<p>This page shows a resource that simply response with a 'Hello world!' message</p>",
- "\t<p>The POJO serialized is a simple String.</p>",
- "</div>"
- }
+ path="/hello",
+ title="Hello (Spring injection demo)",
+ description="A trivial REST resource demonstrating Spring @Autowired injection of a HelloMessageProvider bean."
)
-public class HelloWorldResource extends BasicRestResource {
+public class HelloResource extends BasicRestResource {
@Autowired
- private HelloWorldMessageProvider messageProvider;
+ private HelloMessageProvider messageProvider;
/**
- * GET request handler.
+ * GET /hello/* — returns the message provided by the injected Spring bean.
*
- * @return A simple Hello-World message.
+ * @return The injected message.
*/
- @RestGet(path = "/*", summary = "Responds with injected message")
+ @RestGet(path="/*", summary="Responds with the Spring-injected message.")
public String sayHello() {
return messageProvider.get();
}
-}
\ No newline at end of file
+}
diff --git a/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java
new file mode 100644
index 0000000000..0a1034bfbb
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/RootResources.java
@@ -0,0 +1,88 @@
+/*
+ * 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.juneau.petstore.springboot;
+
+import org.apache.juneau.marshall.html.*;
+import org.apache.juneau.marshall.serializer.*;
+import org.apache.juneau.petstore.rest.*;
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.springboot.*;
+import org.apache.juneau.rest.server.widget.*;
+
+/**
+ * Root router resource for the Spring Boot deployment.
+ *
+ * <p>
+ * Extends {@link BasicSpringRestServletGroup} (i.e. {@link SpringRestServlet}) so child resources can be resolved
+ * as Spring beans — required for {@link HelloResource} to receive its {@code @Autowired} {@link HelloMessageProvider}.
+ * Mounts the deployment-agnostic {@link PetStoreResource} from {@code juneau-petstore-core} alongside the local
+ * {@link HelloResource} injection demo.
+ *
+ * <p>
+ * Note: this Spring Boot deployment intentionally does NOT mount the Jetty/Microservice admin trio
+ * ({@code ConfigResource}/{@code LogsResource}/{@code ShutdownResource}) — those are Jetty-only and have no
+ * meaningful analogue here (Spring Boot has its own actuator surface). This is the documented non-parity
+ * deployment-specific difference between the two petstore deployments.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstoreOverview">juneau-petstore</a>
+ * </ul>
+ *
+ * @serial exclude
+ */
+@Rest(
+ title="Juneau Petstore (Spring Boot)",
+ description="Apache Juneau petstore sample application running under Spring Boot.",
+ children={
+ PetStoreResource.class,
+ PetSecureResource.class,
+ PetMustacheViewResource.class,
+ PetFreemarkerViewResource.class,
+ PetstoreUiResource.class,
+ HelloResource.class
+ }
+)
+@HtmlDocConfig(
+ widgets={
+ ContentTypeMenuItem.class
+ },
+ navlinks={
+ "api: servlet:/api",
+ "stats: servlet:/stats",
+ "$W{ContentTypeMenuItem}",
+ "source: $C{Source/gitHub}/org/apache/juneau/petstore/springboot/RootResources.java"
+ },
+ aside={
+ "<div class='text'>",
+ "\t<p>Apache Juneau petstore sample application — Spring Boot deployment.</p>",
+ "\t<p>This is the same Juneau REST surface as the Jetty deployment, deployed unchanged under Spring Boot",
+ "\t (note: child resources resolve as Spring beans).</p>",
+ "</div>"
+ },
+ asideFloat="RIGHT"
+)
+@SerializerConfig(
+ // Single quotes for consistency with other Juneau samples — simplifies HTML/string assertions in tests.
+ quoteChar="'"
+)
+@SuppressWarnings({
+ "java:S110" // Inheritance depth acceptable for example/demo code
+})
+public class RootResources extends BasicSpringRestServletGroup {
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/package-info.java
old mode 100755
new mode 100644
similarity index 59%
rename from juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
rename to juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/package-info.java
index 0ba233d284..135781fc29
--- a/juneau-examples/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/package-info.java
+++ b/juneau-petstore/juneau-petstore-springboot/src/main/java/org/apache/juneau/petstore/springboot/package-info.java
@@ -15,11 +15,13 @@
* limitations under the License.
*/
/**
- * REST Jetty Examples
+ * Apache Juneau Petstore - Spring Boot deployment.
*
* <p>
- * Example classes demonstrating how to deploy Juneau REST servers using Jetty.
- * These examples show various Jetty-based REST API deployment scenarios.
- * </p>
+ * Provides {@link org.apache.juneau.petstore.springboot.App} ({@code @SpringBootApplication} bootstrap) and
+ * {@link org.apache.juneau.petstore.springboot.RootResources} ({@code BasicSpringRestServletGroup}-based router
+ * mounting {@link org.apache.juneau.petstore.rest.PetStoreResource} from {@code juneau-petstore-core}). The
+ * {@link org.apache.juneau.petstore.springboot.HelloResource} child preserves the legacy {@code @Autowired}
+ * injection demo.
*/
-package org.apache.juneau.examples.rest.jetty;
+package org.apache.juneau.petstore.springboot;
diff --git a/juneau-examples/juneau-examples-rest-springboot/src/main/resources/application.properties b/juneau-petstore/juneau-petstore-springboot/src/main/resources/application.properties
similarity index 100%
rename from juneau-examples/juneau-examples-rest-springboot/src/main/resources/application.properties
rename to juneau-petstore/juneau-petstore-springboot/src/main/resources/application.properties
diff --git a/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
new file mode 100644
index 0000000000..c7e4030858
--- /dev/null
+++ b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
@@ -0,0 +1,241 @@
+/*
+ * 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.juneau.petstore.springboot;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.net.*;
+import java.net.http.*;
+import java.net.http.HttpResponse.*;
+import java.time.*;
+
+import org.junit.jupiter.api.*;
+import org.springframework.boot.test.context.*;
+import org.springframework.boot.test.context.SpringBootTest.*;
+import org.springframework.boot.test.web.server.*;
+
+/**
+ * Integration test that boots the petstore Spring Boot deployment on a random port and exercises the CRUD
+ * surface plus the Spring {@code @Autowired} injection demo.
+ *
+ * <p>
+ * Tagged {@code @SpringbootTest} ({@code @Tag("container")} + {@code @Tag("springboot")}) so it skips under
+ * {@code scripts/test.py --no-container}.
+ *
+ * <p>
+ * Asserts the parity story: the same CRUD surface from {@code juneau-petstore-core} that the Jetty deployment
+ * mounts is reachable identically here, plus the Spring-injected {@link HelloResource} demonstrates the
+ * deployment-specific {@code @Autowired} pattern.
+ */
+@org.apache.juneau.testing.annotations.SpringbootTest
+@SpringBootTest(classes = App.class, webEnvironment = WebEnvironment.RANDOM_PORT)
+class PetstoreSpringboot_Test {
+
+ @LocalServerPort
+ int port;
+
+ private static final HttpClient HTTP = HttpClient.newBuilder()
+ .connectTimeout(Duration.ofSeconds(5))
+ .followRedirects(HttpClient.Redirect.NEVER)
+ .build();
+
+ private HttpResponse<String> get(String path, String accept) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:" + port + path))
+ .timeout(Duration.ofSeconds(10))
+ .header("Accept", accept)
+ .GET()
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ private HttpResponse<String> getWithAuth(String path, String accept, String authValue) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:" + port + path))
+ .timeout(Duration.ofSeconds(10))
+ .header("Accept", accept)
+ .header("Authorization", authValue)
+ .GET()
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ private HttpResponse<String> post(String path, String contentType, String body) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:" + port + path))
+ .timeout(Duration.ofSeconds(10))
+ .header("Content-Type", contentType)
+ .header("Accept", "application/json")
+ .POST(HttpRequest.BodyPublishers.ofString(body))
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ private HttpResponse<String> delete(String path) throws Exception {
+ var req = HttpRequest.newBuilder()
+ .uri(URI.create("http://localhost:" + port + path))
+ .timeout(Duration.ofSeconds(10))
+ .DELETE()
+ .build();
+ return HTTP.send(req, BodyHandlers.ofString());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // a — root router page
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void a01_rootRendersHtml() throws Exception {
+ var resp = get("/", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("petstore"), "expected petstore link on root: " + resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // b — petstore CRUD over real HTTP
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void b01_listPets_jsonContainsSeed() throws Exception {
+ var resp = get("/petstore/pets", "application/json");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), "expected seeded pet name in response: " + resp.body());
+ }
+
+ @Test void b02_getPet_byId_json() throws Exception {
+ var resp = get("/petstore/pets/1", "application/json");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("\"name\":\"Mr. Frisky\""), resp.body());
+ }
+
+ @Test void b03_getPet_unknown_404() throws Exception {
+ var resp = get("/petstore/pets/99999", "application/json");
+ assertEquals(404, resp.statusCode(), "body: " + resp.body());
+ }
+
+ @Test void b04_createPet_thenGet_roundTrip() throws Exception {
+ var body = "{\"name\":\"Wanda\",\"species\":\"RABBIT\",\"price\":12.50,\"status\":\"AVAILABLE\"}";
+ var post = post("/petstore/pets", "application/json", body);
+ assertEquals(200, post.statusCode(), "post body: " + post.body());
+ var id = extractLong(post.body(), "\"id\":");
+ assertNotEquals(0L, id, "server-assigned id missing in: " + post.body());
+
+ var get = get("/petstore/pets/" + id, "application/json");
+ assertEquals(200, get.statusCode(), "get body: " + get.body());
+ assertTrue(get.body().contains("\"name\":\"Wanda\""), get.body());
+ }
+
+ @Test void b05_deletePet_removes() throws Exception {
+ var del = delete("/petstore/pets/2");
+ assertEquals(200, del.statusCode(), "delete body: " + del.body());
+ var get = get("/petstore/pets/2", "application/json");
+ assertEquals(404, get.statusCode());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // c — content negotiation parity with the Jetty deployment
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void c01_listPets_xml() throws Exception {
+ var resp = get("/petstore/pets", "text/xml");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), resp.body());
+ }
+
+ @Test void c02_listPets_html() throws Exception {
+ var resp = get("/petstore/pets", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // d — Spring @Autowired injection demo
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void d01_helloResource_returnsInjectedMessage() throws Exception {
+ var resp = get("/hello", "text/plain");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Hello from Spring-injected bean!"),
+ "expected injected message in response: " + resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // e — view-engine demos (parity with jetty deployment — both inherit from core)
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void e01_mustacheView_rendersPet() throws Exception {
+ var resp = get("/pet-views/mustache/pets/1/view", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), "expected pet name in mustache view: " + resp.body());
+ assertTrue(resp.body().contains("Rendered via Mustache."), "expected mustache marker: " + resp.body());
+ }
+
+ @Test void e02_freemarkerView_rendersPet() throws Exception {
+ var resp = get("/pet-views/freemarker/pets/1/view", "text/html");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), "expected pet name in freemarker view: " + resp.body());
+ assertTrue(resp.body().contains("Rendered via FreeMarker."), "expected freemarker marker: " + resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // f — AuthFilterChain gating /petstore-secure/* (parity with jetty deployment)
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Test void f01_secureEndpoint_noAuth_401() throws Exception {
+ var resp = get("/petstore-secure/pets", "application/json");
+ assertEquals(401, resp.statusCode(), "body: " + resp.body());
+ var challenge = resp.headers().firstValue("WWW-Authenticate").orElse("");
+ assertTrue(challenge.contains("Bearer"), "WWW-Authenticate should advertise Bearer scheme: " + challenge);
+ }
+
+ @Test void f02_secureEndpoint_validToken_200() throws Exception {
+ var resp = getWithAuth("/petstore-secure/pets", "application/json", "Bearer petstore-user");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("Mr. Frisky"), "body: " + resp.body());
+ }
+
+ @Test void f03_secureEndpoint_unknownToken_401() throws Exception {
+ var resp = getWithAuth("/petstore-secure/pets", "application/json", "Bearer wrong-token");
+ assertEquals(401, resp.statusCode(), "body: " + resp.body());
+ }
+
+ @Test void f04_secureEndpoint_whoami_returnsPrincipalName() throws Exception {
+ var resp = getWithAuth("/petstore-secure/whoami", "application/json", "Bearer petstore-admin");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ assertTrue(resp.body().contains("\"name\":\"admin\""), "body: " + resp.body());
+ }
+
+ @Test void f05_unsecuredEndpoint_stillOpen() throws Exception {
+ var resp = get("/petstore/pets/1", "application/json");
+ assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // helpers
+ //-----------------------------------------------------------------------------------------------------------------
+
+ private static long extractLong(String body, String key) {
+ var i = body.indexOf(key);
+ if (i < 0)
+ return 0L;
+ i += key.length();
+ var end = i;
+ while (end < body.length() && (Character.isDigit(body.charAt(end)) || body.charAt(end) == '-'))
+ end++;
+ if (end == i)
+ return 0L;
+ return Long.parseLong(body.substring(i, end));
+ }
+}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/testing/annotations/SpringbootTest.java
old mode 100755
new mode 100644
similarity index 73%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
rename to juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/testing/annotations/SpringbootTest.java
index dd83076900..0ff3f8bc07
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/command/package-info.java
+++ b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/testing/annotations/SpringbootTest.java
@@ -14,12 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.juneau.testing.annotations;
+
+import java.lang.annotation.*;
+
+import org.junit.jupiter.api.*;
+
/**
- * REST Command Examples
- *
- * <p>
- * Example classes demonstrating how to use command pattern with Juneau's REST server.
- * These examples show various command-based REST API scenarios.
- * </p>
+ * Marker for container-backed Spring Boot tests.
*/
-package org.apache.juneau.examples.rest.command;
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Tag("container")
+@Tag("springboot")
+public @interface SpringbootTest {}
diff --git a/juneau-examples/pom.xml b/juneau-petstore/pom.xml
similarity index 75%
copy from juneau-examples/pom.xml
copy to juneau-petstore/pom.xml
index 0a316e6a73..43005b3638 100644
--- a/juneau-examples/pom.xml
+++ b/juneau-petstore/pom.xml
@@ -25,22 +25,15 @@
<version>10.0.0-SNAPSHOT</version>
</parent>
- <artifactId>juneau-examples</artifactId>
+ <artifactId>juneau-petstore</artifactId>
<packaging>pom</packaging>
- <name>Apache Juneau Examples</name>
- <description>Apache Juneau Examples</description>
+ <name>Apache Juneau Petstore</name>
+ <description>Apache Juneau Petstore Sample Applications</description>
<modules>
- <module>juneau-examples-core</module>
- <module>juneau-examples-rest</module>
- <module>juneau-examples-rest-jetty</module>
- <module>juneau-examples-rest-springboot</module>
- <module>juneau-examples-rest-jetty-ftest</module>
+ <module>juneau-petstore-core</module>
+ <module>juneau-petstore-jetty</module>
+ <module>juneau-petstore-springboot</module>
</modules>
- <build>
- <plugins>
- </plugins>
- </build>
-
</project>
diff --git a/juneau-release.sh b/juneau-release.sh
index ecb30605c9..b9c793d520 100755
--- a/juneau-release.sh
+++ b/juneau-release.sh
@@ -150,13 +150,8 @@ ZIP_TGT=$WORKSPACE/juneau-examples-core
echo Unzipping $ZIP_SRC to $ZIP_TGT
unzip -o $ZIP_SRC -d $ZIP_TGT
-ZIP_SRC=juneau-examples/juneau-examples-rest-jetty/target/juneau-examples-rest-jetty-$XV-bin.zip
-ZIP_TGT=$WORKSPACE/juneau-examples-rest-jetty
-echo Unzipping $ZIP_SRC to $ZIP_TGT
-unzip -o $ZIP_SRC -d $ZIP_TGT
-
-ZIP_SRC=juneau-examples/juneau-examples-rest-springboot/target/juneau-examples-rest-springboot-$XV-bin.zip
-ZIP_TGT=$WORKSPACE/juneau-examples-rest-springboot
+ZIP_SRC=juneau-petstore/juneau-petstore-jetty/target/juneau-petstore-jetty-$XV-bin.zip
+ZIP_TGT=$WORKSPACE/juneau-petstore-jetty
echo Unzipping $ZIP_SRC to $ZIP_TGT
unzip -o $ZIP_SRC -d $ZIP_TGT
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/MethodExecStore_Test.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/MethodExecStore_Test.java
index fec50fdf23..8bd777dae3 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/MethodExecStore_Test.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/MethodExecStore_Test.java
@@ -27,6 +27,9 @@ import org.apache.juneau.commons.inject.*;
import org.apache.juneau.rest.server.stats.*;
import org.junit.jupiter.api.*;
+@SuppressWarnings({
+ "resource" // Closeable resources in tests are intentionally unassigned; closing is handled by test infrastructure.
+})
class MethodExecStore_Test extends TestBase {
//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/ThrownStore_Test.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/ThrownStore_Test.java
index 8249538ff9..caac1ab9cb 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/ThrownStore_Test.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/mstat/ThrownStore_Test.java
@@ -29,7 +29,9 @@ import org.apache.juneau.rest.server.stats.*;
import org.junit.jupiter.api.*;
@SuppressWarnings({
- "java:S1172" // Unused parameters in tests are intentional
+ "java:S1172", // Unused parameters in tests are intentional
+ "unused", // Constructor parameters retained for bean-instantiation signature consistency in test fixtures.
+ "resource" // Closeable resources in tests are intentionally unassigned; closing is handled by test infrastructure.
})
class ThrownStore_Test extends TestBase {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
index 48b5fdc9e0..5318339d4b 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
@@ -37,6 +37,9 @@ class MethodInvokerTest extends TestBase {
public static class A {
public int foo() { return 0; }
public int bar() { throw new RuntimeException("bar"); }
+ @SuppressWarnings({
+ "unused" // Parameter is intentionally unused; exercises illegal-argument handling via reflection.
+ })
public void baz(int x) { /* no-op */ }
}
diff --git a/juneau-sc/juneau-sc-server/juneau-server-config.cfg b/juneau-sc/juneau-sc-server/juneau-server-config.cfg
index a97e0aff3a..1c42634fd8 100755
--- a/juneau-sc/juneau-sc-server/juneau-server-config.cfg
+++ b/juneau-sc/juneau-sc-server/juneau-server-config.cfg
@@ -132,7 +132,7 @@ includeRowNums = false
# Source code location
#=======================================================================================================================
[Source]
-gitHub = https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java
+gitHub = https://github.com/apache/juneau/blob/master/juneau-petstore/juneau-petstore-core/src/main/java
#=======================================================================================================================
# PetStoreResource properties
diff --git a/juneau-sc/juneau-sc-server/pom.xml b/juneau-sc/juneau-sc-server/pom.xml
index 9d48ac5de3..219b47ac8f 100644
--- a/juneau-sc/juneau-sc-server/pom.xml
+++ b/juneau-sc/juneau-sc-server/pom.xml
@@ -76,7 +76,7 @@
<goal>single</goal>
</goals>
<configuration>
- <finalName>juneau-examples-rest-jetty-${project.version}</finalName>
+ <finalName>juneau-sc-server-${project.version}</finalName>
<descriptors>
<descriptor>src/assembly/bin.xml</descriptor>
</descriptors>
diff --git a/pom.xml b/pom.xml
index 7c84d6a16d..74c831c1e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,7 @@
<module>juneau-microservice</module>
<module>juneau-sc</module>
<module>juneau-examples</module>
+ <module>juneau-petstore</module>
<module>juneau-integration-tests</module>
<module>juneau-bean</module>
<module>juneau-shaded</module>
diff --git a/scripts/apply-eclipse-prefs.py b/scripts/apply-eclipse-prefs.py
index 3b6fe8644f..9d7a245179 100755
--- a/scripts/apply-eclipse-prefs.py
+++ b/scripts/apply-eclipse-prefs.py
@@ -16,15 +16,30 @@
# limitations under the License.
"""
-Applies Eclipse IDE preference files to all Juneau project modules.
+Applies Eclipse IDE preference files to every Juneau Maven module.
-This script copies Eclipse JDT preferences from the eclipse-preferences directory
-to each module's .settings folder, ensuring consistent IDE configuration across
-all developers.
+Walks the reactor under each REACTOR_GROUPS entry plus STANDALONE_PROJECTS,
+finds every leaf directory with a pom.xml that is NOT a packaging=pom aggregator,
+classifies each as source or test (test = name == 'juneau-integration-tests' or
+*-ftest suffix), and copies the matching .prefs files into each module's
+.settings/ directory.
-There are two sets of preferences:
-- source-prefs: For main source modules
-- test-prefs: For test modules (juneau-integration-tests and *-ftest modules)
+Two sets of preferences live under scripts/eclipse-preferences/:
+- source-prefs/ — main source modules (warnings on resource leaks, unused params, etc.)
+- test-prefs/ — test modules (those warnings relaxed to ignore)
+
+Each set contains:
+- org.eclipse.jdt.core.prefs — JDT compiler problem severities + warning-token settings
+- org.eclipse.jdt.ui.prefs — JDT UI cleanup-on-save settings
+
+Run this whenever a new Maven module is added to the reactor, or whenever the
+canonical preference baseline is updated. Module discovery is automatic — the
+script does not need to be edited when modules are added or removed (only when
+a new top-level reactor group is introduced).
+
+The .settings/ directories are gitignored locally; this script's output is a
+developer-machine-only convenience and never enters version control. The
+canonical preference files under scripts/eclipse-preferences/ ARE tracked.
"""
import os
@@ -33,45 +48,81 @@ import shutil
from pathlib import Path
-# Source modules (main code)
-SOURCE_PROJECTS = [
- "juneau-bean/juneau-bean-atom",
- "juneau-bean/juneau-bean-common",
- "juneau-bean/juneau-bean-html5",
- "juneau-bean/juneau-bean-jsonschema",
- "juneau-bean/juneau-bean-openapi-v3",
- "juneau-bean/juneau-bean-swagger-v2",
- "juneau-core/juneau-assertions",
- "juneau-core/juneau-bct",
- "juneau-core/juneau-commons",
- "juneau-core/juneau-config",
- "juneau-core/juneau-marshall",
- "juneau-core/juneau-marshall-rdf",
- "juneau-examples/juneau-examples-core",
- "juneau-examples/juneau-examples-rest",
- "juneau-examples/juneau-examples-rest-jetty",
- "juneau-examples/juneau-examples-rest-springboot",
- "juneau-microservice/juneau-microservice",
- "juneau-microservice/juneau-microservice-jetty",
- "juneau-microservice/juneau-my-jetty-microservice",
- "juneau-microservice/juneau-my-springboot-microservice",
- "juneau-rest/juneau-rest-client",
- "juneau-rest/juneau-rest-common",
- "juneau-rest/juneau-rest-mock",
- "juneau-rest/juneau-rest-server",
- "juneau-rest/juneau-rest-server-rdf",
- "juneau-rest/juneau-rest-server-springboot",
- "juneau-sc/juneau-sc-client",
- "juneau-sc/juneau-sc-server",
+# Top-level reactor groups under which to scan for modules.
+# Each leaf directory containing a pom.xml that is NOT a packaging=pom aggregator
+# is treated as a project to apply preferences to.
+REACTOR_GROUPS = [
+ "juneau-bean",
+ "juneau-core",
+ "juneau-examples",
+ "juneau-microservice",
+ "juneau-petstore",
+ "juneau-rest",
+ "juneau-sc",
+ "juneau-shaded",
]
-# Test modules
-TEST_PROJECTS = [
+# Standalone (non-grouped) projects at the repo root.
+STANDALONE_PROJECTS = [
"juneau-integration-tests",
- "juneau-examples/juneau-examples-rest-jetty-ftest",
]
+def is_aggregator_pom(pom_path):
+ """Return True if the pom.xml has <packaging>pom</packaging>."""
+ try:
+ with open(pom_path, "r", encoding="utf-8") as f:
+ content = f.read()
+ return "<packaging>pom</packaging>" in content
+ except OSError:
+ return False
+
+
+def is_test_module(project_path):
+ """
+ Returns True if the project should get test-prefs applied (relaxed rules
+ around resource leaks, unused parameters, etc.) — typically integration-test
+ aggregators or *-ftest functional-test overlays.
+ """
+ name = Path(project_path).name
+ return name == "juneau-integration-tests" or name.endswith("-ftest")
+
+
+def discover_projects(root_dir):
+ """
+ Walk the reactor groups and standalone roots; return (source_projects, test_projects)
+ as lists of paths relative to root_dir.
+ """
+ source_projects = []
+ test_projects = []
+
+ candidates = []
+ for group in REACTOR_GROUPS:
+ group_dir = Path(root_dir) / group
+ if not group_dir.exists():
+ continue
+ for child in sorted(group_dir.iterdir()):
+ if not child.is_dir():
+ continue
+ if (child / "pom.xml").exists():
+ candidates.append(child)
+ for standalone in STANDALONE_PROJECTS:
+ standalone_dir = Path(root_dir) / standalone
+ if standalone_dir.exists() and (standalone_dir / "pom.xml").exists():
+ candidates.append(standalone_dir)
+
+ for project_dir in candidates:
+ if is_aggregator_pom(project_dir / "pom.xml"):
+ continue
+ relative = project_dir.relative_to(root_dir).as_posix()
+ if is_test_module(project_dir):
+ test_projects.append(relative)
+ else:
+ source_projects.append(relative)
+
+ return source_projects, test_projects
+
+
def apply_preferences(root_dir, projects, prefs_type):
"""
Apply Eclipse preferences to a list of projects.
@@ -133,31 +184,35 @@ def main():
# Determine root directory (parent of scripts directory)
script_dir = Path(__file__).parent
root_dir = script_dir.parent
-
+
if len(sys.argv) > 1:
root_dir = Path(sys.argv[1])
-
+
print(f"Applying Eclipse preferences to Juneau modules in: {root_dir}\n")
-
+
+ source_projects, test_projects = discover_projects(root_dir)
+
+ print(f"Discovered {len(source_projects)} source modules + {len(test_projects)} test modules.\n")
+
# Apply source preferences
print("Applying source preferences...")
- src_success, src_failed = apply_preferences(root_dir, SOURCE_PROJECTS, "source-prefs")
-
+ src_success, src_failed = apply_preferences(root_dir, source_projects, "source-prefs")
+
print("\nApplying test preferences...")
- test_success, test_failed = apply_preferences(root_dir, TEST_PROJECTS, "test-prefs")
-
+ test_success, test_failed = apply_preferences(root_dir, test_projects, "test-prefs")
+
# Summary
total_success = src_success + test_success
total_failed = src_failed + test_failed
- total_projects = len(SOURCE_PROJECTS) + len(TEST_PROJECTS)
-
+ total_projects = len(source_projects) + len(test_projects)
+
print(f"\n{'='*60}")
print("Summary:")
print(f" Total projects: {total_projects}")
print(f" Successfully updated: {total_success}")
print(f" Failed: {total_failed}")
print(f"{'='*60}")
-
+
if total_failed > 0:
sys.exit(1)
diff --git a/scripts/eclipse-preferences/source-prefs/org.eclipse.jdt.core.prefs b/scripts/eclipse-preferences/source-prefs/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..d6026868b8
--- /dev/null
+++ b/scripts/eclipse-preferences/source-prefs/org.eclipse.jdt.core.prefs
@@ -0,0 +1,117 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.notowning=org.eclipse.jdt.annotation.NotOwning
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.annotation.owning=org.eclipse.jdt.annotation.Owning
+org.eclipse.jdt.core.compiler.annotation.resourceanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
+org.eclipse.jdt.core.compiler.compliance=17
+org.eclipse.jdt.core.compiler.problem.APILeak=warning
+org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=ignore
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleOwningContract=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.insufficientResourceAnalysis=warning
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.memberOfDeprecatedTypeNotDeprecated=info
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=ignore
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
+org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLambdaParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=17
diff --git a/scripts/eclipse-preferences/source-prefs/org.eclipse.jdt.ui.prefs b/scripts/eclipse-preferences/source-prefs/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000..0cf8a2ede4
--- /dev/null
+++ b/scripts/eclipse-preferences/source-prefs/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.ondemandthreshold=1
+org.eclipse.jdt.ui.staticondemandthreshold=1
diff --git a/scripts/eclipse-preferences/test-prefs/org.eclipse.jdt.core.prefs b/scripts/eclipse-preferences/test-prefs/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..ad58d94f90
--- /dev/null
+++ b/scripts/eclipse-preferences/test-prefs/org.eclipse.jdt.core.prefs
@@ -0,0 +1,117 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.notowning=org.eclipse.jdt.annotation.NotOwning
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.annotation.owning=org.eclipse.jdt.annotation.Owning
+org.eclipse.jdt.core.compiler.annotation.resourceanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
+org.eclipse.jdt.core.compiler.compliance=17
+org.eclipse.jdt.core.compiler.problem.APILeak=warning
+org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=ignore
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleOwningContract=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.insufficientResourceAnalysis=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.memberOfDeprecatedTypeNotDeprecated=info
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=ignore
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
+org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLambdaParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=17
diff --git a/scripts/eclipse-preferences/test-prefs/org.eclipse.jdt.ui.prefs b/scripts/eclipse-preferences/test-prefs/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000..0cf8a2ede4
--- /dev/null
+++ b/scripts/eclipse-preferences/test-prefs/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.ondemandthreshold=1
+org.eclipse.jdt.ui.staticondemandthreshold=1
diff --git a/scripts/release.py b/scripts/release.py
index 70a8fdd7b4..db33402385 100755
--- a/scripts/release.py
+++ b/scripts/release.py
@@ -689,10 +689,8 @@ class ReleaseScript:
'my-springboot-microservice'),
('juneau-examples/juneau-examples-core/target/juneau-examples-core-{}-bin.zip',
'juneau-examples-core'),
- ('juneau-examples/juneau-examples-rest-jetty/target/juneau-examples-rest-jetty-{}-bin.zip',
- 'juneau-examples-rest-jetty'),
- ('juneau-examples/juneau-examples-rest-springboot/target/juneau-examples-rest-springboot-{}-bin.zip',
- 'juneau-examples-rest-springboot'),
+ ('juneau-petstore/juneau-petstore-jetty/target/juneau-petstore-jetty-{}-bin.zip',
+ 'juneau-petstore-jetty'),
]
for zip_src_pattern, zip_tgt_name in zip_files:
diff --git a/scripts/start-examples-rest-jetty.py b/scripts/start-petstore-jetty.py
similarity index 72%
rename from scripts/start-examples-rest-jetty.py
rename to scripts/start-petstore-jetty.py
index f4318ff102..cdd914f93e 100755
--- a/scripts/start-examples-rest-jetty.py
+++ b/scripts/start-petstore-jetty.py
@@ -13,16 +13,15 @@
# ***************************************************************************************************************************
"""
-Start Juneau REST Examples (Jetty) Application
+Start Juneau Petstore (Jetty) Application
-This script starts the Juneau REST examples application using the embedded Jetty server.
-It runs the org.apache.juneau.examples.rest.jetty.App main class using Maven's exec plugin.
+This script starts the Juneau petstore sample application using the embedded Jetty/Microservice server.
+It runs the org.apache.juneau.petstore.jetty.App main class using Maven's exec plugin.
Usage:
- python3 scripts/start-examples-rest-jetty.py
+ python3 scripts/start-petstore-jetty.py
"""
-import os
import sys
import subprocess
from pathlib import Path
@@ -45,67 +44,62 @@ def find_project_root():
return None
def main():
- """Start the Jetty examples application."""
- print(f"{BLUE}🚀 Starting Juneau REST Examples (Jetty)...{RESET}")
-
- # Find project root
+ """Start the petstore Jetty application."""
+ print(f"{BLUE}🚀 Starting Juneau Petstore (Jetty)...{RESET}")
+
project_root = find_project_root()
if not project_root:
print(f"{RED}[ERROR] Could not find project root directory{RESET}")
sys.exit(1)
-
- # Set working directory to the examples-rest-jetty module
- examples_dir = project_root / 'juneau-examples' / 'juneau-examples-rest-jetty'
-
- if not examples_dir.exists():
- print(f"{RED}[ERROR] Examples directory not found: {examples_dir}{RESET}")
+
+ petstore_dir = project_root / 'juneau-petstore' / 'juneau-petstore-jetty'
+
+ if not petstore_dir.exists():
+ print(f"{RED}[ERROR] Petstore Jetty directory not found: {petstore_dir}{RESET}")
sys.exit(1)
-
- print(f"{BLUE}📁 Working directory: {examples_dir}{RESET}")
-
- # Check if project is built
- target_dir = examples_dir / 'target' / 'classes'
+
+ print(f"{BLUE}📁 Working directory: {petstore_dir}{RESET}")
+
+ target_dir = petstore_dir / 'target' / 'classes'
if not target_dir.exists():
print(f"{YELLOW}⚠️ Classes not found. Building project first...{RESET}")
print(f"{BLUE}🔨 Running: mvn clean compile{RESET}\n")
-
+
result = subprocess.run(
['mvn', 'clean', 'compile'],
- cwd=str(examples_dir),
+ cwd=str(petstore_dir),
stdout=sys.stdout,
stderr=sys.stderr
)
-
+
if result.returncode != 0:
print(f"\n{RED}[ERROR] Build failed. Please fix compilation errors.{RESET}")
sys.exit(1)
-
+
print(f"\n{GREEN}✓ Build completed successfully{RESET}\n")
-
- # Run the application
- print(f"{BLUE}🚀 Starting Jetty microservice...{RESET}")
- print(f"{BLUE}Main class: org.apache.juneau.examples.rest.jetty.App{RESET}")
+
+ print(f"{BLUE}🚀 Starting Jetty/Microservice...{RESET}")
+ print(f"{BLUE}Main class: org.apache.juneau.petstore.jetty.App{RESET}")
print(f"{BLUE}Default URL: http://localhost:10000{RESET}")
print(f"\n{YELLOW}Press Ctrl+C to stop the server{RESET}\n")
print("=" * 80)
-
+
try:
- # Use Maven exec plugin to run the main class with proper classpath
cmd = [
'mvn',
'exec:java',
- '-Dexec.mainClass=org.apache.juneau.examples.rest.jetty.App'
+ '-Dexec.mainClass=org.apache.juneau.petstore.jetty.App'
]
-
+
process = subprocess.run(
cmd,
- cwd=str(examples_dir),
+ cwd=str(petstore_dir),
stdout=sys.stdout,
stderr=sys.stderr
)
-
+
sys.exit(process.returncode)
-
+
except KeyboardInterrupt:
print(f"\n\n{YELLOW}🛑 Shutting down server...{RESET}")
print(f"{GREEN}Server stopped{RESET}")
@@ -116,4 +110,3 @@ def main():
if __name__ == '__main__':
main()
-
diff --git a/scripts/start-examples-rest-springboot.py b/scripts/start-petstore-springboot.py
similarity index 74%
rename from scripts/start-examples-rest-springboot.py
rename to scripts/start-petstore-springboot.py
index a3b9016ae1..90b4ea38bb 100755
--- a/scripts/start-examples-rest-springboot.py
+++ b/scripts/start-petstore-springboot.py
@@ -13,16 +13,15 @@
# ***************************************************************************************************************************
"""
-Start Juneau REST Examples (Spring Boot) Application
+Start Juneau Petstore (Spring Boot) Application
-This script starts the Juneau REST examples application using Spring Boot.
-It runs the org.apache.juneau.examples.rest.springboot.App main class using Maven's Spring Boot plugin.
+This script starts the Juneau petstore sample application using Spring Boot.
+It runs the org.apache.juneau.petstore.springboot.App main class via the Spring Boot Maven plugin.
Usage:
- python3 scripts/start-examples-rest-springboot.py
+ python3 scripts/start-petstore-springboot.py
"""
-import os
import sys
import subprocess
from pathlib import Path
@@ -45,66 +44,61 @@ def find_project_root():
return None
def main():
- """Start the Spring Boot examples application."""
- print(f"{BLUE}🚀 Starting Juneau REST Examples (Spring Boot)...{RESET}")
-
- # Find project root
+ """Start the petstore Spring Boot application."""
+ print(f"{BLUE}🚀 Starting Juneau Petstore (Spring Boot)...{RESET}")
+
project_root = find_project_root()
if not project_root:
print(f"{RED}[ERROR] Could not find project root directory{RESET}")
sys.exit(1)
-
- # Set working directory to the examples-rest-springboot module
- examples_dir = project_root / 'juneau-examples' / 'juneau-examples-rest-springboot'
-
- if not examples_dir.exists():
- print(f"{RED}[ERROR] Examples directory not found: {examples_dir}{RESET}")
+
+ petstore_dir = project_root / 'juneau-petstore' / 'juneau-petstore-springboot'
+
+ if not petstore_dir.exists():
+ print(f"{RED}[ERROR] Petstore Spring Boot directory not found: {petstore_dir}{RESET}")
sys.exit(1)
-
- print(f"{BLUE}📁 Working directory: {examples_dir}{RESET}")
-
- # Check if project is built
- target_dir = examples_dir / 'target' / 'classes'
+
+ print(f"{BLUE}📁 Working directory: {petstore_dir}{RESET}")
+
+ target_dir = petstore_dir / 'target' / 'classes'
if not target_dir.exists():
print(f"{YELLOW}⚠️ Classes not found. Building project first...{RESET}")
print(f"{BLUE}🔨 Running: mvn clean compile{RESET}\n")
-
+
result = subprocess.run(
['mvn', 'clean', 'compile'],
- cwd=str(examples_dir),
+ cwd=str(petstore_dir),
stdout=sys.stdout,
stderr=sys.stderr
)
-
+
if result.returncode != 0:
print(f"\n{RED}[ERROR] Build failed. Please fix compilation errors.{RESET}")
sys.exit(1)
-
+
print(f"\n{GREEN}✓ Build completed successfully{RESET}\n")
-
- # Run the application
+
print(f"{BLUE}🚀 Starting Spring Boot application...{RESET}")
- print(f"{BLUE}Main class: org.apache.juneau.examples.rest.springboot.App{RESET}")
+ print(f"{BLUE}Main class: org.apache.juneau.petstore.springboot.App{RESET}")
print(f"{BLUE}Default URL: http://localhost:5000{RESET}")
print(f"\n{YELLOW}Press Ctrl+C to stop the server{RESET}\n")
print("=" * 80)
-
+
try:
- # Use Spring Boot Maven plugin to run the application
cmd = [
'mvn',
'spring-boot:run'
]
-
+
process = subprocess.run(
cmd,
- cwd=str(examples_dir),
+ cwd=str(petstore_dir),
stdout=sys.stdout,
stderr=sys.stderr
)
-
+
sys.exit(process.returncode)
-
+
except KeyboardInterrupt:
print(f"\n\n{YELLOW}🛑 Shutting down server...{RESET}")
print(f"{GREEN}Server stopped{RESET}")
@@ -115,4 +109,3 @@ def main():
if __name__ == '__main__':
main()
-