Michael Gerhards
Michael Gerhards

Reputation: 1

Java Wicket AjaxLink and RequestHandler - How to?

Usage scenario: The user clicks on a link on a web site do get a dynamically generated PDF in both languages: German and English.

This code works. generateCouponPdfOnClick creates a ResourceStreamRequestHandler containing a pdf file.

Link<Void> generatePdf = new Link<Void>("generatePdf") {
@Override
public void onClick() {
    ResourceStreamRequestHandler requestHandler = generateCouponPdfOnClick(coupon, PDFLanguage.GERMAN);
    getRequestCycle().scheduleRequestHandlerAfterCurrent(requestHandler);
}
};

Now I want to change the code to get a popup (Wicket Modalwindow, here class PdfDialogPage) where the user can select a language (German/English) for the PDF by klicking on one of the two buttons. If the user clicks a button, the ModalWindow should close and the PDF should be build and displayed.

Here is the modified code: The variable pdflanguageanguage contains the selected language and is set by the PdfDialogPage using the PageReferenz

AjaxLink<Void> generatePdf = new AjaxLink<Void>("generatePdf") {
@Override
public void onClick(final AjaxRequestTarget target) {
    modalWindow.setPageCreator(() -> {
        return new PdfDialogPage(getPage().getPageReference(), modalWindow);
    });
    modalWindow.setWindowClosedCallback((AjaxRequestTarget target1) -> {
        ResourceStreamRequestHandler requestHandler = generateCouponPdfOnClick(coupon, pdflanguageanguage);
        getRequestCycle().scheduleRequestHandlerAfterCurrent(requestHandler);
    });
    modalWindow.show(target);
};

When I click the link, the modalwindow opens. I select the language, e.g. English, and the modalWindow closes while writing "English" to the variable pdflanguageanguage. Than nothing more happens ... and the PDF is not generated. The Wicket Ajax Debug Window tells me the follogwing logs:

</head>]]></header-contribution><evaluate><![CDATA[(function(){var settings = {"minWidth":200,"minHeight":200,"className":"w_blue","width":400,"height":100,"resizable":true,"src":"./wicket/page?6","mask":"semi-transparent","autoSize":false,"unloadConfirmation":true,"onClose":function() { Wicket.Ajax.ajax({"u":"./overviewCoupons?5-1.1-panel-modalWindow","c":"modalWindowb0"}); },"onCloseButton":function() { Wicket.Ajax.ajax({"u":"./overviewCoupons?5-1.0-panel-modalWindow","c":"modalWindowb0"});; return false; }};window.setTimeout(function(){
  Wicket.Window.create(settings).show();
}, 0);
})();]]></evaluate></ajax-response>
INFO: returned focused element: javascript:;
INFO: returned focused element: javascript:;
INFO: Response processed successfully.
INFO: refocus last focused component not needed/allowed
INFO: focus removed from generatePdf5
INFO: focus set on _wicket_window_3
INFO: focus set on undefined
INFO: focus removed from undefined
ERROR: Wicket.Ajax.Call.failure: Error while parsing response: Error: Invalid XML: %PDF-1.4
%����
1 0 obj
<<
/Creator (Apache FOP Version 2.3)
/Producer (Apache FOP Version 2.3)
/CreationDate (D:20180808160110+02'00')

I believe that there is a problem between Ajax and "getRequestCycle().scheduleRequestHandlerAfterCurrent(requestHandler);". How do I use these together. So I reduced code to:

AjaxLink<Void> generatePdf = new AjaxLink<Void>("generatePdf") {
@Override
public void onClick(final AjaxRequestTarget target) {
ResourceStreamRequestHandler requestHandler = generateCouponPdfOnClick(coupon, PDFLanguage.ENGLISH);
getRequestCycle().scheduleRequestHandlerAfterCurrent(requestHandler);
}
};

When I know click the AjaxLink, nothing happens but I get the same Ajax Log Error Output.

How do I use AjaxLink together with ResourceStreamRequestHandler?

Upvotes: 0

Views: 1668

Answers (1)

mrkernelpanic
mrkernelpanic

Reputation: 4451

I solved a similar use case like you have in this way.

You need the Java class AjaxDownload from here

Alternatively you can use my variation which takes a FileResourceStream as input.

import lombok.extern.slf4j.Slf4j;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
import org.apache.wicket.request.resource.ContentDisposition;
import org.apache.wicket.util.resource.FileResourceStream;

/**
 * @author Sven Meier
 * @author Ernesto Reinaldo Barreiro ([email protected])
 * @author Jordi Deu-Pons ([email protected])
 */
@Slf4j
public class AJAXDownload extends AbstractAjaxBehavior {

    private boolean addAntiCache;
    private FileResourceStream fileResourceStream;
    private String fileName;

    public AJAXDownload() {
        this(true);
    }

    public AJAXDownload(boolean addAntiCache) {
        super();
        this.addAntiCache = addAntiCache;
    }

    /**
     * Call this method to initiate the download.
     */
    public void initiate(AjaxRequestTarget target, FileResourceStream fileResourceStream, String fileName) {
        this.fileResourceStream= fileResourceStream;
        this.fileName = fileName;
        String url = getCallbackUrl().toString();

        if (addAntiCache) {
            url = url + (url.contains("?") ? "&" : "?");
            url = url + "antiCache=" + System.currentTimeMillis();
        }

        // the timeout is needed to let Wicket release the channel
        target.appendJavaScript("setTimeout(\"window.location.href='" + url + "'\", 100);");
    }

    public void onRequest() {
        try{
            ResourceStreamRequestHandler handler = new ResourceStreamRequestHandler(fileResourceStream, fileName);
            handler.setContentDisposition(ContentDisposition.ATTACHMENT);
            getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
        } catch (Exception e){
            log.error("Error while trying to download", e);
            onErrorOccurred();
        }
    }
    protected void onErrorOccurred(){}
}

How to use?

  1. you have to add the AjaxDownload to your Form

    form.add(ajaxDownload = new AJAXDownload());
    
  2. in your onSubmit from your AjaxLink you can call:

    File yourPdfFile = //create your pdf file;
    final FileResourceStream resourceStream= new FileResourceStream(yourPdfFile);
    ajaxDownload.initiate(target, resourceStream, "yourPDF.pdf");
    

Upvotes: 1

Related Questions