Professional Documents
Culture Documents
IDOC As Web Service
IDOC As Web Service
We had a requirement to convert IDOCs in web service without PI (PO). We tried to find out
whether SAP provides such solutions. SAP replied to our OSS message saying NO. So we
developed our own solution that can convert any IDOC into a web service within minutes. Here I
will explain the steps.
Once you set up the system then all programs are reusable to convert any IDOC into web
service.
Step 1. Create WSDL for the IDOC basic type or extension type
Step 2. Create server proxy for the WSDL to host the IDOC
Step 1. Create WSDL for the IDOC basic type or extension type. You dont need to transport step
1 to subsequent systems.
II) Create method GET_WSDL. Paste the source code attached below.
2) Copy program SAPMSEDIDOCU to ZSAPMSEDIDOCU
Run the transaction to download the WSDL of the IDOC. If you are using standard IDOC type
then use parameter Basic Type or else if you have IDOC extension use Enhancement to
download the WSDL.
Here I am downloading standard basic type ORDERS05
Save the file in your local drive. I have saved the file into my desktop.
Step 2. Create server proxy for the WSDL to host the IDOC
Create a class ZCL_CA_IDOC_SERVICE with 3 methods as below and copy paste the source
code attached below and activate the class.
Now create the server proxy from the WSDL you downloaded in step 1. Go to SE80 and crate a
service
I have used $tmp. Please use your package and transport here.
Activate the service
Go to the implementing class by double clicking, Insert this code and activate the class.
outputtid = zcl_ca_idoc_service=>trigger_idoc( input = input queueid = space ).
Go to SOAMANAGER and create an endpoint for the service.
Now test the service from SOAPUI to post an IDOC into the system
TID 0A6A381E48FE541C4FFF0304 create with IDOC 881704
lr_ixml cl_ixml=>create( ).
=
lr_streamfac lr_ixml->create_stream_factory( ).
=
lr_istream lr_streamfac->create_istream_xstring( string = schema ).
=
lr_document lr_ixml->create_document( ).
=
lr_parser lr_ixml->create_parser( stream_factory = lr_streamfac
=
istream = lr_istream
document = lr_document ).
call method lr_parser->set_namespace_mode( mode =
if_ixml_parser=>co_namespace_aware ).
* whitespace Problem
lr_parser->add_strip_space_element( name = '*' uri = '*' ).
if lr_parser->parse( ) ne 0.
* 018(sprx): "The document description is syntactically incorrect."
message e018(sprx).
endif.
lr_schema = lr_document->get_root_element( ).
cl_proxy_xsd_utils=>check_node( lr_schema ).
lr_definitions = lr_document->create_element_ns(
uri = if_proxy_const_ns=>namespace_wsdl
prefix = 'wsdl' "#EC NOTEXT
name = 'definitions' "#EC NOTEXT
).
add_namespace_decl(
document = lr_document
element = lr_definitions
name = 'wsdl' "#EC NOTEXT
uri = if_proxy_const_ns=>namespace_wsdl
).
lr_types->append_child( lr_schema ).
lr_porttype = lr_document->create_element_ns(
uri = if_proxy_const_ns=>namespace_wsdl
prefix = 'wsdl' "#EC NOTEXT
name = 'portType' "#EC NOTEXT
).
lr_definitions->append_child( lr_porttype ).
lr_porttype->set_attribute(
name = 'name' "#EC NOTEXT
value = short_name( lv_target_ns )
).
lr_children = lr_schema->get_children( ).
lv_index = 0.
lv_no = 0.
lv_count = lr_children->get_length( ).
while lv_index < lv_count.
lr_child = lr_children->get_item( lv_index ).
lv_index = lv_index + 1.
try.
lr_element ?= lr_child.
lv_name = lr_element->get_name( ).
if lv_name = 'element'. "#EC NOTEXT
lv_no = lv_no + 1.
lv_mess_name = lv_no.
concatenate 'message' lv_mess_name into lv_mess_name."#EC NOTEXT
condense lv_mess_name no-gaps.
lr_message = lr_document->create_element_ns(
uri = if_proxy_const_ns=>namespace_wsdl
prefix = 'wsdl' "#EC NOTEXT
name = 'message' "#EC NOTEXT
).
lr_definitions->append_child( lr_message ).
lr_message->set_attribute( name = 'name' value = lv_mess_name )."#EC
NOTEXT
lv_part_name = lv_no.
concatenate 'part' lv_part_name into lv_part_name."#EC NOTEXT
condense lv_part_name no-gaps.
lr_part = lr_document->create_element_ns(
uri = if_proxy_const_ns=>namespace_wsdl
prefix = 'wsdl' "#EC NOTEXT
name = 'part' "#EC NOTEXT
).
lr_message->append_child( lr_part ).
lr_part->set_attribute( name = 'name' value = lv_part_name )."#EC NOTEXT
lr_part->set_attribute( name = 'element' value = lv_typename )."#EC
NOTEXT
lv_op_name = lv_no.
concatenate 'op' lv_op_name into lv_op_name.
condense lv_op_name no-gaps.
lr_operation = lr_document->create_element_ns(
uri = if_proxy_const_ns=>namespace_wsdl
prefix = 'wsdl' "#EC NOTEXT
name = 'operation' "#EC NOTEXT
).
lr_porttype->append_child( lr_operation ).
lr_operation->set_attribute( name = 'name' value = lv_op_name )."#EC
NOTEXT
lr_inout = lr_document->create_element_ns(
uri = if_proxy_const_ns=>namespace_wsdl
prefix = 'wsdl' "#EC NOTEXT
name = 'output' "#EC NOTEXT
).
lr_operation->append_child( lr_inout ).
lr_inout->set_attribute( name = 'message' value = lv_mess_name )."#EC
NOTEXT
endif.
endmethod.
METHOD GET_WSDL.
DATA: xml_as_string TYPE xstring,
wsdl TYPE xstring,
cwsdl2 TYPE string.
ENDIF.
TRY.
CALL METHOD zcl_proxy_utils=>xsd2wsdl
EXPORTING
schema = wsdl
RECEIVING
wsdl = wsdl.
CATCH cx_proxy_gen_error .
ENDTRY.
* IF idoctyp IS INITIAL.
* idoctyp = mestyp.
* ENDIF.
CLEAR lv_res.
CONCATENATE
'<wsdl:definitions name="' idoctyp '" targetNamespace="http://SAPIdocServices.com"
xmlns:tns="http://SAPIdocServices.com" '
'xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" '
'xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">'
'<wsp:UsingPolicy wsdl:required="true" />'
'<wsp:Policy wsu:Id="OP_' idoctyp '" />' INTO lv_res RESPECTING BLANKS.
CLEAR seddocustr-idoctdescr.
CLEAR seddocustr-cimdescrp.
CLEAR seddocustr-segdescrp.
IF seddocustr-idoctyp NE space.
* basic type selected
* existence check
CALL FUNCTION 'IDOCTYPE_EXISTENCE_CHECK'
EXPORTING
pi_idoctyp = seddocustr-idoctyp
pi_read_devc = ' '
IMPORTING
pe_attributes = l_attributes
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0 AND
g_init_flag EQ 'X' AND
okcode_100 NE 'TYPSEL' AND
seddocustr-bassel NE space.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* set description
seddocustr-idoctdescr = l_attributes-descrp.
ENDIF.
IF seddocustr-cimtyp NE space.
* extension selected
* existence check
CLEAR l_attributes.
CALL FUNCTION 'EXTTYPE_EXISTENCE_CHECK'
EXPORTING
pi_cimtyp = seddocustr-cimtyp
pi_read_devc = ' '
IMPORTING
pe_attributes = l_attributes
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0 AND g_init_flag EQ 'X'
AND okcode_100 NE 'TYPSEL'
AND seddocustr-cimsel NE space.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* set description
seddocustr-cimdescrp = l_attributes-descrp.
ENDIF.
IF seddocustr-segtyp NE space.
* segment is selected
l_seghead-segtyp = seddocustr-segtyp.
CALL FUNCTION 'SEGMENT_READ'
EXPORTING
segmenttyp = l_seghead-segtyp
IMPORTING
segmentheader = l_seghead
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0 AND g_init_flag EQ 'X'
AND okcode_100 NE 'TYPSEL'
AND seddocustr-segsel NE space.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* set description
seddocustr-segdescrp = l_seghead-descrp.
ENDIF.
ENDFORM. " check_and_set_descrp
*&---------------------------------------------------------------------*
*& Form read_version_descrp
*&---------------------------------------------------------------------*
FORM read_version_descrp.
CALL FUNCTION 'DDIF_DOMA_GET'
EXPORTING
name = 'EDI_VERSIO'
langu = sy-langu
TABLES
dd07v_tab = gt_version_descrp.
** exceptions
** illegal_input = 1
** others = 2.
* ignore exceptions
LOOP AT gt_version_descrp WHERE domvalue_l EQ seddocustr-version.
seddocustr-verdescrp = gt_version_descrp-ddtext.
EXIT.
ENDLOOP.
ENDFORM. " read_version_descrp
*&---------------------------------------------------------------------*
*& Form start_html_docu
*&---------------------------------------------------------------------*
FORM start_html_docu.
DATA: l_type TYPE char1,
l_segment TYPE edilsegtyp,
l_object TYPE edi_docobj.
* check selection
IF l_object IS INITIAL AND
seddocustr-segsel IS INITIAL AND
seddocustr-controlrec IS INITIAL AND
seddocustr-datarec IS INITIAL AND
seddocustr-statusrec IS INITIAL.
MESSAGE s346.
EXIT.
ENDIF.
FORM start_user_settings.
CALL FUNCTION 'IDOC_MAINTAIN_USER'
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM. " start_user_settings
*&---------------------------------------------------------------------*
*& Form check_unicode
*&---------------------------------------------------------------------*
IF seddocustr-version = '3'
AND save_okcode100 = 'SCHEMA'.
CLEAR unicode_flag.
CALL FUNCTION 'POPUP_TO_CONFIRM_STEP'
EXPORTING
defaultoption = 'Y'
textline1 = text-106
titel = syst-title
cancel_display = space
IMPORTING
answer = l_answer.
IF l_answer = 'J'.
MOVE 'X' TO unicode_flag.
ENDIF.
ENDIF.
ENDFORM. " check_unicode
*&---------------------------------------------------------------------*
*& Form start_cheader_docu
*&---------------------------------------------------------------------*
FORM start_cheader_docu.
DATA: l_type TYPE char1,
l_object TYPE edi_docobj.
* check selection
IF l_object IS INITIAL AND
seddocustr-controlrec IS INITIAL AND
seddocustr-datarec IS INITIAL AND
seddocustr-statusrec IS INITIAL.
MESSAGE s346.
EXIT.
ENDIF.
* generate c-header-declarations
REFRESH gt_formated_docu.
CALL FUNCTION 'IDOC_TYPE_GENERATE_C_HEADER'
EXPORTING
release = g_released
applrel = gd_applrel
struct_type = l_type
idoctype = l_object
with_control_record = seddocustr-controlrec
with_data_record = seddocustr-datarec
with_status_record = seddocustr-statusrec
version = seddocustr-version
TABLES
text = gt_formated_docu
EXCEPTIONS
definition_read_error = 1
format_error = 2
OTHERS = 3.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* check selection
IF NOT seddocustr-segsel IS INITIAL.
MESSAGE s345.
EXIT.
ELSEIF NOT seddocustr-bassel IS INITIAL AND
seddocustr-idoctyp IS INITIAL .
MESSAGE s653(e0).
EXIT.
ELSEIF NOT seddocustr-cimsel IS INITIAL AND
seddocustr-cimtyp IS INITIAL.
MESSAGE s653(e0).
EXIT.
ENDIF.
* generate dtd-definition
REFRESH gt_formated_docu.
CALL FUNCTION 'IDOC_TYPE_DTD_TABLE'
EXPORTING
pi_idoctype = l_idoctyp
pi_cimtype = l_cimtyp
pi_dtd_type = 'E'
unicode_format = conv_version
TABLES
pt_dtd = gt_formated_docu
EXCEPTIONS
OTHERS = 1.
IF sy-subrc NE 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* check selection
IF l_object IS INITIAL AND
seddocustr-controlrec IS INITIAL AND
seddocustr-datarec IS INITIAL AND
seddocustr-statusrec IS INITIAL.
MESSAGE s346.
EXIT.
ENDIF.
* check selection
IF l_object IS INITIAL AND
seddocustr-controlrec IS INITIAL AND
seddocustr-datarec IS INITIAL AND
seddocustr-statusrec IS INITIAL.
MESSAGE s346.
EXIT.
ENDIF.
* generate c-header-declarations
REFRESH gt_formated_docu.
CALL FUNCTION 'EDI_IDOC_PARSER'
EXPORTING
object = l_object
object_type = l_type
object_release = g_released
object_applrel = gd_applrel
version = seddocustr-version
with_control_record = seddocustr-controlrec
with_data_record = seddocustr-datarec
with_status_record = seddocustr-statusrec
IMPORTING
parser_docu = gt_formated_docu
EXCEPTIONS
definition_read_error = 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.
FIELD-SYMBOLS:
<element> TYPE REF TO if_ixml_element.
IF seddocustr-bassel = 'X'.
IF NOT seddocustr-idoctyp IS INITIAL.
idoctyp = seddocustr-idoctyp.
control-is_cim = ' '.
CALL FUNCTION 'SDIXML_IDOC_TO_SCHEMA'
EXPORTING
mestyp = mestyp
idoctyp = idoctyp
control = control
IMPORTING
elements = elements
CHANGING
idocdescr = idoctypdescr
document = document
EXCEPTIONS
idoc_not_exists = 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.
EXIT.
ENDIF.
ELSE.
MESSAGE s346(ea).
EXIT.
ENDIF.
ELSEIF seddocustr-cimsel = 'X'.
IF NOT seddocustr-cimtyp IS INITIAL.
idoctyp = seddocustr-cimtyp.
control-is_cim = 'X'.
CALL FUNCTION 'SDIXML_IDOC_TO_SCHEMA'
EXPORTING
mestyp = mestyp
idoctyp = idoctyp
control = control
IMPORTING
elements = elements
CHANGING
idocdescr = idoctypdescr
document = document
EXCEPTIONS
idoc_not_exists = 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.
EXIT.
ENDIF.
ELSE.
MESSAGE s346(ea).
EXIT.
ENDIF.
ELSE. " es mu eins der beiden ausgewhlt worden sein
ENDIF.
METHOD trigger_idoc.
DATA: ls_edidc_40 TYPE edi_dc40,
lt_edidc_40 TYPE TABLE OF edi_dc40,
lt_edidd_40 TYPE TABLE OF edi_dd40.
" Set RFC_DEST from DB table EDIPOA by port or set RFC_DEST directly from
"" HERE
IF queueid IS INITIAL.
CALL FUNCTION 'IDOC_INBOUND_SINGLE'
IN BACKGROUND TASK
AS SEPARATE UNIT
DESTINATION lv_rfc_dest
EXPORTING
pi_idoc_control_rec_40 = ls_edidc_40
pi_do_commit = 'X'
* IMPORTING
* PE_IDOC_NUMBER =
* PE_ERROR_PRIOR_TO_APPLICATION =
TABLES
pt_idoc_data_records_40 = lt_edidd_40
EXCEPTIONS
idoc_not_saved = 1
OTHERS = 2.
IF sy-subrc = 0.
CALL FUNCTION 'ID_OF_BACKGROUNDTASK'
IMPORTING
tid = lv_r3_trans_id
EXCEPTIONS
OTHERS = 0.
tid = lv_r3_trans_id.
ENDIF.
ELSE.
APPEND ls_edidc_40 TO lt_edidc_40.
* set outbound queue
CALL FUNCTION 'TRFC_SET_QUEUE_NAME'
EXPORTING
qname = queueid.
* exceptions not possible because of asynchronous call
CALL FUNCTION 'IDOC_INBOUND_IN_QUEUE'
IN BACKGROUND TASK
AS SEPARATE UNIT
DESTINATION lv_rfc_dest
EXPORTING
qname = queueid
TABLES
idoc_control_rec_40 = lt_edidc_40
idoc_data_queue = lt_edidd_40
EXCEPTIONS
communication_failure = 1
system_failure = 2.
IF sy-subrc <> 0.
ENDIF.
CALL FUNCTION 'ID_OF_BACKGROUNDTASK'
IMPORTING
tid = lv_r3_trans_id
EXCEPTIONS
OTHERS = 0.
tid = lv_r3_trans_id.
ENDIF.
COMMIT WORK.
ENDMETHOD.
METHOD get_ddic_object.
DATA: l_desc TYPE REF TO cl_abap_typedescr.
DATA: l_line TYPE LINE OF dd_x031l_table.
DATA: x030l TYPE x030l,
lv_type TYPE char10.
IF l_desc->kind = 'T'.
x030l = l_desc->get_ddic_header( ).
l_desc = cl_abap_typedescr=>describe_by_name( x030l-refname ).
tdd03 = l_desc->get_ddic_object( ).
refname = x030l-refname.
ELSE.
tdd03 = l_desc->get_ddic_object( ).
SPLIT l_desc->absolute_name AT '=' INTO lv_type refname.
ENDIF.
ENDMETHOD.
METHOD get_idoc_data.
DATA: ls_dd40 TYPE edi_dd40,
ls_dd03 TYPE x031l,
lt_dd03 TYPE dd_x031l_table,
lt_dd03_1 TYPE dd_x031l_table,
p_tabname TYPE tabname.
IF <fs_dd03>-fieldname = 'IDOC'.
ASSIGN COMPONENT 'IDOC' OF STRUCTURE <fs_input> TO <fs_p_segnam>.
ELSEIF <fs_dd03>-fieldname = 'EDI_DC40'.
ASSIGN COMPONENT 'EDI_DC40' OF STRUCTURE <fs_p_segnam> TO <fs_dc40>.
MOVE-CORRESPONDING <fs_dc40> TO edi_dc40.
ELSEIF <fs_dd03>-dtyp = 'STR2'.
ls_dd40-segnam = <fs_dd03>-fieldname.
lv_data = <fs_dd03>-fieldname.
ASSIGN COMPONENT lv_data OF STRUCTURE <fs_p_segnam> TO <fs_segnam>.
IF sy-subrc = 0 AND <fs_segnam> IS ASSIGNED.
ASSIGN <fs_segnam> TO <fs_segnam2>.
CREATE DATA lv_segnam TYPE (<fs_dd03>-fieldname).
ASSIGN lv_segnam->* TO <fs_segnam1>.
MOVE-CORRESPONDING <fs_segnam> TO <fs_segnam1>.
IF <fs_segnam1> IS ASSIGNED AND <fs_segnam> IS NOT INITIAL.
ls_dd40-sdata = <fs_segnam1>.
APPEND ls_dd40 TO edi_dd40.
ENDIF.
ENDIF.
IF ls_dd03-dtyp = 'TTAB'.
ls_dd40-segnam = ls_dd03-fieldname.
ASSIGN COMPONENT ls_dd03-fieldname OF STRUCTURE <fs_segnam2> TO
<fs_segnam_t>.
IF sy-subrc = 0 AND <fs_segnam_t> IS ASSIGNED.
CREATE DATA lt_segnam_t TYPE TABLE OF (ls_dd03-fieldname).
CREATE DATA lv_segnam TYPE (ls_dd03-fieldname).
ASSIGN lv_segnam->* TO <fs_segnam1>.
ASSIGN <fs_segnam_t> TO <fs_t_seg>.
* Nested loop is required to process all data
LOOP AT <fs_t_seg> ASSIGNING <fs_s_seg>.
MOVE-CORRESPONDING <fs_s_seg> TO <fs_segnam1>.
IF <fs_segnam1> IS ASSIGNED AND <fs_s_seg> IS NOT INITIAL.
ls_dd40-sdata = <fs_segnam1>.
APPEND ls_dd40 TO edi_dd40.
ENDIF.
ls_dd40-segnam = <fs_dd03>-fieldname.
ASSIGN COMPONENT <fs_dd03>-fieldname OF STRUCTURE <fs_p_segnam> TO
<fs_segnam_t>.
IF sy-subrc = 0 AND <fs_segnam_t> IS ASSIGNED.
CREATE DATA lt_segnam_t TYPE TABLE OF (<fs_dd03>-fieldname).
CREATE DATA lv_segnam TYPE (<fs_dd03>-fieldname).
ASSIGN lv_segnam->* TO <fs_segnam1>.