cancel
Showing results for 
Search instead for 
Did you mean: 

Get PDF file from R/3 and display in a WD application

Former Member
0 Kudos

I have a WD application which will call an R/3 RFC that returns a binary PDF file (actually it is in the form of an internal table structure like TLINE).

In a servlet application, one could pass this binary file to the HTTP request object, set the correct mime type and the browser does the rest.

How do I do this in a WD application?

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

Thank you Tom and Stefan!

I am using the Sneak preview because the only Web AS server being shipped today is 6.20. As you know, 6.40 is in ramp-up and will be GA around Oct 2004. I don't want to learn/develop applications on 6.2 and then upgrade/learn new 6.40 features later I would rather use 6.40 to do adventure missions!

Back to my original questions and your responses... This is what I understand from your responses - Since the R/3 RFM is sending back an internal table of structure TLINE [TDFORMAT(2), TDLINE(132)], the ideal way would be to use the InteractiveForm. But since the sneak preview does not support the runtime of InteractiveForm, I guess I will have to use the IFrame.

I did try using IFrame but I have this question now - How do I set the source property of IFrame to this returned TLINE internal table.

Former Member
0 Kudos

Hi,

it's all about URLs. You'll need the url of a servlet, which transfers the PDF data to the browser. Setting this url as the source property of the IFrame actually "calls back" your servlet. You've to set the content-type to pdf and fill the response data and length.

BTW, didn't you say in your initial post that you have such a servlet already?

Hope that helps.

Regards

Stefan

Former Member
0 Kudos

Stefan,

In my initial post, I was trying to use logic used in servlets to try to relate my question in WD terms - it seems that analogy put my original question on the wrong track for you - sorry for that

Let me rephrase my question - I do not have a servlet that is passing PDF data to the WD application rather it is an R/3 BAPI/RFM that is passing this data. I want to use this data (passed via an Internal table of format TLINE) to display a PDF file in a WD application.

Thanks for you help!

Former Member
0 Kudos

Hi,

no you didn't put me on the wrong track, the only misunderstanding was that i thought you have the servlet already available.

I implemented exactly such an application sometime ago, where there was no InterActiveForm element available yet (since you doesn't have it in Sneak Preview, it's quite similar).

