Skip to Content

Recently, we faced a scenario where we had to retrieve the documents attached to a Business Object and then had to display the attachment in the NetWeaver Portal.
I faced some problems in achieving this and found that many other

fellow SDN’ers

faced similar issues( like document getting corrupted while displaying ), so i decided to jot down this blog discussing how to fetch the attached documents of objects when we store them in an application transaction using

Services for the Object

or use

SAPoffice

as the document storage location and then how to display the document in a

Business Server Page(BSP)

and in a

WebDynpro Java application.

There are general functions that we want to execute, like creating a note for an object, sending an object, or starting a workflow for an object, some of which can only be realized for a specific object type with a great deal of programming.
If we store documents in an application transaction using “Services for the Object” or use “SAPoffice” as the document storage location, the attachments are linked with the application objects via binary links of the

Object Relationship Service (ORS)

.
In order to determine the contents of the document attached to the object, we must first read the corresponding links, and then determine the contents from the linked documents.

As of Basis Release 6.10, this can done by calling the public static method

CL_BINARY_RELATION=>READ_LINKS_OF_OBJECTS

. After calling this, the links appear in the internal table ET_LINKS and we get the objects of type MESSAGE that are given an ID .

I created a remote enabled “Z” Function module encapsulating the call to the method of the class CL_BINARY_RELATION, as follows:

h5. IMPORT

Parameter name

Type Specification

Associated Type

I_INSTANCEID

TYPE

SIBFLPORB-INSTID

I_TYPEID

TYPE

TYPEID

I_CATID

TYPE

CATID

h5. EXPORT

Parameter name

Type Specification

Associated Type

DOCUMENT_ID

TYPE

SOFOLENTI1-DOC_ID

EXCEPTION_STRING

TYPE

STRING

h5. IMPLEMENTATION


DATA:  is_object TYPE sibflporb,

         et_links TYPE obl_t_link,

         et_links_s TYPE obl_s_link ,

         RESULT TYPE C,

         icx_obl_parameter_error TYPE REF TO cx_obl_parameter_error ,

         icx_obl_internal_error TYPE REF TO cx_obl_internal_error,

         icx_obl_model_error TYPE REF TO cx_obl_model_error,

*************initialize*******

  is_object-instid = I_INSTANCEID. * ( Instance ID )

  is_object-typeid = I_TYPEID. * (Type of Objects in Persistent Object References EG: BUS2045 FOR Business Object INSPECTION LOTS)

  is_object-catid  = I_CATID. *(Category of Objects in Persistent Object References default BO)

***********************read attachments of relationship type ‘ATTA’

  TRY.

      CALL METHOD cl_binary_relation=>read_links_of_binrel

        EXPORTING

          is_object    = is_object

  •    IP_LOGSYS    =

          ip_relation  = ‘ATTA’

  •    IP_ROLE      =

  •    IP_PROPNAM   =

  •    IP_NO_BUFFER = SPACE

        IMPORTING

          et_links     = et_links

  •    ET_ROLES     =

          .

    CATCH cx_obl_parameter_error INTO icx_obl_parameter_error.

      EXCEPTION_STRING = icx_obl_parameter_error->get_longtext( ).

    CATCH cx_obl_internal_error INTO icx_obl_internal_error  .

      EXCEPTION_STRING = icx_obl_internal_error->get_longtext( ).

    CATCH cx_obl_model_error INTO icx_obl_model_error.

     EXCEPTION_STRING = icx_obl_model_error->get_longtext( ).

  ENDTRY.

  IF et_links[] IS NOT INITIAL.

    SORT et_links BY utctime DESCENDING .

    READ TABLE et_links INDEX 1 INTO et_links_s .

     document_id = et_links_s-instid_b .

**We can pass the entire list of attachments as export parameter or sort by time and send only the latest attachment. **

  ENDIF.

CALL FUNCTION ‘SO_DOCUMENT_READ_API1’

    EXPORTING

      document_id                      = docid

  •   FILTER                           = ‘X ‘

