8 Replies Latest reply: Mar 4, 2013 12:56 PM by Dave.Jarvis RSS

    Validation, Task Flow, Servlet, Pop-up, and a Managed Bean

    Dave.Jarvis
      Hi,

      We're trying to display a PDF in a pop-up by calling a Servlet within a JSF page by using a task flow in JDeveloper 11g R2.

      The relevant JSF snippet:
      <af:inlineFrame id="if1" shortDesc="Report" source="/pdfservlet" styleClass="AFStretchWidth"></af:inlineFrame>
      The /pdfservlet points to a Servlet with a doGet method as follows:
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.reset();
        
        OutputStream out = response.getOutputStream();
      
        FacesContext context = this.getFacesContext(request, response);
        OracleReportBean bean =
          context.getApplication().evaluateExpressionGet(context, "#{reportBean}", OracleReportBean.class);
      
        bean.run(context, out);
        removeFacesContext();
      
        out.close();
      }
      The Servlet attempts to get the FacesContext, but we've encountered the following exception:
      Caused By: javax.faces.FacesException: Cant instantiate class: oracle.adfinternal.view.faces.component.AdfViewRoot.
      We removed the following lines from the getFacesContext() method:
      UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "");
      facesContext.setViewRoot(view);
      This avoids the exception above, however... We're trying to get the parameters from the form that was submitted. Here is an example element from the form:
      <h:inputHidden value="MyMedicationList_Report" id="system_REPORT_RESOURCE"/>
      When the Servlet calls the Managed Bean to retrieve the value, it uses:
      Map<String, String[]> requestParameters = getRequestParameters();
      Parameters p = getParameters();
      
      for( String key : requestParameters.keySet() ) {
        for( String value : requestParameters.get( key ) ) {
          int i = key.indexOf( ':' );
      
          if( i >= 0 ) {
            key = key.substring( i + 1 );
          }
      
          p.put( key, value );
        }
      }
      Where getRequestParameters() attempts to get the external context to retrieve the request parameter values map:
      return getExternalContext().getRequestParameterValuesMap();
      The map comes up empty.

      I've tried following http://www.oracle.com/technetwork/developer-tools/adf/learnmore/oct2010-otn-harvest-183714.pdf by setting the web.xml to:
        <!-- JspFilter must be configured before adfBindings. -->
        <filter-mapping>
          <filter-name>JpsFilter</filter-name>
          <servlet-name>PDFServlet</servlet-name>
          <dispatcher>FORWARD</dispatcher>
          <dispatcher>INCLUDE</dispatcher>
          <dispatcher>REQUEST</dispatcher>
        </filter-mapping>
        <filter-mapping>
          <filter-name>adfBindings</filter-name>
          <servlet-name>PDFServlet</servlet-name>
          <dispatcher>FORWARD</dispatcher>
          <dispatcher>REQUEST</dispatcher>
        </filter-mapping>
      And set the data bindings to:
        <pageMap>
          <page path="/pdfservlet" usageId="ca_bcpra_promis_reporting_view_PDFServletPageDef"/>
        </pageMap>
        <pageDefinitionUsages>
          <page id="ca_bcpra_promis_reporting_view_PDFServletPageDef" path="ca.bcpra.promis.reporting.view.PDFServletPageDef"/>
        </pageDefinitionUsages>
      The Servlet executes, calls the instantiated managed bean, but cannot read the request parameters.

      The button used to launch the task flow in a dialog is:
      <af:commandButton text="Run Report" id="submitReport" useWindow="true"
                        windowEmbedStyle="inlineDocument" windowModalityType="applicationModal" windowHeight="500"
                        windowWidth="700" action="runReport"/>
      By using a task flow, the user inputs are validated before the pop-up is opened. We want to keep that behaviour. The PDF opens and then returns with a NullPointerException:

      http://pastebin.com/raw.php?i=PaM64jL4

      The Servlet, through the managed bean, makes a request to the report server to pass parameters and generate a PDF. The PDF is streamed back to the browser via the Servlet.

      What other approaches can we take to:

      1. Send user and system parameters.
      2. Generate a PDF on a remote server.
      3. Stream the PDF back to the user in a pop-up.

      Thank you.
        • 1. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
          Bijesh Krishnadas
          Your best option to pass parameters is to include the get parameters in the URL to the pdfServlet. So something like /pdfServlet?ParamX=YZX and then read using the servlet request object.

          Luc has a post on a very similar requirement - http://technology.amis.nl/2011/07/28/adf-11g-show-pdf-in-a-popup/
          • 2. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
            Dave.Jarvis
            Thank you. We've looked at that solution and our security constraints prevent that solution from working for us.

            The parameters must be hidden for security reasons, and only the web server is allowed to query the report server.

            We cannot use <af:inlineFrame source="http://reports/rwservlet?param=XYZ" .../>

            The Servlet must call the managed bean, which then (eventually) invokes the following code to export the report from the report server to the user's browser:
            URL url = new URL( getReportPath() );
            
            connection = (HttpURLConnection)(url.openConnection());
            connection.setRequestProperty( "Accept-Charset", getCharacterSet() );
            reportStream = connection.getInputStream();
            browserStream = getController().getOutputStream();
            
            if( status ==  HttpURLConnection.HTTP_OK ) {
              copy( reportStream, browserStream );
            }
            The call to getReportPath() performs the magic of determining the report parameters and building the appropriate URL, which, as I mentioned, cannot be revealed to the user.

            See this image: http://i.imgur.com/6PYcoL9.png
            • 3. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
              Bijesh Krishnadas
              When you inline a document, it spawns a new GET request and will not carry over any request parameters from the origin page. Which is why you get an empty request params map.

              You will need to find alternatives to get to the required parameters. For e.g store the parameters in DB with a unique primary key and pass the primary key to the servlet.

              Just to clarify - your requirement is to inline the pdf and providing a download link won't suffice?

              Edited by: Bijesh Krishnadas on Mar 1, 2013 9:18 AM
              • 4. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
                Dave.Jarvis
                It is not a static PDF. The PDF is generated, dynamically, on the report server using the parameters from multiple forms on the page.

                We've leveraged the HttpSession getSessionMap() object for now. When combined with a Method Task Flow, we can transfer the data (and FacesContext) to the report Servlet. For example, the following code exposes objects that the Servlet needs through the session:
                  public void initReport(String reportName) {
                    FacesContext context = FacesContext.getCurrentInstance();
                    ExternalContext ec = context.getExternalContext();
                
                    OracleReportBean bean =
                      context.getApplication().evaluateExpressionGet(context, "#{reportBean}", OracleReportBean.class);
                
                    bean.setFacesContext(context);
                
                    ec.getSessionMap().put("reportBean", bean);
                    ec.getSessionMap().put(Parameters.PARAM_REPORT_RESOURCE, reportName);
                  }
                This means the Servlet can use the object:
                  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                    response.reset();
                
                    // Find the bean from the session.
                    OracleReportBean bean = (OracleReportBean)request.getSession().getAttribute("reportBean");
                
                    OutputStream out = response.getOutputStream();
                    bean.run(out);
                    out.close();
                  }
                This allows the bean to generate reports.
                • 5. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
                  Timo Hahn
                  Dave, it should be possible to get the data control frame of a page inside the servlet. I'm using this trick to stream image or other data back to a client. The second solution in my blog http://tompeez.wordpress.com/2011/12/16/jdev11-1-2-1-0-handling-imagesfiles-in-adf-part-3/ points to a sample by Duncan Mills who shows how to store the current data control frame in the session so that the servlet can use it to get information (in your case some parameters).
                  If this is interesting to you I'll try to find the blog.

                  Timo
                  • 6. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
                    Dave.Jarvis
                    Hi, Timo.

                    Thank you for the response.

                    More information is definitely better. If you would dig up the post and share it, that would be rather helpful.
                    • 7. Re: Validation, Task Flow, Servlet, Pop-up, and a Managed Bean
                      Timo Hahn
                      Here you go
                      https://www.evernote.com/shard/s48//sh/ae8f58be-c4d3-4ab9-8f94-3e01d0e967d0/923ab115aca22fd1e2fccbf6321cbf09

                      Timo