I used the CONVERT_OTF_TO_PDF FM (not really sure if the name is exactly spelled) in ABAP to convert SmartForms output to pdf and an own RFM (let's call it GET_PDF) which transported the TLINE data to the "outside world".

This is one possible sequence to do that:

1. In your WD application you create an IFrame bound to a string context value attribute named "url" for example.

2. After getting the TLINE data you store the data in a file (here 1.pdf) and set the url to the servlet url, something like: http://yourhost:50000/GetPdf/servlet/GetPdfServlet?file=1.pdf

3. The servlet is "called back by the IFrame" by setting the url and opens the file available in request parameters, sets content-type, length and content of the HttpServletResponse.

That's it.

Hope that helps.

Regards

Stefan

Former Member
0 Kudos

Stefan,

You are awesome!!

Thanks for your help!! I will try this out!

Former Member
0 Kudos

Stefan,

Now that we are implementing your idea, here are some questions:

How do we convert the output node for the PDF(TLINE) internal table to a binary stream? I am using the following code to convert data from TLINE format to binary but not able to convert correctly. Is there a more elegant/recommended way?


aFileWriter = new FileWriter(aFileName);
CharArrayWriter aStream = new CharArrayWriter();
IPublicDisplayPDFComponent.II_Pdf_OutputNode node = wdContext.nodeI_Pdf_Output();
IWDNodeElement element;
node.moveFirst();
element = node.getCurrentElement();
while ((element) != null) {
	String sTdformat = element.getAttributeValue("Tdformat").toString();

	String sTdline = element.getAttributeValue("Tdline").toString();

        aStream.write(sTdformat.toCharArray(), 0, sTdformat.length());
        aStream.write(sTdline.toCharArray(), 0, sTdline.length());

	element = node.moveNext();
}
aFileWriter.write(aStream.toCharArray(),
		  0,
		  aStream.toCharArray().length);
		  aFileWriter.flush();

Former Member
0 Kudos

Hi,

i'll have a look, if i'm able find the servlet and corresponding WD sample code, stay tuned

Just one hint: The string conversion of the PDF data may lead to invalid character conversions (and therefore to invalid PDF data).

Regards

Stefan

Former Member
0 Kudos

An alternative solution for getting PDF...

My friend Renjith, has designed a solution using "FileDownload" UI element. Advantage is you don't require an IFrame. Disadvantage is you don't have an IFrame.

<u>STEPS</u>

1.Attach "FileDownload" UI element to your WD View

2.Poplulate the output from the TLINE table to a string variable(Loop through TLINE and concatenate TDFORMAT AND TDLINE eg : String str = TDFORMAT + TDLINE )

3.Get the byte array out of str

4.Bind it to the Value attribute(binary) that is mapped to the "FileDownload"

If you are not able to get it through, let me know....

Thanks and Regards,

Sam Mathew

Former Member
0 Kudos

Sam, Thank you for your reply!

I had tried the solution you posted before going the IFrame way. In both the solutions, the first problem I am facing is that I cannot convert the TLINE(TDFORMAT + TDLINE) format to a valid binary format. The file seems corrupted. Is there something that I have to do special to get the TLINE format into a binary one? (Please refer to the code in my earlier post).

Former Member
0 Kudos

Hi Singhvi,

You are right ..The out put from SAP is correpted because of some missing spaces...

Please try the following code ..

String str = new String();

String strtmp = "";

String strtmp1 = "";

List lst = wdContext.currentModElement().modelObject().getOutput().getItab();

for (Iterator iter = lst.iterator(); iter.hasNext();) {

Tline element = (Tline) iter.next();

strtmp = element.getTdformat();

int diff = 2 - strtmp.length();

while (diff > 0){

strtmp = strtmp + " ";

diff--;

}

strtmp1 = element.getTdline();

diff = 132 - strtmp1.length();

while (diff > 0){

strtmp1 = strtmp1 + " ";

diff--;

}

str = str + strtmp + strtmp1;

}

Thanks and Regards,

Sam Mathew

Former Member
0 Kudos

Hi,

sorry for the delay. Unfortunately i didn't find the source code of the servlet/WD projects. But i remember that there were problems according to possible codepage conversions when using the Tdline-approach with chars/Strings.

What you can do is create a remote function module, which calls sx_object_convert_otf_pdf and transports the resulting SOLI items as SOLIX items to the caller. This is much easier to handle on the Java side, since you'll get a byte[] for each SOLIX item, there's no conversion, all you have to do is to concat the byte arrays up to total content length.

Code snippet of function module sx_object_convert_otf_pdf:

function sx_object_convert_otf_pdf.
...
data: pdf_lines like content_out occurs 100.

call function  'CONVERT_OTF'
     exporting  format                = 'PDF'
                max_linewidth         = 134
     importing  bin_filesize          = len_out
     tables     otf                   = content_in
                lines                 = pdf_lines
     exceptions err_max_linewidth     = 1
                err_format            = 2
                err_conv_not_possible = 3
                others                = 4.
if sy-subrc <> 0.
  ...
endif.
call function  'SX_TABLE_LINE_WIDTH_CHANGE'
     exporting  line_width_src              = 134
                line_width_dst              = 255
     tables     content_in                  = pdf_lines
                content_out                 = content_out
     exceptions err_line_width_src_too_long = 1
                err_line_width_dst_too_long = 2
                err_conv_failed             = 3
                others                      = 4.
if sy-subrc <> 0.
  ...
endif.

<b>* In your own FM, add a TABLE parameter transfer_out
* of structure SOLIX.
* this will result in a byte[] array transfer in 
* the corresponding proxy or WD model attribute

refresh transfer_out.
move content_out[] to transfer_out[].</b>
endfunction.

Sorry for the inconvenience.

Hope that helps.

Regards

Stefan

matt_steiner
Active Contributor
0 Kudos

Hi folks,

just to desribe another approach:

Use the CONVERT_OTF function to create the binary for you (in later releases ~ 6.30) there's a parameter called BIN_FILE of type XSTRING.

Create an RFC Proxy and you'll get the data as a byte array in java.

On the WebDynpro you can use the FileDownload Control to access the data. Bind it to a Value Attribute of your Context of type binary (e.g. BinaryFileObject).

Here's a code snippet for you to see how to set the byte stream:

byte[] binaryFile = null;

// @TODO call the proxy and set the binaryFile

IWDAttributeInfo attInfo = wdContext.getNodeInfo().getAttribute("BinaryFileObject");

ISimpleTypeModifiable type = attInfo.getModifiableSimpleType();

IWDModifiableBinaryType binaryType = (IWDModifiableBinaryType)type;

binaryType.setFileName("test.pdf");

binaryType.setMimeType(WDWebResourceType.PDF);

this.wdContext.currentContextElement().setBinaryFileObject(binaryFile);

Hope this helps

Regards

Matthias

Former Member
0 Kudos

Thanks, Sam, Stefan and Matthias for these responses!! It definitely helps a newbie WD developer like me to get support from experts like you! I am going to try <b>all</b> these different approaches!

Biraj
Associate
Associate
0 Kudos

Hello,

I'm fairly new to webdynpro and am trying to render a pdf in webdynpro.

I implemented the methods mentioned by all of you but somehow the pdf does not get rendered.The webdynpro application runs but I see only a blank screen with the title.Is there any specific setting I need to do in order to view this pdf?

Thanks in advance

Biraj

Answers (5)

Answers (5)

Former Member
0 Kudos

I have a Web Dynpro application which will call an R/3 RFC that returns a PDF file.

1) Is it possible to pass parameters dynamically (For eg userid of the person who has logged onto the portal) from webdynpro to a RFC? If yes, how?

