weblogicportalbinary-datajpf

Returning binary content from a JPF action with Weblogic Portal 10.2


One of the actions of my JPF controller builds up a PDF file and I would like to return this file to the user so that he can download it.

Is it possible to do that or am I forced to write the file somewhere and have my action forward a link to this file? Note that I would like to avoid that as much as possible for security reasons and because I have no way to know when the user has downloaded the file so that I can delete it.

I've tried to access the HttpServletResponse but nothing happens:

getResponse().setContentLength(file.getSize());
getResponse().setContentType(file.getMimeType());
getResponse().setHeader("Content-Disposition", "attachment;filename=\"" + file.getTitle() + "\"");
getResponse().getOutputStream().write(file.getContent());
getResponse().flushBuffer();

Solution

  • We have something similar, except returning images instead of a PDF; should be a similar solution, though, I'm guessing.

    On a JSP, we have an IMG tag, where the src is set to:

    <c:url value="/path/getImage.do?imageId=${imageID}" />
    

    (I'm not showing everything, because I'm trying to simplify.) In your case, maybe it would be a link, where the href is done in a similar way.

    That getImage.do maps to our JPF controller, obviously. Here's the code from the JPF getImage() method, which is the part you're trying to work on:

    @Jpf.Action(forwards = {
        @Jpf.Forward(name = FWD_SUCCESS, navigateTo = Jpf.NavigateTo.currentPage),
        @Jpf.Forward(name = FWD_FAILURE, navigateTo = Jpf.NavigateTo.currentPage) })
    public Forward getImage(final FormType pForm) throws Exception {
      final HttpServletRequest lRequest = getRequest();
      final HttpServletResponse lResponse = getResponse();
      final HttpSession lHttpSession = getSession();
      final String imageIdParam = lRequest.getParameter("imageId");
    
      final long header = lRequest.getDateHeader("If-Modified-Since");
      final long current = System.currentTimeMillis();
    
      if (header > 0 && current - header < MAX_AGE_IN_SECS * 1000) {
        lResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        return null;
      }
    
      try {
        if (imageIdParam == null) {
          throw new IllegalArgumentException("imageId is null.");
        }
    
        // Call to EJB, which is retrieving the image from
        // a separate back-end system
        final ImageType image = getImage(lHttpSession, Long
            .parseLong(imageIdParam));
    
        if (image == null) {
          lResponse.sendError(404, IMAGE_DOES_NOT_EXIST);
          return null;
        }
    
        lResponse.setContentType(image.getType());
        lResponse.addDateHeader("Last-Modified", current);
        // public: Allows authenticated responses to be cached.
        lResponse.setHeader("Cache-Control", "max-age=" + MAX_AGE_IN_SECS
            + ", public");
        lResponse.setHeader("Expires", null);
        lResponse.setHeader("Pragma", null);
        lResponse.getOutputStream().write(image.getContent());
    
      } catch (final IllegalArgumentException e) {
        LogHelper.error(this.getClass(), "Illegal argument.", e);
        lResponse.sendError(404, IMAGE_DOES_NOT_EXIST);
      } catch (final Exception e) {
        LogHelper.error(this.getClass(), "General exception.", e);
        lResponse.sendError(500);
      }
      return null;
    }
    

    I've actually removed very little from this method, because there's very little in there that I need to hide from prying eyes--the code is pretty generic, concerned with images, not with business logic. (I changed some of the data type names, but no big deal.)