javaxpages

XPages - delay before second button click takes place


I have a form with two rich text fields used to hold attachments and an XPage that contains two file download controls (one for each field) and two buttons.

The buttons call a method in a Java class that creates a zip file containing the files from the relevant field. The zip file is downloaded in the browser for the user.

It all works perfectly - apart from the fact that if you download either zip file, you cannot immediately download the other. There is a delay of around 15-20 seconds before the second button click does anything.

XPage :-

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:this.data>
        <xp:dominoDocument var="document1" formName="Document"></xp:dominoDocument>
    </xp:this.data>
    
    <xp:panel tagName="div"
        style="margin-left:auto; margin-right:auto; width:50%">

        <xp:br></xp:br>

        <xp:fileDownload rows="30" id="fileDownload1"
            displayLastModified="false" value="#{document1.Body1}">
        </xp:fileDownload>
        
        <xp:button value="Download Zipfile 1" id="button1">
            <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
                <xp:this.script><![CDATA[console.log("Button1 click")]]></xp:this.script>
                <xp:this.action><![CDATA[#{javascript:uk.co.mp.DownloadAllAttachments.downloadFromField(context.getUrlParameter("documentId"), "Body1");
}]]></xp:this.action>
            </xp:eventHandler>
        </xp:button>

        <xp:br></xp:br>

        <xp:fileDownload rows="30" id="fileDownload2"
            displayLastModified="false" value="#{document1.Body2}">
        </xp:fileDownload>

        
        <xp:button value="Download Zipfile 2" id="button2">
            <xp:eventHandler event="onclick" submit="true"
                refreshMode="complete">
                <xp:this.script><![CDATA[console.log("Button2 click")]]></xp:this.script>
                <xp:this.action><![CDATA[#{javascript:uk.co.mp.DownloadAllAttachments.downloadFromField(context.getUrlParameter("documentId"), "Body2");
}]]></xp:this.action>
            </xp:eventHandler>
        </xp:button>

    </xp:panel>

</xp:view>

Java class :-

package uk.co.mp;

import java.io.BufferedInputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;
import lotus.domino.Document;
import lotus.domino.EmbeddedObject;
import lotus.domino.RichTextItem;

import com.ibm.xsp.designer.context.XSPContext;
import com.ibm.xsp.model.domino.DominoUtils;

//
import lotus.domino.Session;
import lotus.domino.Database;
import com.ibm.xsp.extlib.util.ExtLibUtil;

public class DownloadAllAttachments {
    

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void downloadFromField(String documentUNID, String fieldName) {

        // Initialize global XPage objects
        FacesContext facesContext = FacesContext.getCurrentInstance();
        XSPContext context = XSPContext.getXSPContext(facesContext);
        UIViewRoot view = facesContext.getViewRoot();
        Map viewScope = view.getViewMap();

        try {

            if (documentUNID == null || documentUNID.trim().equals("")) {
                viewScope.put("errorString", "URL parameter \"documentUNID\" or \"u\" is required.");
                view.setRendered(true);
                return;
            }

            Session s = ExtLibUtil.getCurrentSessionAsSigner();
            Database db = s.getCurrentDatabase();
            
            // Get and validate the document from which attachments would be zipped
            Document downloadDocument = null;
            downloadDocument = db.getDocumentByUNID(documentUNID);

            // Get and validate zip file name from URL
            String zipFileName = fieldName + ".zip";

            boolean bAnyAttachments = false;
            EmbeddedObject embeddedObj = null;
            Vector attachments = null;
            
            // ...check for attachments in the field supplied and collect the names of the attachments
            RichTextItem rtitem = (RichTextItem)downloadDocument.getFirstItem(fieldName);
            Vector vec = rtitem.getEmbeddedObjects();
            attachments = new Vector(vec.size());
            
            if (!vec.isEmpty()) {
                Iterator it = vec.iterator();

                while(it.hasNext()){
                    embeddedObj = (EmbeddedObject)it.next();
                    if (embeddedObj != null) {
                        attachments.add(embeddedObj.getName());
                        bAnyAttachments = true;
                    }

                }
            }

            
            //By this point we should have a list of the attachment names we want to include in the zip file            

            //If we have not found any attachments then return a message
            if (!bAnyAttachments) {
                viewScope.put("errorString", "<center><h3>No attachments found in the Document.</h3></center>");
                return;
            }

            // Set response header values
            HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", -1);
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName);

            // Get stream related objects
            OutputStream outStream = response.getOutputStream();
            ZipOutputStream zipOutStream = new ZipOutputStream(outStream);
            BufferedInputStream bufferInStream = null;

            // Get all attachment names and loop through all of them adding to zip
            for (int i = 0; i < attachments.size(); i++) {
                embeddedObj = downloadDocument.getAttachment(attachments.get(i).toString());
                if (embeddedObj != null) {
                    bufferInStream = new BufferedInputStream(embeddedObj.getInputStream());
                    int bufferLength = bufferInStream.available();
                    byte data[] = new byte[bufferLength];
                    bufferInStream.read(data, 0, bufferLength); // Read the attachment data
                    ZipEntry entry = new ZipEntry(embeddedObj.getName());
                    zipOutStream.putNextEntry(entry);
                    zipOutStream.write(data); // Write attachment into Zip file
                    bufferInStream.close();
                    embeddedObj.recycle();
                }
            }


            // Clean up and close objects
            downloadDocument.recycle();
            zipOutStream.flush();
            zipOutStream.close();
            outStream.flush();
            outStream.close();
            facesContext.responseComplete();

        } catch (Exception e) {
            viewScope.put("errorString", "Error while zipping attachments.<br>" + e.toString());
            e.printStackTrace();
        }
    }
    
    
}

Is there something preventing the second button click from occurring for that 15-20 seconds? Many thanks for any suggestions


Solution

  • Try adding XSP.allowSubmit()to the client side JS event of your button.

    <xp:button value="Download Zipfile 1" id="button1">
        <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
            <xp:this.script><![CDATA[console.log("Button1 click")]]></xp:this.script>
            <xp:this.action><![CDATA[#{javascript:uk.co.mp.DownloadAllAttachments.downloadFromField(context.getUrlParameter("documentId"), "Body1");
    }]]></xp:this.action>
            <xp:this.script><![CDATA[XSP.allowSubmit()]]></xp:this.script>
        </xp:eventHandler>
    </xp:button>