Thanks in advance.

Jayesh

BeGanz
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hallo K.,

all the described solutions do not utilize the generic Web Dynpro service class <b>WDWebResource</b>. With this service you can store some dynamic resource in the Web Dynpro Runtime cache and then address it in an InteractiveForm-UI-Element, an Iframe or an external URL window. Here is the sample code based on a toplevel context attribute of type <i>binary</i> with name <i>PDFDoc</i>:

//@@begin javadoc:wdDoInit()
  /** Hook method called to initialize controller. */
  //@@end
  public void wdDoInit()
  {
    //@@begin wdDoInit()
 
    // Modify datatype, propare datatype for modifications done by the runtime
    wdContext.getNodeInfo().getAttribute("PDFDoc").getModifiableSimpleType();

    //@@end
  }


//@@begin javadoc:onActionUpload(ServerEvent)
  /** Declared validating event handler. */
  //@@end
  public void onActionLoadPDF(com.sap.tc.webdynpro.progmodel.api.IWDCustomEvent wdEvent )
  {
    //@@begin onActionUpload(ServerEvent)
    IWDCachedWebResource cachedResource = null;
    String pdfUrl = null;

    /* precondition: the byte array containing the PDF 
       source must already be stored in the context 
       attribute.  In practice this is e.g. done by 
       executing a model class for retreiving the PDF 
       from a R/3 system. */
    
    loadPDFIntoContext();

    WDWebResourceType type =
      ((ModifiableBinaryType) wdContext
        .getNodeInfo()
        .getAttribute("PDFDoc")
        .getModifiableSimpleType())
        .getMimeType();

       byte[] pdf = wdContext.currentContextElement().getPDFDoc();

    if (pdf != null) {
      cachedResource = WDWebResource.getWebResource(pdf, type);

      try {
        pdfUrl = cachedResource.getURL();
        wdContext.currentContextElement().setPDFUrl(pdfUrl);
      } catch (WDURLException e) {
        wdComponentAPI.getMessageManager().reportException(e.getLocalizedMessage(), true);
      }
    }

    //@@end
  }
 

This is a much more simple solution than all other described workarounds. By the way, I'm quite impressed by the creativity (of former posts) for finding an own solution for this problem. Nevertheless the WDWebResource-approach is the favorable one.

Greetings, Bertram

Former Member
0 Kudos

Sam is right, but only if you don't have WebAS Sneak Preview, since there are the InteractiveForm services missing and it will not work at runtime if you use the InteractiveForm UIElement.

Regards

Stefan

Former Member
0 Kudos

Hi,

More specific to WD, you have the option of using "InteractiveForm" UI element to display a PDF File.

You could use the TLINE itself as a datasource for the UI element.

Thanks and Regards,

Sam Mathew

Former Member
0 Kudos

It's possible exactly like you've described it. Use an IFrame for that and set the Url of the IFrame to the servlet-Url, specifying dynamic url-parameters like an PDF-id or a Web-resource path which the servlet should use. You don't even have to change the servlet for that. The IFrame is like a browser in the browser and acts as usual (activating Adobe Acrobat Reader plugin).

Hope that helps.

Regards

Stefan