IMPORTING

   DOCUMENT_DATA                    = DOCUMENT_DATA

   TABLES

     object_header                    = object_header

     object_content                   = object_content

  •   OBJECT_PARA                      =

  •   OBJECT_PARB                      =

  •   ATTACHMENT_LIST                  =

  •   RECEIVER_LIST                    =

    CONTENTS_HEX                     = CONTENTS_HEX

  • EXCEPTIONS

  •   DOCUMENT_ID_NOT_EXIST            = 1

  •   OPERATION_NO_AUTHORIZATION       = 2

  •   X_ERROR                          = 3

  •   OTHERS                           = 4

            .

  DATA:object_header_str TYPE solisti1,

       object_content_str TYPE solisti1,

       FILE_TYP TYPE STRING.

  CLEAR:temp,object_header_str,object_content_str .

  IF object_header IS NOT INITIAL.

    LOOP AT object_header INTO object_header_str .

      IF sy-tabix EQ ‘1’.

        SPLIT object_header_str-line AT ‘.’ INTO file_name FILE_TYP.

      ENDIF.

      IF sy-tabix EQ ‘2’.

        SPLIT object_header_str-line AT ‘=’ INTO temp file_format.

      ENDIF.

    ENDLOOP.

  ENDIF.

  DATA:file_content_temp TYPE string.

  data:input_length type i,

       lin type i.

  CLEAR file_content_temp .

  if file_format EQ ‘BIN’.

 

************concatenate content as xstring*********

  IF CONTENTS_HEX IS NOT INITIAL.

  DESCRIBE TABLE CONTENTS_HEX LINES lin.

  input_length = lin * sy-tleng .

  CALL FUNCTION ‘SCMS_BINARY_TO_XSTRING’

    EXPORTING

      input_length       = input_length

  •     FIRST_LINE         = 0

  •     LAST_LINE          = 0

   IMPORTING

     BUFFER             = FILE_CONTENT

    tables

      binary_tab         = CONTENTS_HEX

  •   EXCEPTIONS

  •     FAILED             = 1

  •     OTHERS             = 2

            .

  IF sy-subrc <> 0.

  • MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO

  •         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

  ENDIF.

if FILE_TYP EQ ‘pdf’.

  file_mime_type = ‘application/pdf’ .

else if FILE_TYP EQ ‘doc’.

  file_mime_type = ‘application/msword’ ..

else if FILE_TYP EQ ‘xls’.

  file_mime_type = ‘application/vnd.ms-excel’ .

*similarly for others

ENDIF.

  ELSE.

  file_mime_type = ‘text/html’ .

  IF object_content IS NOT INITIAL.

   CALL FUNCTION ‘SCMS_TEXT_TO_XSTRING’

  •    EXPORTING

  •      FIRST_LINE       = 0

  •      LAST_LINE        = 0

  •      MIMETYPE         = ‘ ‘

    IMPORTING

      BUFFER           = FILE_CONTENT

     TABLES

       text_tab         = object_content

  •    EXCEPTIONS

  •      FAILED           = 1

  •      OTHERS           = 2

             .

   IF sy-subrc <> 0.

  • MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO

  •         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

   ENDIF.

  ENDIF.

  endif.

*************display in Browser***********************

  IF  XSTRLEN( file_content ) > 0.

    DATA: cached_response TYPE REF TO if_http_response.

    CREATE OBJECT cached_response TYPE cl_http_response EXPORTING

  add_c_msg = 1.

    cached_response->set_data( file_content ).

    cached_response->set_header_field( name  =

  if_http_header_fields=>content_type

                                       value = file_mime_type ).

    cached_response->set_status( code = 200 reason = ‘OK’ ).

    cached_response->server_cache_expire_rel( expires_rel = 180 )

.

    DATA: guid TYPE guid_32.

    CALL FUNCTION ‘GUID_CREATE’

      IMPORTING

        ev_guid_32 = guid.

    CONCATENATE runtime->application_url ‘/’ guid INTO display_url

.

    cl_http_server=>server_cache_upload( url      = display_url

                                     response = cached_response )

.

    RETURN.

  ENDIF.

Now, we would create a similar application in

WebDynpro-Java

