2
votes

I use this code in my xpage to download a file from a remote server. When the user click a download button from the xpage a new download.xsp page opens up and runs the code below.

#{javascript:
var exCon = facesContext.getExternalContext();
var response = exCon.getResponse();
var out = response.getOutputStream();

var zipfile = sessionScope.thezip;
var dname = zipfile.substring(zipfile.lastIndexOf("\\")+1);

dl.download(zipfile,dname);
sessionScope.thezip = null;

response.setContentType("application/zip, application/octet-stream");
response.addHeader("Content-disposition","attachment; filename="+dname);
response.setHeader("Cache-Control", "no-cache");

facesContext.responseComplete();
out.close();

Download method (db.download(string,string)) is a Java method which is brought up to the xpage as a managed bean.

public void download(String filepath, String dname){
        Connection con = null;
        PreparedStatement stm = null;
        ResultSet rs = null;
        try{
            Class.forName(jdbcClass);
            con = DriverManager.getConnection(url);

                String insSql = "INSERT INTO Cache(name,zip) SELECT '"+filepath+"',* FROM OPENROWSET(BULK N'"+filepath+"', SINGLE_BLOB) AS import;";
                stm = con.prepareStatement(insSql);
                stm.executeUpdate();

            String sql = "SELECT TOP 1 * FROM Cache where name = ?;";
            stm = con.prepareStatement(sql);
            stm.setString(1, filepath);
            rs = stm.executeQuery();

            while(rs.next()){
                InputStream zip = rs.getBinaryStream("zip");

                FacesContext facesContext = FacesContext.getCurrentInstance(); 
                ExternalContext externalContext = facesContext.getExternalContext();
                HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
                response.setContentType("application/zip, application/octet-stream");
                response.setHeader("Content-disposition","attachment; filename="+dname);
                response.setHeader("Cache-Control", "no-cache");

                byte[] buf = new byte[8192];
                int c = 0;

                while ((c = zip.read(buf, 0, buf.length)) > 0) {
                    OutputStream o = response.getOutputStream();
                    o.write(buf, 0, c);
                    o.close();
                }
                zip.close();
            }

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try{
                if(stm!=null){stm.close();}
                if(rs!=null){rs.close();}
                if(con!=null){con.close();}
            }catch(Exception ex){ex.printStackTrace();}
        }

    }

This java code runs an sql query to get a zip file as bytes and store it in a table. Then it select this row and returns the bytes to the caller java method. This way i get the remote file because there is no webserver to provide a url.

My problem is how can i use the httpResponse outputStream so as to download 2 or 3 files? if i copy-paste the code i get only the first file. I i try not to close the outputStream i get an error that the stream is already in use.

Does anyone have any idea?

P.S: Above code is tested and works fine if i want to download 1 file only.

1

1 Answers

6
votes

Your best bet would likely be to combine the multiple files into another ZIP file dynamically using the java.util.zip classes. You could wrap the output stream with ZipOutputStream and then loop through your ResultSet rows, creating ZipEntry objects to distinguish each file within it.