resources = delegate.search(terms);
+ JSONArray results = new JSONArray();
+ for (Requirement req : resources) {
+ JSONObject obj = new JSONObject();
+ obj.put("title", req.getTitle());
+ obj.put("resource", req.getAbout().toString());
+ results.put(obj);
+ }
+ return Response.ok(results.toString()).build();
+ } else {
+ // Initial dialog request - return Qute template
+ return requirementSelector.data("selectionUri", selectionUri);
+ }
+}
+```
+
+Add template injection to the service class:
+
+```java
+@Path("serviceProviders/{serviceProviderId}/service1/requirements")
+public class RequirementsService {
+
+ @Inject
+ Template requirementSelector; // Qute finds templates/requirementSelector.html
+
+ // ... rest of class
+}
+```
+
+Qute template: `src/main/resources/templates/requirementSelector.html`
+
+```html
+
+
+ Requirement Selector
+
+
+
+
+
+
+
+
+```
+
+**Key changes:**
+- Method return type changes from `Response`/`void` to `Object` to support both returns
+- Add `MediaType.APPLICATION_JSON` to `@Produces` annotation
+- Return `TemplateInstance` for HTML, `Response` for JSON
+- Inject template with `@Inject Template templateName`
+- Template name matches file name without extension
+
+### Pattern 3: Migrating resource detail pages
+
+Resource detail pages show a single OSLC resource in HTML format.
+
+**Before (JSP):**
+
+```java
+@GET
+@Path("{resourceId}")
+@Produces({ MediaType.TEXT_HTML })
+public void getRequirementAsHtml(
+ @PathParam("resourceId") final String resourceId
+) throws ServletException, IOException {
+
+ Requirement requirement = delegate.getRequirement(resourceId);
+ if (requirement != null) {
+ httpServletRequest.setAttribute("requirement", requirement);
+ RequestDispatcher rd = httpServletRequest.getRequestDispatcher(
+ "/co/oslc/refimpl/rm/gen/requirement.jsp");
+ rd.forward(httpServletRequest, httpServletResponse);
+ return;
+ }
+ throw new WebApplicationException(Status.NOT_FOUND);
+}
+```
+
+JSP: `src/main/webapp/co/oslc/refimpl/rm/gen/requirement.jsp`
+
+```jsp
+<%@ page import="org.eclipse.lyo.oslc.domains.rm.Requirement" %>
+<% Requirement req = (Requirement) request.getAttribute("requirement"); %>
+
+
+
+ <%= req.getTitle() %>
+ Identifier: <%= req.getIdentifier() %>
+ Description: <%= req.getDescription() %>
+
+
+```
+
+**After (Qute):**
+
+Option 1: Disable HTML representation (recommended initially):
+
+```java
+// NOTE: HTML representation disabled in Quarkus migration as JSP forwarding
+// is not supported. Quarkus uses Qute templates instead.
+// For now, only RDF representations are supported.
+// @GET
+// @Path("{resourceId}")
+// @Produces({ MediaType.TEXT_HTML })
+// public void getRequirementAsHtml(...) { ... }
+```
+
+Option 2: Migrate to Qute (when needed):
+
+```java
+@Inject
+Template requirement;
+
+@GET
+@Path("{resourceId}")
+@Produces({ MediaType.TEXT_HTML })
+public TemplateInstance getRequirementAsHtml(
+ @PathParam("resourceId") final String resourceId
+) {
+ Requirement req = delegate.getRequirement(resourceId);
+ if (req != null) {
+ return requirement
+ .data("requirement", req)
+ .data("title", req.getTitle())
+ .data("identifier", req.getIdentifier())
+ .data("description", req.getDescription());
+ }
+ throw new WebApplicationException(Status.NOT_FOUND);
+}
+```
+
+Qute template: `src/main/resources/templates/requirement.html`
+
+```html
+
+
+ {title}
+ Identifier: {identifier}
+ Description: {description}
+
+
+```
+
+### Qute syntax reference for JSP developers
+
+| JSP Syntax | Qute Equivalent | Notes |
+|------------|-----------------|-------|
+| `<%= expr %>` | `{expr}` | Expression output |
+| `${expr}` | `{expr}` | Expression output |
+| `` | `{#if condition}...{/if}` | Conditional |
+| `` | `{#for item in list}...{/for}` | Iteration |
+| `` | `{#if}...{#else if}...{#else}...{/if}` | Multiple conditions |
+| `` | `/path` or `{basePath}/path` | Static or dynamic URL |
+| `` | `{text}` | Escaped output (default) |
+| `${text}` (unescaped) | `{text.raw}` | Unescaped output |
+| `${obj.property}` | `{obj.property}` | Property access |
+| `${map['key']}` | `{map.get('key')}` | Map access |
+| `${list[0]}` | `{list.get(0)}` | List access |
+| `${fn:length(list)}` | `{list.size}` | Collection size |
+
+### Common Qute patterns
+
+**Conditional rendering:**
+
+```html
+{#if user}
+ Welcome, {user.name}!
+{#else}
+ Please log in.
+{/if}
+```
+
+**Iteration:**
+
+```html
+
+{#for item in items}
+ - {item.name} - {item.price}
+{/for}
+
+```
+
+**Null-safe access:**
+
+```html
+{resource.title ?: 'Untitled'}
+{resource.description orEmpty}
+```
+
+**Calling methods:**
+
+```html
+Total: {items.size}
+First: {items.get(0).name}
+```
+
+### Migration checklist
+
+For each JSP file to migrate:
+
+- [ ] Create new `.html` file in `src/main/resources/templates/`
+- [ ] Convert JSP directives and imports (not needed in Qute)
+- [ ] Convert `<%= %>` and `${}` to `{}`
+- [ ] Convert JSTL tags to Qute sections (`{#if}`, `{#for}`, etc.)
+- [ ] Identify data needed from request attributes
+- [ ] Create or update JAX-RS resource class
+- [ ] Add `@Inject Template templateName` field
+- [ ] Change method return type to `TemplateInstance` (or `Object` for dual-mode)
+- [ ] Replace `RequestDispatcher.forward()` with `return template.data(...)`
+- [ ] Pass data using `.data(key, value)` calls
+- [ ] Test the migrated page
+- [ ] Delete the old JSP file
+
+### Recommended migration order
+
+1. **Start with simple pages**: Home page, about page, error pages
+2. **Then OSLC dialogs**: Selection dialogs, creation dialogs
+3. **Finally resource pages**: Individual resource detail views (or disable them)
+4. **Leave query collection pages**: These are often complex; consider disabling HTML and keeping only RDF
+
+### Testing migrated templates
+
+After migration, verify:
+
+```bash
+# Test HTML rendering
+curl -H "Accept: text/html" http://localhost:8800/
+
+# Test selection dialog
+curl --user admin:admin http://localhost:8800/.../selector
+
+# Test with search parameter (should return JSON)
+curl --user admin:admin http://localhost:8800/.../selector?terms=test
+```
+
+### When to skip HTML migration
+
+Not all HTML endpoints need migration immediately. Consider disabling HTML representations for:
+
+- Query collection pages (complex iteration and paging)
+- Resource detail pages (if rarely used)
+- Preview pages (small/large preview)
+
+Keep these as RDF-only endpoints and focus on migrating essential UI:
+
+```java
+// Comment out HTML endpoints
+// @GET
+// @Path("query")
+// @Produces({ MediaType.TEXT_HTML })
+// public void queryResourcesAsHtml(...) {
+// // JSP forwarding code
+// }
+```
+
+This allows you to complete the Quarkus migration without rewriting every HTML view immediately.
+
+## Step 6: Update Dockerfile
+
+Replace Jetty-based Dockerfile with Quarkus configuration:
+
+```dockerfile
+FROM docker.io/library/maven:3-eclipse-temurin-21 AS build
+
+COPY . /src
+WORKDIR /src
+
+# Copy project files
+COPY pom.xml pom.xml
+COPY client-toolchain/pom.xml client-toolchain/pom.xml
+COPY lib-common/ lib-common/
+COPY server-rm/ server-rm/
+
+# Build Quarkus uber-jar (single JAR with all dependencies)
+RUN mvn -B --no-transfer-progress -DskipTests clean package \
+ -pl server-rm -am -Dquarkus.package.jar.type=uber-jar
+
+FROM registry.access.redhat.com/ubi8/openjdk-21-runtime:1.20
+
+# Add metadata
+LABEL org.opencontainers.image.title="OSLC RefImpl RM Server"
+LABEL org.opencontainers.image.description="OSLC RM Reference Implementation"
+LABEL org.opencontainers.image.source="https://github.com/oslc-op/refimpl"
+LABEL org.opencontainers.image.vendor="OSLC Open Project"
+LABEL org.opencontainers.image.licenses="EPL-2.0"
+
+ENV LANGUAGE='en_US:en'
+
+WORKDIR /deployments
+
+# Copy the Quarkus uber-jar
+COPY --from=build --chown=185 /src/server-rm/target/*-runner.jar \
+ /deployments/quarkus-run.jar
+
+EXPOSE 8800
+USER 185
+
+ENTRYPOINT ["java", "-jar", "/deployments/quarkus-run.jar"]
+```
+
+Update `docker-compose.yml`:
+
+```yaml
+services:
+ server-rm:
+ build:
+ context: ./
+ dockerfile: server-rm/Dockerfile
+ ports:
+ - "127.0.0.1:8800:8800" # Note: Quarkus uses 8800, not 8080
+```
+
+## Step 7: Update integration tests
+
+Update test wait conditions for Quarkus:
+
+```java
+@Container
+public static ComposeContainer environment = new ComposeContainer(
+ new File("src/test/resources/docker-compose.yml"))
+ .withExposedService(RM_SVC, RM_PORT,
+ Wait.forLogMessage(".*(Started oejs.Server@|Quarkus.*started in).*", 1)
+ .withStartupTimeout(Duration.ofSeconds(STARTUP_TIMEOUT)))
+```
+
+Update Swagger UI URLs in tests:
+
+```java
+// Use /swagger-ui for Quarkus RM server
+var swaggerUrl = RM_SVC.equals(svc)
+ ? "http://%s:%d/swagger-ui".formatted(serviceHost, servicePort)
+ : "http://%s:%d/swagger-ui/index.jsp".formatted(serviceHost, servicePort);
+```
+
+## Step 8: Optional - Remove /services prefix
+
+The traditional Lyo pattern uses `/services/` as a prefix for all OSLC resources. Quarkus allows you to remove this prefix for cleaner URLs.
+
+Update `application.properties`:
+
+```properties
+# Remove /services prefix
+quarkus.resteasy.path=/
+```
+
+Update `@OpenAPIDefinition`:
+
+```java
+@OpenAPIDefinition(info = @Info(title = "RM", version = "1.0.0"),
+ servers = @Server(url = "/"))
+```
+
+Update all hardcoded `/services/` references in templates and code.
+
+## Troubleshooting
+
+### UT010023 - Undertow request wrapper error
+
+**Problem**: `UT010023: Request already used for a different request`
+
+**Solution**: Undertow validates that requests passed to `RequestDispatcher.forward()` are either the original request or properly wrapped. Create a utility method:
+
+```java
+public class ServletUtil {
+ public static HttpServletRequest unwrapRequest(HttpServletRequest request) {
+ ServletRequest current = request;
+ while (current instanceof HttpServletRequestWrapper) {
+ current = ((HttpServletRequestWrapper) current).getRequest();
+ }
+ return (HttpServletRequest) current;
+ }
+}
+```
+
+Use it before forwarding:
+
+```java
+HttpServletRequest originalRequest = ServletUtil.unwrapRequest(httpServletRequest);
+RequestDispatcher rd = originalRequest.getRequestDispatcher("/path/to/jsp");
+rd.forward(originalRequest, httpServletResponse);
+```
+
+### Home page returns 403 Forbidden
+
+**Problem**: Home page accessible but returns 403.
+
+**Solution**: Check that:
+1. `HomePageResource` is registered in `Application.getClasses()`
+2. `HomePageResource` has `@ApplicationScoped` annotation
+3. `CredentialsFilter` excludes the root path
+
+### Resources not discovered
+
+**Problem**: JAX-RS resources not appearing in startup logs.
+
+**Solution**: Either add `@ApplicationScoped` to resource classes, or explicitly register them in `Application`:
+
+```java
+static {
+ RESOURCE_CLASSES.add(YourResourceClass.class);
+}
+```
+
+### Swagger UI not found
+
+**Problem**: Swagger UI returns 404.
+
+**Solution**: Configure in `application.properties`:
+
+```properties
+quarkus.swagger-ui.always-include=true
+quarkus.swagger-ui.path=/swagger-ui
+```
+
+## Performance comparison
+
+### Before (Jersey/Jetty)
+
+```
+2025-12-20T18:02:29.000Z Started oejs.Server@3d4eac69{STARTING}
+Startup time: 5-10 seconds
+```
+
+### After (Quarkus)
+
+```
+2025-12-20T18:02:34.235Z server-rm 0.3.0-SNAPSHOT on JVM
+ (powered by Quarkus 3.17.4) started in 0.787s.
+Startup time: <1 second
+```
+
+## Additional resources
+
+- [Quarkus Documentation](https://quarkus.io/guides/)
+- [Eclipse Lyo Documentation](https://oslc.github.io/developing-oslc-applications/)
+- [Qute Template Engine Guide](https://quarkus.io/guides/qute)
+- [Quarkus CDI Reference](https://quarkus.io/guides/cdi-reference)
+- [Example Migration PR](https://github.com/oslc-op/refimpl/pull/482)
+
+## Summary
+
+This migration delivers significant benefits:
+
+- **10x faster startup**: Enables deployment to serverless and auto-scaling platforms
+- **Reduced memory footprint**: More efficient resource usage
+- **Modern stack**: CDI instead of HK2, Qute instead of JSP
+- **Better security**: Template engines that do not execute arbitrary code
+- **Cloud-ready**: Compatible with Google Cloud Run, Azure Container Apps, AWS App Runner
+
+The main trade-offs are:
+
+- JSP pages must be migrated to Qute templates
+- OAuth 1.0a support requires additional work (consider OAuth 2.0 instead)
+- Some HTML representations may need to be disabled temporarily
+
+Overall, the migration effort is worthwhile for any OSLC server adaptor targeting modern deployment platforms.
diff --git a/docs-new/eclipse_lyo/migration-5x-6x.md b/docs-new/eclipse_lyo/migration-5x-6x.md
index b203960..57aa6ac 100644
--- a/docs-new/eclipse_lyo/migration-5x-6x.md
+++ b/docs-new/eclipse_lyo/migration-5x-6x.md
@@ -446,7 +446,7 @@ Based on the refimpl migration (commit 3ca27c7), key changes include:
17
-6.0.0-SNAPSHOT
+6.0.0.Final
3.1.5
```
diff --git a/mkdocs.yml b/mkdocs.yml
index 22fa044..aff763d 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -183,6 +183,7 @@ nav:
- Lyo 4.x → 5.x: eclipse_lyo/migration-4x-5x.md
- Lyo 5.x → 6.x: eclipse_lyo/migration-5x-6x.md
- Lyo 6.x → 7.x: eclipse_lyo/migration-6x-7x.md
+ - Jersey → Quarkus: eclipse_lyo/migrating-to-quarkus.md
- Advanced topics:
- Core Internals: eclipse_lyo/lyo-core-internals.md
- OSGi Bundles: eclipse_lyo/lyo-as-osgi-bundles.md