.
The same function modules (The Z Function module and SO_DOCUMENT_READ_API1) would be used but in addition to them we would do some processing as we did in the BSP application, depending upon the type of document returned(BIN or ASC).

So, create a WebDynpro project in the NetWeaver Developer Studio. Create an RFC adaptive model for the required Function Modules,( Z Function module to get the latest attachment and the standard function module SO_DOCUMENT_READ_API1).
We would display the attachment in a popup window, so create the window

“PopupWindow”

and the view

“AttachmentView”

apart from the main window

“ReadAttachmentWindow”

and main View

“ReadAttachmentComponentView”

.

The main view contains an

input field

and a

button

while the popup view contains an

iframe

and a

button

to close the popup.

The project structure would be as follows:

image

Map the controller context to the model as

!https://weblogs.sdn.sap.com/weblogs/images/36759/ComponentmodelBinding.PNG|height=370|alt=image|width=484|src=https://weblogs.sdn.sap.com/weblogs/images/36759/ComponentmodelBinding.PNG|border=0!

Edit and map the View Context for the “ReadAttachmentComponentView” view to the Component Controller context as

!https://weblogs.sdn.sap.com/weblogs/images/36759/MainViewControllermapping.PNG|height=340|alt=image|width=514|src=https://weblogs.sdn.sap.com/weblogs/images/36759/MainViewControllermapping.PNG|border=0!

Map the popup view context to the component controller context as

!https://weblogs.sdn.sap.com/weblogs/images/36759/popupconetxtmenu.PNG|height=269|alt=image|width=511|src=https://weblogs.sdn.sap.com/weblogs/images/36759/popupconetxtmenu.PNG|border=0!

Now we create some methods in our component controller, which will be responsible for executing the models, processing the values, setting context values etc.

public void getDocID( )

{

//@@begin getDocID()

1) Execute the model object for the Z Function module to retrieve the document ID for the business object instance

//@@end

}

public void openPopUp( )

{

1) Open Pop up window to show document

}

public void closePopUp( )

{

1) Destroy and close the pop up window for attachment

}

public byte[] createAttaSource( )

This method is used for attachments of type

BIN

when we need to read rows of bytes from table

Contents_Hex

and create a single byte stream to re-create the attachment.

public java.lang.String createTxtSrc( )

This method is used for attachments of type

ASC

when we have to read “lines” of strings from table

Object_Content

and create a single string.

public void prepToOpenAtta( )

This method is used to determine the type of attachment being returned((ASC or BIN)) by the call to the Function module SO_DOCUMENT_READ_API1 , to call the appropriate method for the processing required, to set the mime type of the attachment document returned, to generate and retrieve the URL of the Web Resource thus formed and to set the context value storing the URL for that particular attachment.

public void getAttaDoc( )

{

//@@begin getAttaDoc()

1)Call method getDocID( ) and set the input value Document_Id for the model object for SO_Document_Read_API1

2) Execute the model object for SO_DOCUMENT_READ_API1 and invalidate the output context nodes.

3)Call Method prepToOpenAtta();

4)Call openPopUp();

//@@end

}

In “ReadAttachmentComponentView”,the method corresponding to the button action “

getDocument

public void onActiongetDocument(com.sap.tc.webdynpro.progmodel.api.IWDCustomEvent wdEvent )

{

//@@begin onActiongetDocument(ServerEvent)

1) Call the component controller method getAttaDoc();

//@@end

}

When we enter the Instance Id of the business object(for eg:Inspection Lot Number) and press the button in the main view (“ReadAttachmentComponentView”), the attached document is retrieved , processed , a web resource is generated and the URL is retrieved and set for iFrame in the popup view.

Hope this blog would help SDN’ers facing problems in retrieving and displaying attachments.

Note: The code provided is for illustration purposes only and so it does not gurantee completeness nor correctness!!

   

To report this post you need to login first.

6 Comments

You must be Logged on to comment or reply to a post.

  1. Ray Ng
    Have you tried with 2007 Excel native format with .xlsx open XMl format?  I have been having problem opening the file.
    (0) 

Leave a Reply