Announcement Announcement Module
Collapse
No announcement yet.
Writing a byte[] to the response without getting an exception Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Writing a byte[] to the response without getting an exception

    Hi All,

    I have been using Webflow 1.0.3 (version required by client) to create a little application to show (not create) a pdf file in the browser. I have it working fine, but when viewing the pdf I get an org.springframework.webflow.engine.NoMatchingTrans itionExceptionexception in the log.

    Here is my Action class:
    Code:
    public class Action extends FormAction {
      public Event getFile(RequestContext ctx) throws Exception {
      ....
      // Get the response object from the context
      ServletExternalContext servletContext = (ServletExternalContext)ctx.getExternalContext();
      HttpServletResponse response = servletContext.getResponse();
      
      try {
        getFileResponse = serviceStub.getFile(getFileRequest);
        
        // Get the response from web service and convert to a byte array
        DataHandler fileHandler = getFileResponse.get_return();
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        fileHandler.writeTo(os);
        file = os.toByteArray();
        
        response.setContentType("application/pdf");
        response.setContentLength(file.length);
        
        // Set the filename and cache settings (for IE)
        response.setHeader("Content-Disposition", "inline; filename=file.pdf");
        response.setHeader("Pragma", "public");
        response.setHeader("Cache-Control", "cache");
        response.setHeader("Cache-Control", "must-revalidate");
        
        // Write the file to the response
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(file); 
        outputStream.flush();
        outputStream.close();
      
      } catch (RemoteException e) {
        e.printStackTrace();
      }
      catch (IOException e) {
        e.printStackTrace();
      }
      return null;
      //return success();
    And here is my flow definition:
    Code:
    <start-state idref="printHelloWorldView" />
    
    <view-state id="printHelloWorldView" view="index">
      <transition on="submit" to="getViewAction"/>
    </view-state>
    
    <action-state id="getViewAction"> 
      <action bean="action" method="getFile" />
      <transition on="*" to="finish"/>
    </action-state>
    
    <end-state id="finish" view="finish"/>
    And the exception I get is:
    Code:
    org.springframework.webflow.engine.NoMatchingTransitionException: No transition was matched on the event(s) signaled by the [1] action(s) that executed in this action state 'getViewAction' of flow 'main'; transitions must be defined to handle action result outcomes -- possible flow configuration error? Note: the eventIds signaled were: 'array<String>[[null]]', while the supported set of transitional criteria for this action state is 'array<TransitionCriteria>[*]'
    	at org.springframework.webflow.engine.ActionState.doEnter(ActionState.java:212)
    	at org.springframework.webflow.engine.State.enter(State.java:200)
    	at org.springframework.webflow.engine.Transition.execute(Transition.java:229)
    So, I understand why this is happening, it's because I am writing directly to the http response object (which is outside the scope of Webflow), no Event object is returned and therefore the flow controller doesn't know what to do next.

    As you can see I also tried returning sucess(), but I now get an exception saying: java.lang.IllegalStateException: getOutputStream() has already been called for this response.

    So does anyone have any ideas about how to get around this problem? I need to view the pdf inline rather than being a download/attachment so I can't use org.springframework.web.servlet.view.document.Abst ractPdfView. Also I get a file from a web service request rather than building it myself too.

    Sorry for such a long post, thanks in a advance for any help, it's greatly appreciated.

    Dave

  • #2
    I think that return null; is not a valid Event value.
    therefore in your exception appear

    Code:
    transitions must be defined to handle action result outcomes 
    -- possible flow configuration error?
    Note: the eventIds signaled were: 'array<String>[[null]]'

    You should use your comment line return success();

    First time that I see on="*" (is legal?)

    As you can see I also tried returning sucess(), but I now get an exception saying: java.lang.IllegalStateException: getOutputStream() has already been called for this response.
    It should be the correct approach,
    therefore getOutputStream() must be handle


    So does anyone have any ideas about how to get around this problem? I need to view the pdf inline rather than being a download/attachment so I can't use org.springframework.web.servlet.view.document.Abst ractPdfView. Also I get a file from a web service request rather than building it myself too.
    Ok by parts (for the second bold part),

    normally I used to work with
    org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
    Can you use jasperreport to generate the report?
    and send it to the flow scope?

    (for the first bold part)
    the same browser (Firefox, Opera, IE I dont know) let you configure if the pdf should be open in the same browser window/tab (your requeriment) or if should be download , therefore check it out.

    I hope you project works in an intranet therefore then configure each browser in the worst of the cases (I dont know if with java code you can do mandatory that the browser open in the same window the pdf file - perhaps your code do that, but you are missing maybe do the fusion with SWF (sending the object to the flow scope) to avoid the exception)

    but see jasperreport how a solution, it works fine with SWF

    HTH
    Last edited by dr_pompeii; Jan 11th, 2009, 06:38 PM.

    Comment


    • #3
      Got it working!!!

      Thanks for the quick response. I followed your suggestion and extended AbstractView.

      For anyone else who comes across this problem this is how I fixed it:
      Servlet config, notice the order=1, thats what makes all this work
      Code:
      <!-- Resolves the pdf view to a PDF document -->
      <bean id="pdfViewResolver" class="view.PDFViewResolver">
        <property name="order" value="1" />
      </bean>
      
      <!-- Resolves flow view names to .jsp templates -->
      <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
        <property name="order" value="2" />
      </bean>
      My flow definition:
      Code:
      <view-state id="indexView" view="index">
        <transition on="submit" to="pdfRenderer"/>
      </view-state>
      
      <view-state id="pdfRenderer" view="pdf">
        <render-actions>
          <action bean="action" method="renderPDF"/>
        </render-actions>
      </view-state>
      My action class:
      Code:
      public Event renderPDF(RequestContext ctx) {
        byte[] file = getFileFromWebService();
        ctx.getFlashScope().put("file", file);
        
        return success();
      }
      My View class:
      Code:
      public class PDFView extends AbstractView {
      @Override
      protected final void renderMergedOutputModel(
          Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        
        byte[] file = (byte[])model.get("file");
        if(null == file) {
          System.err.println("File is NULL");
        }
      
        response.setContentType("application/pdf);
        response.setContentLength(file.length);
        
        response.setHeader("Content-disposition", "inline;filename=file.pdf");
        response.setHeader("Cache-Control", "cache");
        response.addHeader("Cache-Control", "must-revalidate");
        response.setHeader("Pragma", "public");
        
        ServletOutputStream out = response.getOutputStream();
        out.write(file);
        
        out.flush();
      }
      And lastly my View Resolver:
      Code:
      public class PDFViewResolver extends AbstractCachingViewResolver implements Ordered {
      
      @Override
      protected View loadView(String viewName, Locale local) throws Exception {
        if (viewName != null) {
          if ("pdf".equals(viewName)) {
            logger.debug("Creating an PDFView for view name " + viewName);
            return new PDFView();
          }
        }
        return null;
      }
      Thanks @dr_pompeii

      Comment

      Working...
      X