This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v3
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/v3 by this push:
new cd9dd621788 CAUSEWAY-3958: [v3] backports action result mediation from
v4
cd9dd621788 is described below
commit cd9dd62178826fbf6c5273ed77b87736ec0b680b
Author: andi-huber <[email protected]>
AuthorDate: Sun Jan 18 17:32:01 2026 +0100
CAUSEWAY-3958: [v3] backports action result mediation from v4
---
.../wicket/ui/exec/DownloadHandlerFactory.java | 104 ---------------------
.../causeway/viewer/wicket/ui/exec/Mediator.java | 72 ++++++--------
.../viewer/wicket/ui/exec/MediatorFactory.java | 10 +-
3 files changed, 32 insertions(+), 154 deletions(-)
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/DownloadHandlerFactory.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/DownloadHandlerFactory.java
deleted file mode 100644
index 9eeca477cc1..00000000000
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/DownloadHandlerFactory.java
+++ /dev/null
@@ -1,104 +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.causeway.viewer.wicket.ui.exec;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.time.Duration;
-
-import org.apache.wicket.request.IRequestHandler;
-import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
-import org.apache.wicket.request.resource.ContentDisposition;
-import org.apache.wicket.util.resource.AbstractResourceStream;
-import org.apache.wicket.util.resource.IResourceStream;
-import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
-import org.apache.wicket.util.resource.StringResourceStream;
-
-import org.apache.causeway.applib.value.Blob;
-import org.apache.causeway.applib.value.Clob;
-import org.apache.causeway.applib.value.NamedWithMimeType;
-import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
-
-import lombok.experimental.UtilityClass;
-
-@UtilityClass
-final class DownloadHandlerFactory {
-
- public IRequestHandler downloadHandler(
- final ObjectAction action,
- final Object value) {
- if(value instanceof Clob clob) {
- return handlerFor(action, resourceStreamFor(clob), clob);
- }
- if(value instanceof Blob blob) {
- return handlerFor(action, resourceStreamFor(blob), blob);
- }
- return null;
- }
-
- // -- HELPER
-
- private IResourceStream resourceStreamFor(final Blob blob) {
- final IResourceStream resourceStream = new AbstractResourceStream() {
- private static final long serialVersionUID = 1L;
- @Override public InputStream getInputStream() throws
ResourceStreamNotFoundException {
- return new ByteArrayInputStream(blob.bytes());
- }
- @Override public String getContentType() {
- return blob.mimeType().toString();
- }
- @Override public void close() throws IOException {
- }
- };
- return resourceStream;
- }
-
- private IResourceStream resourceStreamFor(final Clob clob) {
- return new StringResourceStream(clob.chars(),
clob.mimeType().toString());
- }
-
- private IRequestHandler handlerFor(
- final ObjectAction action,
- final IResourceStream resourceStream,
- final NamedWithMimeType namedWithMimeType) {
- var handler =
- new ResourceStreamRequestHandler(resourceStream,
namedWithMimeType.name());
- handler.setContentDisposition(ContentDisposition.ATTACHMENT);
-
- //CAUSEWAY-1619, prevent clients from caching the response content
- return action.getSemantics().isIdempotentOrCachable()
- ? handler
- : enforceNoCacheOnClientSide(handler);
- }
-
- // -- CLIENT SIDE CACHING ASPECTS ...
-
- private static IRequestHandler enforceNoCacheOnClientSide(final
IRequestHandler downloadHandler){
- if(downloadHandler==null) {
- return downloadHandler;
- }
- if(downloadHandler instanceof ResourceStreamRequestHandler)
- ((ResourceStreamRequestHandler) downloadHandler)
- .setCacheDuration(Duration.ZERO);
-
- return downloadHandler;
- }
-
-}
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/Mediator.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/Mediator.java
index 98b5225364b..428181c499a 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/Mediator.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/Mediator.java
@@ -18,21 +18,17 @@
*/
package org.apache.causeway.viewer.wicket.ui.exec;
-import java.time.Duration;
-
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.RequestCycle;
-import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
-import org.apache.wicket.request.resource.ContentDisposition;
-import org.apache.wicket.util.resource.IResourceStream;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.apache.causeway.applib.value.OpenUrlStrategy;
import org.apache.causeway.commons.internal.exceptions._Exceptions;
+import org.apache.causeway.commons.io.TextUtils;
import org.apache.causeway.core.metamodel.context.MetaModelContext;
import org.apache.causeway.core.metamodel.object.ManagedObject;
import org.apache.causeway.viewer.wicket.model.models.ActionModel;
@@ -129,36 +125,35 @@ void handle() {
case SCHEDULE_HANDLER -> {
var requestCycle = RequestCycle.get();
var ajaxTarget =
requestCycle.find(AjaxRequestTarget.class).orElse(null);
+ final IRequestHandler requestHandler = handler();
if (ajaxTarget == null) {
// non-Ajax request => just stream the Lob to the browser
// or if this is a no-arg action, there also will be no
parent for the component
- requestCycle.scheduleRequestHandlerAfterCurrent(handler());
+
requestCycle.scheduleRequestHandlerAfterCurrent(requestHandler);
+ return;
+ }
+ // otherwise,
+ // Ajax request => respond with a redirect to be able to
stream the Lob to the client
+ if(requestHandler instanceof LobRequestHandler
lobRequestHandler) {
+ var streamingBehavior = new
StreamAfterAjaxResponseBehavior(lobRequestHandler);
+ ajaxTarget.getPage().add(streamingBehavior);
+
+ var relativeDownloadPageUri =
TextUtils.cutter(streamingBehavior.getCallbackUrl().toString())
+ .keepAfterLast("/")
+ .getValue();
+ scheduleJs(ajaxTarget,
javascriptFor_sameWindow(relativeDownloadPageUri), 10);
+ } else if(requestHandler instanceof
RedirectRequestHandlerWithOpenUrlStrategy redirectHandler) {
+ var fullUrl = expanded(requestCycle,
redirectHandler.getRedirectUrl());
+ var js = redirectHandler.getOpenUrlStrategy().isNewWindow()
+ ? javascriptFor_newWindow(fullUrl)
+ : javascriptFor_sameWindow(fullUrl);
+
+ scheduleJs(ajaxTarget, js, 100);
} else {
- // otherwise,
- // Ajax request => respond with a redirect to be able to
stream the Lob to the client
- final IRequestHandler requestHandler = handler();
- if(requestHandler instanceof ResourceStreamRequestHandler
scheduledHandler) {
- var streamingBehavior = new
StreamAfterAjaxResponseBehavior(scheduledHandler);
- var page = ajaxTarget.getPage();
- page.add(streamingBehavior);
- CharSequence callbackUrl =
streamingBehavior.getCallbackUrl();
- scheduleJs(ajaxTarget,
javascriptFor_sameWindow(callbackUrl), 10);
- } else if(requestHandler instanceof
RedirectRequestHandlerWithOpenUrlStrategy redirectHandler) {
-
- final String url = redirectHandler.getRedirectUrl();
- final String fullUrl = expanded(requestCycle, url);
-
- if(redirectHandler.getOpenUrlStrategy().isNewWindow())
{
- scheduleJs(ajaxTarget,
javascriptFor_newWindow(fullUrl), 100);
- } else {
- scheduleJs(ajaxTarget,
javascriptFor_sameWindow(fullUrl), 100);
- }
- } else {
- throw _Exceptions.unrecoverable(
- "no logic implemented to handle
IRequestHandler of type %s",
- requestHandler.getClass().getName());
- }
+ throw _Exceptions.unrecoverable(
+ "no logic implemented to handle IRequestHandler of
type %s",
+ requestHandler.getClass().getName());
}
}
}
@@ -195,7 +190,7 @@ private static String javascriptFor_sameWindow(final
CharSequence url) {
private static void scheduleJs(final AjaxRequestTarget target, final
String js, final int millis) {
// the timeout is needed to let Wicket release the channel
- target.appendJavaScript(String.format("setTimeout(%s, %d);", js,
millis));
+ target.appendJavaScript("setTimeout(%s, %d);".formatted(js, millis));
}
/**
@@ -205,22 +200,15 @@ private static void scheduleJs(final AjaxRequestTarget
target, final String js,
private static class StreamAfterAjaxResponseBehavior extends
AbstractAjaxBehavior {
private static final long serialVersionUID = 1L;
- private final String fileName;
- private final IResourceStream resourceStream;
- private final Duration cacheDuration;
+ private final LobRequestHandler lobRequestHandler;
- public StreamAfterAjaxResponseBehavior(final
ResourceStreamRequestHandler scheduledHandler) {
- this.fileName = scheduledHandler.getFileName();
- this.resourceStream = scheduledHandler.getResourceStream();
- this.cacheDuration = scheduledHandler.getCacheDuration();
+ StreamAfterAjaxResponseBehavior(final LobRequestHandler
lobRequestHandler) {
+ this.lobRequestHandler = lobRequestHandler;
}
@Override public void onRequest() {
- var handler = new ResourceStreamRequestHandler(resourceStream,
fileName);
- handler.setCacheDuration(cacheDuration);
- handler.setContentDisposition(ContentDisposition.ATTACHMENT);
var page = getComponent();
- page.getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
+
page.getRequestCycle().scheduleRequestHandlerAfterCurrent(lobRequestHandler);
page.remove(this);
}
}
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
index 71f1d451cbb..8de2add58a6 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
@@ -135,16 +135,10 @@ private Mediator actionResultResponse(
var pageRedirectRequest =
PageRedirectRequest.forPage(ValuePage.class, valuePage);
return Mediator.toPage(pageRedirectRequest);
}
- case VALUE_BLOB: {
- final Object value = resultAdapter.getPojo();
- IRequestHandler handler =
-
DownloadHandlerFactory.downloadHandler(actionModel.getAction(), value);
- return Mediator.withHandler(handler);
- }
+ case VALUE_BLOB:
case VALUE_CLOB: {
final Object value = resultAdapter.getPojo();
- IRequestHandler handler =
-
DownloadHandlerFactory.downloadHandler(actionModel.getAction(), value);
+ IRequestHandler handler =
LobRequestHandler.downloadHandler(actionModel.getAction(), value);
return Mediator.withHandler(handler);
}
case VALUE_LOCALRESPATH_AJAX: {