Post-Sale FAQs
Composing XML
- Is there a way to return the exact XML sent in the request as the response?
- When I compose an XML message, if there is a & in the text anywhere, do I have to scan the text and convert it before I call the RXS_updVar?
- While composing the XML stream, one section is not being written out. I can see in debug that the RPG logic that is supposed to write this section is not being bypassed and all the rest of the sections are being written fine. What could be wrong?
- None of my sections are being written out when I try to compose the XML stream. I keep getting a Section not found error.
- I'm composing an XML document with RPG-XML Suite and placing it in the IFS. My problem is that I don't seem to be able to read the composed document with my PC applications.
- I keep getting large job logs that identify issues with a module called LOGFN and a procedure called LOG_OUT and the message: "Section CUSTOMNAME not found"
- Why would I need to encode an XML transaction? and how would I do that?
- How do I get around the RPG 65K limit when offering a webservice?
-
//*******************************************************************************
// @Desc: The purpose of this program is to show how to offer a webservice using// IFS files (to eliminate the problem of the 65K limit for RPG
// variables). This is a very simple example and has no real business
// logic. It simply parses the incoming XML and stores it in a data
// structure. The outgoing response sends the same values back to
// the requester along with a unique id.
//*******************************************************************************
// Example XML that is being received into this program via HTTP POST and then//parsed for its contents.
//
//<PostAdr residential="true">
// <name title="Mr.">
// <first>Aaron</first>
// <last>Bartell</last>
// </name>
// <street>123 Center Rd</street>
// <cty>Mankato</cty>
// <state>MN</state>
// <zip>56001</zip>
// <phone>123-123-1234</phone>
// <phone>321-321-4321</phone>
//</PostAdr>
H dftactgrp(*no) bnddir('RXSBND')
D PA ds
D uid 15 0
D rsdtl 1
D ttl 5
D fnam 20
D lnam 20
D strt 15
D cty 30
D stt 2
D zip 5
D phn1 12
D phn2 12
/copy rxs,RXSCp
D allHandler pr
D pType value like(RXS_Type)
D pXPath value like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
D errHandler pr
D pCurLine 10i 0 value
D pCurCol 10i 0 value
D pErrStr 1024a value varying
D gPhnCnt s 10i 0 inz(0)
D gError ds likeds(RXS_Error) inz
D gSndHdr s n
D gUId s 3a
D gReqFile s like(RXS_FilePath)
D gRspFile s like(RXS_FilePath)
/free
monitor;
clear gError;
reset gPhnCnt;
gSndHdr = *on;
gUId = RXS_nextUnqChar();
// File names created with below RXS_cmpTransFile
// /www/myrxs/trans/999_req_.xml (where 999 is a unique number)
// /www/myrxs/trans/999_rsp_.xml (where 999 is a unique number)
gReqFile = RXS_cmpTransFile('_': '.xml': gUId: 'RXS3B_req');
gRspFile = RXS_cmpTransFile('_': '.xml': gUId: 'RXS3B_rsp');
RXS_readToFile(gReqFile);
exsr parse;
exsr compose;
RXS_outFromFile(gRspFile);
on-error;
gError = RXS_catchError();
RXS_stdOutError('error': gError: gSndHdr);
endmon;
*inlr = *on;
//------------------------------------------------------------------------------
begsr parse;
RXS_allElemBeginHandler(%paddr(allHandler));
RXS_allElemContentHandler(%paddr(allHandler));
RXS_allAttrHandler(%paddr(allHandler));
RXS_parse(gReqFile: RXS_STMF: %paddr(errHandler));
endsr;
//------------------------------------------------------------------------------
begsr compose;
RXS_initTplEng(RXS_STMF: gRspFile: *omit: *omit: *omit: *off);
RXS_loadTpl('rxs3b.tpl');
RXS_wrtSection('HTTP_HEAD');
RXS_wrtSection('PostAdrResp_beg');
RXS_updVar('residential': RSDTL);
RXS_updVar('uid': gUID);
RXS_updVar('title': TTL);
RXS_updVar('first': FNAM);
RXS_updVar('last': LNAM);
RXS_updVar('street': STRT);
RXS_updVar('cty': CTY);
RXS_updVar('state': STT);
RXS_updVar('zip': ZIP);
RXS_wrtSection('PostAdr_begin');
RXS_updVar('phone': PHN1);
RXS_wrtSection('phone');
RXS_updVar('phone': PHN2);
RXS_wrtSection('phone');
RXS_wrtSection('PostAdr_end');
RXS_wrtSection('PostAdrResp_end': *on);
endsr;
/end-free
//-------------------------------------------------------------------------------
// @Desc: This local sub procedure will be called for each element content and// attribute event that occurs during the parsing of the PostAdr document.
// Based on the event this sub procedure is being notified of it will
// place the value in the appropriate PF field.
// @Notes: There are four events that your program can be notified of through the
// allHandler sub procedure and they are passed in the pEvntType parm.
// An event is triggered as the parser reads the document top down,
// left to right (same way you read the newspaper). Note that you will
// only be notified of events you specified before the call to
// RXS_parse by using API's RXS_allElemBegHandler,
// RXS_allElemEndHandler, RXS_allElemContentHandler, and
// RXS_allAttrHandler.
//
// The four events and their values (note that these can all be overidden
// by changing the RXSCFG file or by doing a temporary override on the
// RXS_parse command)
//
// Element Begin = '>' -- Placed at end of string (i.e. '/elem>')
// Element Content = '/' -- Placed at end of string (i.e. '/elem/')
// Element End = '/>' -- Placed at end of string (i.e. '/elem/>')
// Attribute = '@' -- Placed between the elem and attr// (i.e.'/elem@attr')
//
// The most common events you will use are Element Content and Attribute// simply because these are the two that provide business data via the
// pData parm on the allHandler procedure interface. Events Element Begin// and Element End are very helpful when you have repeating XML data. You
// can then use the Begin and End events to do a CLEAR and WRITE to a PF
// record respectively. Remember that in-between the Element Begin and
// Element End events you will be notified of all the element content,
// which means that after the CLEAR (i.e. Element Begin event) you can
// place data into the PF record until you reach the Element End event
// at which time you can do a WRITE of that record because it has now
// been populated with data.
//-------------------------------------------------------------------------------
P allHandler b
D allHandler pi
D pType value like(RXS_Type)
D pXPath value like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
/free
select;
when pXPath = '/PostAdr@residential';
if pData = 'true';
RSDTL = 'T';
else;
RSDTL = 'F';
endif;
when pXPath = '/PostAdr/name@title';
TTL = pData;
when pXPath = '/PostAdr/name/first/';
FNAM = pData;
when pXPath = '/PostAdr/name/last/';
LNAM = pData;
when pXPath = '/PostAdr/street/';
STRT = pData;
when pXPath = '/PostAdr/cty/';
CTY = pData;
when pXPath = '/PostAdr/state/';
STT = pData;
when pXPath = '/PostAdr/zip/';
ZIP = pData;
when pXPath = '/PostAdr/phone/';
gPhnCnt = gPhnCnt + 1;
select;
when gPhnCnt = 1;
PHN1 = pData;
when gPhnCnt = 2;
PHN2 = pData;
endsl;
endsl;
/end-free
P e
//-------------------------------------------------------------------------------
// @Desc: If an error occurs this local sub procedure will be called by the// parser.
//-------------------------------------------------------------------------------
P errHandler B
D errHandler PI
D pCurLine 10i 0 value
D pCurCol 10i 0 value
D pErrStr 1024a value varying
/free
gError.code = 'RXS3B.1';
gError.severity = 100;
gError.pgm = 'RXS3B.errHandler';
gError.text =
'Line:' + %char(pCurLine) +
' Column:' + %char(pCurCol) +
' ' + pErrStr;
/end-free
P E - How do I get around the RPG 65K limit when consuming a webservice?
Yes, If you have a DB2 field that might contain any of the
special characters used in XML, that field's value will either have to be
placed in a CDATA tag or be modified to use the appropriate escape characters
before being passed to the RXS_updVar API. For example, if a name field had a
possible value of "Jackson & Jackson" that field would need to be modified
(or a work field used) to be "Jackson & Jackson". The same would hold
true for any of the following characters, if they were potentially part of the
field data; <,>, ", '. RXS_soapDecode can be used to accomplish this, see
user manual for details. The potential values you may need to replace, and
their respective new values are:
& - &
< - <
> - >
" - "e;
' - '
When doing the replacement, don't forget the semi-colon on the end of the
replacement value.
It should be noted that the CDATA tag simplifies the generated XML a bit. You
would still need to scan for the special characters, but when found you could
embed the entire field value into the CDATA tag. For the above example, the
value that would be passed to the RXS_updVar API would be <![CDATA[Ben & Jerry]]>. Remember, CDATA can only be
used with element values, attributes would need to use replacement values.
RXS_updVar('templatefield' :
'<![CDATA[Ben & Jerry]]>');
or
workfield = '<![CDATA[' +
%trim(NameField) + ']]>';
RXS_updVar('templatefield' :
workfield);
If you have a large number of records that you know will have one of the
special characters in a specific field, it is of course not necessary to scan
the field each time. You could just convert the field value every time (or use
the CDATA tag). This is a decision you will have to make taking performance and
the ultimate size of your XML document into consideration.
A technique we have used in the past when confronted with this situation is to
"overload" the RXS_updVar() API. This
essentially requires you to create a local procedure in your program that is
named RXS_updVar. Inside this sub-procedure you place your character
replacement logic and allias the RPG-XML Suite API for RXS_updVar()
to a different name. After you have your variable value converted, you then
call the aliased API. Sound confusing? See the code below for a sample program
that uses this logic.
H
dftactgrp(*no) bnddir('RXSBND')
/copy rxs,RXSCp
D
gError ds likeds(RXS_Error) inz
D
I s 10i 0
D
gXML s like(RXS_XMLData)
/free
monitor;
RXS_initTplEng(RXS_VAR: *omit: *omit: *omit: *omit: *on);
RXS_loadTpl('tpleng1.tpl');
RXS_updVar('residential': 'true');
RXS_updVar('title': 'Mr"".');
RXS_updVar('first': 'Aaron & Aaron');
RXS_updVar('last': 'Bartell');
RXS_updVar('street': '123 Center Rd<>');
RXS_updVar('cty': 'Mankato');
RXS_updVar('state':
'MN');
RXS_updVar('zip': '56001');
RXS_wrtSection('PostAdr_begin');
for i = 1 to 3 by 1;
RXS_updVar('phone': '123-123-123' + %char(i));
RXS_wrtSection('phone');
endfor;
RXS_wrtSection('PostAdr_end');
gXML = RXS_getBuffData(*on); // *on=flush the buffer
on-error;
gError = RXS_catchError();
endmon;
*inlr = *on;
/end-free
//----------------------------------------------------------------------------------
//
@Desc: This is an "over loaded" (Java term) version of the RXS_updVar
API. This
// will need to be included in each program that wishes to make use of the
// "translating" capabilities.
//----------------------------------------------------------------------------------
P RXS_updVar b
D RXS_updVar pi
D pName 30a const varying
D pValue 65535a const varying
D pTrim n value options(*nopass)
D RXS_updVar2 pr extproc('RXS_UPDVAR')
D pName 30a const varying
D pValue 65535a const varying
D pTrim n value options(*nopass)
D tmpStr s 65535a varying
D from s 10a dim(10) varying
D to s 10a dim(10) varying
/free
tmpStr = pValue;
to(1) = '&';
from(1) = '&';
to(2) = '<';
from(2) = '<';
to(3) = '>';
from(3) = '>';
to(4) = '"';
from(4) = '"';
to(5) = ''';
from(5) = '''';
RXS_soapDecode(tmpStr: RXS_VAR:
from: to);
if %parms > 2;
RXS_updVar2(pName: tmpStr:
pTrim);
else;
RXS_updVar2(pName: tmpStr);
endif;
/end-free
P e
EDTF STMF('/www/myrxs/templates/rxs3.tpl')
If you are using WDSC to update the file, after bringing the template file up for update, left click somewhere on the CUSTOMNAME section line to the right of the section name. If the cursor is not flush with the end of the section name, you have trailing spaces. Simply backspace until the cursor is flush with the end of the section name, save the file, and try again.
It
sounds like your RXSCFG file is not populated. This is a one-record file that
contains information pertinent to template location and configuration and is
populated as part of the installation procedure (CALL RXS/INSTALL PARM('RXS' '8181' 'MYRXS'). The default values for this file
are shown in the screen shot below:
This
is most often an issue with the CCSID that is being used to translate your
document to the IFS. Try changing your RXS_initTplEng to specify CCSID 819
(ISO-8859-1). This will solve this problem most of the time.
RXS_initTplEng(RXS_STMF: gReqFile: 819: *omit: *omit:
*on);
EDTF '/www/myrxs/templates/yourtemplatename.tpl'
Then move your cursor to be immediately after your CUSTOMNAME section and hold down the delete key for 10 seconds (you can't visually see the spaces being deleted, but they are in fact being deleted). Then, to save the file, press F3 twice. Note that the custom section name is preceded with double colons (or, for RPG-XML Suite version 1.3 or earlier, slash dollar '/$')
If you are using WDSC to update the file, the process is less confusing. After bringing the template file up for update, merely left click somewhere on the CUSTOMNAME section line to the right of the section name. You have trailing spaces if the cursor is not flush with the end of the section name. Simply backspace until the cursor is flush with the end of the section name, save the file, and try again.
Sometimes the WSDL for the webservice you are trying
to consume will incorrectly indicate that the XML you are sending is actually
an element value, perhaps because the WSDL is incomplete. When this happens the
remote webservice will *think* that your XML string is actually an element
value and attempt to validate it as such. If it finds any additional element
tags or special XML characters which are not encoded, the validation will fail.
For example let's say your XML stream looks like this:
<workflowName><element1>xyz</element1></workflowName>
and that the following declaration is in the XSD portion of the WSDL:
<element
name="workflowName" type="xsd:string"/>
This declaration says nothing about the child element (element1) and is only
expecting the 'value' for workflowName.
The validator at the remote service you are trying to consume would be looking
for data to follow the begin-element tag for workflowName. Instead it finds
another begin-element tag (for element1) that the WSDL knows nothing about. The
validation process would fail as soon as the validator encountered the
"unknown" begin-element tag for element1. This does not mean that the
actual webservice would not process the stream correctly. The validator is many
times part of a seperate process that occurs prior to the webservice actually
processing your XML. (Think of it as an validation
routine.)
To pass the validator you need to do one of two things.
1.
Use a CDATA tag to encompass
everything within workflowName or
2.
Encode everything within
workflowName
That takes care of why you may need to use encoding. Now how do we do it? One
method of doing that is to use the CDATA tags as mentioned above, since the
parser (and hence the validator) ignores everything within the CDATA tag. The
other approach is to translate all reserved characters (i.e. < becomes
< )
With that said we *should* be able to use CDATA, but we may have to escape a
few more things. These 3 examples are equivalent. One of them should work.
1.
<workflowName><![CDATA[<element1>xyz</element1>]]></workflowName>
2.
<workflowName><![CDATA[<element1>xyz</element1>]]></workflowName>
·
In the above the <, >,
[, ], and ! characters have
been translated/escaped for the CDATA tag itself.
3.
<workflowName><element1>xyz</element1></workflowName>
·
In the above we abandoned
the CDATA tag entirely and encoded the whole string within workflowName
! = !
[ = [
] = ]
< = < = <
> = > = >
" = " =
"
' = ' = '
& = & = &
If you go the encoding route you will probably want to use the RXS_soapDecode
API. This is very well explained in the RPG-XML Suite User Manual that can be
found on both our Support and Download pages. While the name implies decoding
SOAP transactions, it can also be used to encode either a data field or a full
IFS document.
You can avoid the issue of the 65K limit by using IFS files to hold your XML streams. Below is an example of a very simple web service (using a modified version of RXS3 from our sample programs) as a basis. The lines pertaining to using IFS files to store the XML have been highlighted. Both the incoming request and the outgoing response are stored in IFS files in the default trans directory.
You
can avoid the issue of the 65K limit by using IFS files to hold your XML
stream. Below is an example of a program that sends a request to a remote
webservice and uses IFS files to hold the request and the corresponding
response. The lines pertaining to using IFS files to store and send the XML
have been highlighted.
//*******************************************************************************
// @Desc: Compose a simple xml
stream for a non-SOAP web service transaction. It
// will call web service http://192.168.0.11:8181/myrxs/rxs3 which is
// included in the base install of the RPG-XML Suite. Note the IP address
// will need to be changed to that of the machine where RPG-XML Suite was
// installed.
// @Notes: This program uses IFS
files for the request and response.
//*******************************************************************************
H dftactgrp(*no) bnddir('RXSBND')
/copy rxs,RXSCp
D compose pr
D transmit pr
D parse pr
D allHandler pr
D pType value like(RXS_Type)
D pXPath value like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
D errHandler pr
D pCurLine 10i 0
value
D pCurCol 10i 0
value
D pErrStr 1024a value varying
D gError ds likeds(RXS_Error) inz
// Result of parse
D gPrsData ds qualified inz
D status 10a varying
D msg 256a varying
// Used for RXS_getUri API
D gInCfg ds likeds(RXS_GetUriIn) inz
D gRspHttpHdr s like(RXS_XmlData)
D gUId s 15 0
D gReqFile
s
like(RXS_FilePath)
D
gRspFile
s
like(RXS_FilePath)
/free
reset gError;
reset gPrsData;
// Setup unique file names for IFS
files
// The next 3 lines of code setup
unique file names for the
// IFS files that are going to be
created for the request and
// response. RXS_nextUnqNbr
creates a unique number which
// RXS_cmpTransFile will append to
the end of the file names.
gUID = RXS_nextUnqNbr();
gReqFile
= RXS_cmpTransFile('_': '.xml': 'geturi3a_req': %char(gUID));
gRspFile
= RXS_cmpTransFile('_': '.xml': 'geturi3a_rsp': %char(gUID));
compose();
if gError.code <> *blanks;
return;
endif;
transmit();
if gError.code <> *blanks;
return;
endif;
parse();
RXS_log(RXS_DIAG:
'gPrsData.status=' + gPrsData.status);
RXS_log(RXS_DIAG: 'gPrsData.msg='
+ gPrsData.msg);
*inlr = *on;
/end-free
//-------------------------------------------------------------------------------
P compose b
D compose pi
/free
monitor;
// The next two lines of code
determine which template will be
// used to compose the request.
RXS_initTplEng sets up the
// template engine, the first
parm specifies where the output
// will go (in our case it's a
STMF), the second parm specifies
// the name of the STMF to be
written, and the third parm specifies
// the CCSID used to create the
file. RXS_loadTpl then loads the
// IFS template file to be used
to compose the XML.
RXS_initTplEng(RXS_STMF: gReqFile: 819: *omit:
*omit: *on);
RXS_loadTpl('geturi3.tpl');
RXS_updVar('residential':
'true');
RXS_updVar('title': 'Mr.');
RXS_updVar('first': 'Aaron');
RXS_updVar('last': 'Bartell');
RXS_updVar('street': '123 Center
Rd');
RXS_updVar('cty': 'Mankato');
RXS_updVar('state': 'MN');
RXS_updVar('zip': '56001');
RXS_wrtSection('PostAdr_begin');
RXS_updVar('phone':
'123-123-1234');
RXS_wrtSection('phone');
RXS_updVar('phone':
'321-321-4321');
RXS_wrtSection('phone');
// When writing to IFS files be
sure to specify *on as the second
// PARM on your LAST
RXS_wrtSection instruction. This will clear
// the buffer and guarantee that
all the information gets written
// to the IFS file.
RXS_wrtSection('PostAdr_end':*on);
on-error;
gError = RXS_catchError();
endmon;
/end-free
P e
//-------------------------------------------------------------------------------
P transmit b
D transmit pi
/free
monitor;
// Note the below IP address
needs to be changed to that of the iSeries where
// the RPG-XML Suite was
installed. Also note that if a different value was
// used for the name of the RXS
instance than 'myrxs' that should be specified
// in the below URL.
gInCfg.URI = 'http://192.168.0.11/myrxs/rxs3';
gInCfg.Port = 8181;
// When using IFS files it is
necessary to specify the REQTYPE as well as the
// STMF name (ReqSTMF). By
default RXS assumes you want to use RPG variables
// to store the request and
response XML.
gInCfg.ReqType
= RXS_STMF;
gInCfg.ReqStmf
= gReqFile;
gInCfg.RspType
= RXS_STMF;
gInCfg.RspStmf
= gRspFile;
gInCfg.Debug = RXS_YES;
// When using IFS files the 2nd
& 3rd Parms should be *Omit on the RXS_getURI
// API because we aren't using RPG
variables to hold the XML.
RXS_getUri(gInCfg:
*Omit: *Omit: gRspHttpHdr);
on-error;
gError = RXS_catchError();
endmon;
/end-free
e
//------------------------------------------------------------------------------
P parse b
D parse pi
/free
monitor;
RXS_allElemContentHandler(%paddr(allHandler));
RXS_allAttrHandler(%paddr(allHandler));
// We are receiving our response
file into the IFS and use the API
// RXS_parse to parse that file.
The first parm specifies the
// name of the file in the IFS
that we are parsing, the second parm
// identifies it as a STMF, and
the third parm specifies the name
// of the procedure to be called
in case of a parsing error.
RXS_parse(gRspFile: RXS_STMF: %paddr(errHandler));
on-error;
gError = RXS_catchError();
endmon;
/end-free
e
//-------------------------------------------------------------------------------
// @Desc:
// @Notes: There are four events
that your program can be notified of through
// the allHandler sub procedure and they
are passed in the pEvntType parm. An
// event is triggered as the parser
reads the document top down, left to right
// (same way you read the newspaper).
Note that you will only be notified of
// events you specified before the all to
RXS_parse by using API's
// RXS_allElemBegHandler, RXS_allElemContentHandler,
RXS_allElemEndHandler, and
// RXS_allAttrHandler.
//
// The four events
and their values (note that these can all be overidden
// by changing the RXSCFG file or by doing a
temporary override on the
// RXS_parse command)
//
// Element Begin = '>' -- Placed at end of string (i.e. '/elem>')
// Element Content = '/' -- Placed at end of string (i.e. '/elem/')
// Element End = '/>' -- Placed at end of string (i.e.
'/elem/>')
// Attribute = '@' -- Placed between the elem and
attr
// (i.e.
'/elem@attr')
//
// The most common
events you will use are Element Content and Attribute
// simply because these are the two that provide business data via the
// pData parm on the allHandler procedure interface. Events Element Begin
// and Element End are very helpful when you have repeating XML data. You
// can then use the Begin and End events to do a CLEAR and WRITE to a PF
// record respectively. Remember that in-between the Element Begin and
// Element End events you will be notified of all the element content,
// which means that after the CLEAR (i.e. Element Begin event) you can
// place data into the PF record until you reach the Element End event at
// which time you can do a WRITE of that record because it has now been
// populated with data.
//-------------------------------------------------------------------------------
P allHandler b
D allHandler pi
D pEvntType value like(RXS_Type)
D pXPath value
like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
/free
select;
when pXPath = '/response@status';
gPrsData.status = pData;
when pXPath = '/response/';
gPrsData.msg = pData;
endsl;
/end-free
P e
//-------------------------------------------------------------------------------
P errHandler B
D errHandler PI
D pCurLine 10i 0
value
D pCurCol 10i 0
value
D pErrStr 1024a value varying
/free
gError.code = 'GETURI3001';
gError.severity = 100;
gError.pgm =
'GETURI3A.errHandler';
gError.text =
'Line:' + %char(pCurLine) +
' Column:' + %char(pCurCol) +
' ' + pErrStr;
/end-free
P E
Parsing XML
- I'm trying to build a rpg parse subprocedure and am getting the following error when I test it with the Web Service Tester tool: <error code="RXS3.1 pgm="RXS3.errhandler" severity= "100">line:1 column:0 no element found</error>
- I'm having trouble parsing an XML document. There are no special XML characters (i.e. &, <, >, ', "), but the document does contain some values that are foreign language characters such as Ü and à.
- I am trying to use BLDPRS and keep getting these errors. Creation of source file unsuccessful:Line:1 Column:4 not well-formed (invalid token)
- How do you normally handle HTTP responses that are errors?
- How do I get around the RPG 65K limit when offering a webservice?
- How do I get around the RPG 65K limit when consuming a webservice?
Some
of the Example programs require an incoming XML stream in order to be executed.
These programs will need to be tested using the Web Service Tester that is
provided in the initial download. The required XML stream for these programs
can be found in the examples.txt file that is in the zip file you used to
download RPG-XML Suite. This text should be copied and then pasted into the
Request box of the Web Service Tester (as shown below) prior to hitting the
<Get It> button.
It should be noted that the error "line:1 column:0 no element found"
can be found during normal processing and is not specific to using the Web
Service Tester. In most cases it is related to a missing XML stream or when the
XML has leading blanks and does not start in position 1 of row 1.
By default the parser will look at the first few
characters of the file to attempt to determine what encoding should be used. By
default, and more often than not, UTF-8 is used. That can cause problems if the
data was actually obtained using CCSID 819 (i.e. encoding ISO88591). If you are
having trouble parsing characters like Ü then your data is probably being
returned as ISO88591 vs. UTF-8 (as many XML declarations incorrectly state). To
correct this problem, do a RXS_setParseEnc just prior
to your RXS_parse as shown below.
RXS_setParseEnc(RXS_ISO88591);
RXS_parse(gRspData: RXS_VAR: %paddr(errHandler));
Make
sure that the XML in the document you are converting starts in postion 1, line
1. The XML has to start in the first position of the file to be converted
properly.
Also make sure that your XML file was created using CCSID 819. Files created
with a different CCSID may not convert properly. To see what the CCSID is for
an IFS file from a green screen use the WRKLNK command to bring up the file:
wrklnk
('/www/myrxs/templates/rxs3.tpl')
To create a new IFS file with the correct CCSID
just enter the following command (with the correct path and filename):
QSH CMD('touch
-C 819 /www/myrxs/templates/newfile.tpl')
This is invoking th QShell environment and calling the touch command. The touch
command will simply create the file if it doesn't yet exist. The value "-C
819" is specifying what CCSID should be used to create the file. To learn
more about the syntax of touch please refer to the following URL:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/rzahz/touch.htm
/free
RXS_geturi(… : … : … : rspHttpHdr);
if %scan('200 OK': rspHttpHdr) > 0;
//Success
else;
//Failed, log error in appropriate location
endif;
/end-free
You can avoid the issue of the 65K limit by using IFS files to hold your XML streams. Below is an example of a very simple web service (using a modified version of RXS3 from our sample programs) as a basis. The lines pertaining to using IFS files to store the XML have been highlighted. Both the incoming request and the outgoing response are stored in IFS files in the default trans directory.
//*******************************************************************************
// @Desc: The
purpose of this program is to show how to offer a webservice using
// IFS files (to eliminate
the problem of the 65K limit for RPG
// variables). This is a
very simple example and has no real business
// logic. It simply parses
the incoming XML and stores it in a data
// structure. The outgoing response sends
the same values back to
// the requester along with
a unique id.
//*******************************************************************************
// Example XML that is being received
into this program via HTTP POST and then
//parsed for its
contents.
//
//<PostAdr
residential="true">
// <name title="Mr.">
// <first>Aaron</first>
// <last>Bartell</last>
// </name>
// <street>123 Center Rd</street>
// <cty>Mankato</cty>
// <state>MN</state>
// <zip>56001</zip>
// <phone>123-123-1234</phone>
// <phone>321-321-4321</phone>
//</PostAdr>
H dftactgrp(*no) bnddir('RXSBND')
D PA ds
D uid 15 0
D rsdtl 1
D ttl 5
D fnam 20
D lnam 20
D strt 15
D cty 30
D stt 2
D zip 5
D phn1 12
D phn2 12
/copy rxs,RXSCp
D allHandler pr
D pType value like(RXS_Type)
D pXPath value like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
D errHandler pr
D pCurLine 10i 0
value
D pCurCol 10i 0
value
D pErrStr 1024a value varying
D gPhnCnt s 10i 0 inz(0)
D gError ds likeds(RXS_Error) inz
D gSndHdr s n
D gUId s 3a
D
gReqFile
s
like(RXS_FilePath)
D
gRspFile
s
like(RXS_FilePath)
/free
monitor;
clear gError;
reset gPhnCnt;
gSndHdr = *on;
gUId = RXS_nextUnqChar();
// File names created with below
RXS_cmpTransFile
// /www/myrxs/trans/999_req_.xml (where 999 is a unique number)
//
/www/myrxs/trans/999_rsp_.xml (where 999
is a unique number)
gReqFile
= RXS_cmpTransFile('_': '.xml': gUId: 'RXS3B_req');
gRspFile
= RXS_cmpTransFile('_': '.xml': gUId: 'RXS3B_rsp');
RXS_readToFile(gReqFile);
exsr parse;
exsr compose;
RXS_outFromFile(gRspFile);
on-error;
gError = RXS_catchError();
RXS_stdOutError('error': gError:
gSndHdr);
endmon;
*inlr = *on;
//------------------------------------------------------------------------------
begsr parse;
RXS_allElemBeginHandler(%paddr(allHandler));
RXS_allElemContentHandler(%paddr(allHandler));
RXS_allAttrHandler(%paddr(allHandler));
RXS_parse(gReqFile:
RXS_STMF: %paddr(errHandler));
endsr;
//------------------------------------------------------------------------------
begsr compose;
RXS_initTplEng(RXS_STMF:
gRspFile: *omit: *omit: *omit: *off);
RXS_loadTpl('rxs3b.tpl');
RXS_wrtSection('HTTP_HEAD');
RXS_wrtSection('PostAdrResp_beg');
RXS_updVar('residential': RSDTL);
RXS_updVar('uid': gUID);
RXS_updVar('title': TTL);
RXS_updVar('first': FNAM);
RXS_updVar('last': LNAM);
RXS_updVar('street': STRT);
RXS_updVar('cty': CTY);
RXS_updVar('state': STT);
RXS_updVar('zip': ZIP);
RXS_wrtSection('PostAdr_begin');
RXS_updVar('phone': PHN1);
RXS_wrtSection('phone');
RXS_updVar('phone': PHN2);
RXS_wrtSection('phone');
RXS_wrtSection('PostAdr_end');
RXS_wrtSection('PostAdrResp_end':
*on);
endsr;
/end-free
//-------------------------------------------------------------------------------
// @Desc: This local sub procedure
will be called for each element content and
// attribute event that occurs during the parsing of the PostAdr document.
// Based on the event this sub procedure is being
notified of it will
// place the value in the appropriate PF field.
// @Notes: There are four events that
your program can be notified of through the
// allHandler sub procedure and they are passed in the pEvntType parm.
// An event is triggered as the parser reads the
document top down,
// left to right (same way you read the newspaper). Note that you will
// only be notified of events you specified before the call to
// RXS_parse by using API's RXS_allElemBegHandler,
// RXS_allElemEndHandler, RXS_allElemContentHandler, and
// RXS_allAttrHandler.
//
// The four events and their values (note that these
can all be overidden
// by changing the RXSCFG file or by doing a temporary override on the
// RXS_parse command)
//
// Element Begin = '>' -- Placed at end of string (i.e. '/elem>')
// Element Content = '/' -- Placed at end of string (i.e. '/elem/')
// Element End = '/>' -- Placed at end of string (i.e.
'/elem/>')
// Attribute = '@' -- Placed between the elem and attr
// (i.e.'/elem@attr')
//
// The most
common events you will use are Element Content and Attribute
// simply because these are the two that provide business data via the
// pData parm on the allHandler procedure
interface. Events Element Begin
// and Element End are very helpful when you have repeating XML data. You
// can then use the Begin and End events to do a CLEAR and WRITE to a PF
// record respectively. Remember that in-between the Element Begin and
// Element End events you will be notified of all the element content,
// which means that after the CLEAR (i.e. Element Begin event) you can
// place data into the PF record until you reach the Element End event
// at which time you can do a WRITE of that record because it has now
// been populated with data.
//-------------------------------------------------------------------------------
P allHandler b
D allHandler pi
D pType value like(RXS_Type)
D pXPath value like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
/free
select;
when pXPath =
'/PostAdr@residential';
if pData = 'true';
RSDTL = 'T';
else;
RSDTL = 'F';
endif;
when pXPath = '/PostAdr/name@title';
TTL = pData;
when pXPath =
'/PostAdr/name/first/';
FNAM = pData;
when pXPath =
'/PostAdr/name/last/';
LNAM = pData;
when pXPath = '/PostAdr/street/';
STRT = pData;
when pXPath = '/PostAdr/cty/';
CTY = pData;
when pXPath = '/PostAdr/state/';
STT = pData;
when pXPath = '/PostAdr/zip/';
ZIP = pData;
when pXPath = '/PostAdr/phone/';
gPhnCnt = gPhnCnt + 1;
select;
when gPhnCnt = 1;
PHN1 = pData;
when gPhnCnt = 2;
PHN2 = pData;
endsl;
endsl;
/end-free
P e
//-------------------------------------------------------------------------------
// @Desc: If an error occurs this
local sub procedure will be called by the
// parser.
//-------------------------------------------------------------------------------
P errHandler B
D errHandler PI
D pCurLine 10i 0
value
D pCurCol 10i 0
value
D pErrStr 1024a value varying
/free
gError.code = 'RXS3B.1';
gError.severity = 100;
gError.pgm = 'RXS3B.errHandler';
gError.text =
'Line:' + %char(pCurLine) +
' Column:' + %char(pCurCol) +
' ' + pErrStr;
/end-free
P E
You
can avoid the issue of the 65K limit by using IFS files to hold your XML
stream. Below is an example of a program that sends a request to a remote
webservice and uses IFS files to hold the request and the corresponding
response. The lines pertaining to using IFS files to store and send the XML
have been highlighted.
//*******************************************************************************
// @Desc: Compose a simple xml
stream for a non-SOAP web service transaction. It
// will call web service http://192.168.0.11:8181/myrxs/rxs3 which is
// included in the base install of the RPG-XML Suite. Note the IP address
// will need to be changed to that of the machine where RPG-XML Suite was
// installed.
// @Notes: This program uses IFS
files for the request and response.
//*******************************************************************************
H dftactgrp(*no) bnddir('RXSBND')
/copy rxs,RXSCp
D compose pr
D transmit pr
D parse pr
D allHandler pr
D pType value like(RXS_Type)
D pXPath value like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
D errHandler pr
D pCurLine 10i 0
value
D pCurCol 10i 0
value
D pErrStr 1024a value varying
D gError ds likeds(RXS_Error) inz
// Result of parse
D gPrsData ds qualified inz
D status 10a varying
D msg 256a varying
// Used for RXS_getUri API
D gInCfg ds likeds(RXS_GetUriIn) inz
D gRspHttpHdr s like(RXS_XmlData)
D gUId s 15 0
D gReqFile
s
like(RXS_FilePath)
D
gRspFile
s
like(RXS_FilePath)
/free
reset gError;
reset gPrsData;
// Setup unique file names for IFS
files
// The next 3 lines of code setup
unique file names for the
// IFS files that are going to be
created for the request and
// response. RXS_nextUnqNbr
creates a unique number which
// RXS_cmpTransFile will append to
the end of the file names.
gUID = RXS_nextUnqNbr();
gReqFile
= RXS_cmpTransFile('_': '.xml': 'geturi3a_req': %char(gUID));
gRspFile
= RXS_cmpTransFile('_': '.xml': 'geturi3a_rsp': %char(gUID));
compose();
if gError.code <> *blanks;
return;
endif;
transmit();
if gError.code <> *blanks;
return;
endif;
parse();
RXS_log(RXS_DIAG:
'gPrsData.status=' + gPrsData.status);
RXS_log(RXS_DIAG: 'gPrsData.msg='
+ gPrsData.msg);
*inlr = *on;
/end-free
//-------------------------------------------------------------------------------
P compose b
D compose pi
/free
monitor;
// The next two lines of code
determine which template will be
// used to compose the request.
RXS_initTplEng sets up the
// template engine, the first
parm specifies where the output
// will go (in our case it's a
STMF), the second parm specifies
// the name of the STMF to be
written, and the third parm specifies
// the CCSID used to create the
file. RXS_loadTpl then loads the
// IFS template file to be used
to compose the XML.
RXS_initTplEng(RXS_STMF: gReqFile: 819: *omit:
*omit: *on);
RXS_loadTpl('geturi3.tpl');
RXS_updVar('residential':
'true');
RXS_updVar('title': 'Mr.');
RXS_updVar('first': 'Aaron');
RXS_updVar('last': 'Bartell');
RXS_updVar('street': '123 Center
Rd');
RXS_updVar('cty': 'Mankato');
RXS_updVar('state': 'MN');
RXS_updVar('zip': '56001');
RXS_wrtSection('PostAdr_begin');
RXS_updVar('phone':
'123-123-1234');
RXS_wrtSection('phone');
RXS_updVar('phone':
'321-321-4321');
RXS_wrtSection('phone');
// When writing to IFS files be
sure to specify *on as the second
// PARM on your LAST
RXS_wrtSection instruction. This will clear
// the buffer and guarantee that
all the information gets written
// to the IFS file.
RXS_wrtSection('PostAdr_end':*on);
on-error;
gError = RXS_catchError();
endmon;
/end-free
P e
//-------------------------------------------------------------------------------
P transmit b
D transmit pi
/free
monitor;
// Note the below IP address
needs to be changed to that of the iSeries where
// the RPG-XML Suite was
installed. Also note that if a different value was
// used for the name of the RXS
instance than 'myrxs' that should be specified
// in the below URL.
gInCfg.URI = 'http://192.168.0.11/myrxs/rxs3';
gInCfg.Port = 8181;
// When using IFS files it is
necessary to specify the REQTYPE as well as the
// STMF name (ReqSTMF). By
default RXS assumes you want to use RPG variables
// to store the request and
response XML.
gInCfg.ReqType
= RXS_STMF;
gInCfg.ReqStmf
= gReqFile;
gInCfg.RspType
= RXS_STMF;
gInCfg.RspStmf
= gRspFile;
gInCfg.Debug = RXS_YES;
// When using IFS files the 2nd
& 3rd Parms should be *Omit on the RXS_getURI
// API because we aren't using RPG
variables to hold the XML.
RXS_getUri(gInCfg:
*Omit: *Omit: gRspHttpHdr);
on-error;
gError = RXS_catchError();
endmon;
/end-free
e
//------------------------------------------------------------------------------
P parse b
D parse pi
/free
monitor;
RXS_allElemContentHandler(%paddr(allHandler));
RXS_allAttrHandler(%paddr(allHandler));
// We are receiving our response
file into the IFS and use the API
// RXS_parse to parse that file.
The first parm specifies the
// name of the file in the IFS
that we are parsing, the second parm
// identifies it as a STMF, and
the third parm specifies the name
// of the procedure to be called
in case of a parsing error.
RXS_parse(gRspFile: RXS_STMF: %paddr(errHandler));
on-error;
gError = RXS_catchError();
endmon;
/end-free
e
//-------------------------------------------------------------------------------
// @Desc:
// @Notes: There are four events
that your program can be notified of through
// the allHandler sub procedure and they
are passed in the pEvntType parm. An
// event is triggered as the parser
reads the document top down, left to right
// (same way you read the newspaper).
Note that you will only be notified of
// events you specified before the all to
RXS_parse by using API's
// RXS_allElemBegHandler, RXS_allElemContentHandler,
RXS_allElemEndHandler, and
// RXS_allAttrHandler.
//
// The four events
and their values (note that these can all be overidden
// by changing the RXSCFG file or by doing a
temporary override on the
// RXS_parse command)
//
// Element Begin = '>' -- Placed at end of string (i.e. '/elem>')
// Element Content = '/' -- Placed at end of string (i.e. '/elem/')
// Element End = '/>' -- Placed at end of string (i.e.
'/elem/>')
// Attribute = '@' -- Placed between the elem and
attr
// (i.e.
'/elem@attr')
//
// The most common
events you will use are Element Content and Attribute
// simply because these are the two that provide business data via the
// pData parm on the allHandler procedure interface. Events Element Begin
// and Element End are very helpful when you have repeating XML data. You
// can then use the Begin and End events to do a CLEAR and WRITE to a PF
// record respectively. Remember that in-between the Element Begin and
// Element End events you will be notified of all the element content,
// which means that after the CLEAR (i.e. Element Begin event) you can
// place data into the PF record until you reach the Element End event at
// which time you can do a WRITE of that record because it has now been
// populated with data.
//-------------------------------------------------------------------------------
P allHandler b
D allHandler pi
D pEvntType value like(RXS_Type)
D pXPath value
like(RXS_XPath)
D pData value like(RXS_XmlData)
D pDataLen value like(RXS_Length)
/free
select;
when pXPath = '/response@status';
gPrsData.status = pData;
when pXPath = '/response/';
gPrsData.msg = pData;
endsl;
/end-free
P e
//-------------------------------------------------------------------------------
P errHandler B
D errHandler PI
D pCurLine 10i 0
value
D pCurCol 10i 0
value
D pErrStr 1024a value varying
/free
gError.code = 'GETURI3001';
gError.severity = 100;
gError.pgm =
'GETURI3A.errHandler';
gError.text =
'Line:' + %char(pCurLine) +
' Column:' + %char(pCurCol) +
' ' + pErrStr;
/end-free
P E
Errors
- Why do I get a spool file that contains CPF9897 Diagnostic messages?
- The BLDPRS code generator gives me: "Creation of source file unsuccessful:Line:1 Column:0 no element found"
- I keep getting large job logs that identify issues with a module called LOGFN and a procedure called LOG_OUT and the message: "Section CUSTOMNAME not found"
- How do you normally handle HTTP responses that are errors?
- How do I resolve the following error: "Error performing SSL handshake. There is no error. RC(23) errno()."
- What does an HTTP response of 403 mean:
- I'm trying to build a rpg parse subprocedure and am getting the following error when I test it with the Web Service Tester tool: <error code="RXS3.1 pgm="RXS3.errhandler" severity= "100">line:1 column:0 no element found</error>
The spool file entries occur when the template
engine has logging turned on. Look at the RXS_initTplEng()
API in your code and the last parm is probably set to *ON (i.e. *ON=Logging ON,
*OFF=Logging Off). You will want to change that to *OFF to disable the job log
entries.
RXS_initTplEng(RXS_STDOUT:
*omit: *omit: *omit: *omit: *on) ----> Additional diagnostic messages written to joblog
RXS_initTplEng(RXS_STDOUT: *omit: *omit: *omit: *omit: *off) ----> Additional diagnostic messages NOT written to joblog
EDTF '/www/myrxs/templates/yourtemplatename.tpl'
Then move your cursor to be immediately after your CUSTOMNAME section and hold down the delete key for 10 seconds (you can't visually see the spaces being deleted, but they are in fact being deleted). Then, to save the file, press F3 twice. Note that the custom section name is preceded with double colons (or, for RPG-XML Suite version 1.3 or earlier, slash dollar '/$')
If you are using WDSC to update the file, the process is less confusing. After bringing the template file up for update, merely left click somewhere on the CUSTOMNAME section line to the right of the section name. You have trailing spaces if the cursor is not flush with the end of the section name. Simply backspace until the cursor is flush with the end of the section name, save the file, and try again.
/free
RXS_geturi(… : … : … : rspHttpHdr);
if %scan('200 OK': rspHttpHdr) > 0;
//Success
else;
//Failed, log error in appropriate location
endif;
/end-free
A
HTTP response of 403 basically means you ran into permission issues. Below is a
URL where you can learn more about it if you care too (note it is not AS400
specific):
http://en.wikipedia.org/wiki/HTTP_403
What
you need to do is ensure that any custom folder(s) and IFS files that you are
using for your webservice, have the same authorities
as folder /www/myrxs/. Also make sure that any program objects and library
being used by any custom programs, have the same authorities as the MYRXS
instance.
Some
of the Example programs require an incoming XML stream in order to be executed.
These programs will need to be tested using the Web Service Tester that is
provided in the initial download. The required XML stream for these programs
can be found in the examples.txt file that is in the zip file you used to
download RPG-XML Suite. This text should be copied and then pasted into the
Request box of the Web Service Tester (as shown below) prior to hitting the
<Get It> button.
It should be noted that the error "line:1 column:0 no element found"
can be found during normal processing and is not specific to using the Web
Service Tester. In most cases it is related to a missing XML stream or when the
XML has leading blanks and does not start in position 1 of row 1.
System Requirements
- Does RPG-XML Suite work on V6R1 and/or V5R4?
- Does RPG-XML Suite use any of IBM's "XML Toolkit - 5733XT1" LPP ?
Apache
- How can I tell if the Apache server is running correctly over a certain library?
- We created an Apache server instance to run RPG-XML Suite. I brought the instance down, but traffic still goes from our iSeries to an outside webservice. Is the (Apache server) instance only used for inbound requests? Which job is sending the requests?
You
will want to take a look at the Apache config. You can do this by typing the
following into the command line:
dspf ’/www/myrxs/conf/httpd.conf’
This
is the part of the config (i.e. httpd.conf) that details which library the requests
will be sent to:
ScriptAliasMatch
^/MYRXS/(.*) /qsys.lib/MYRXS.lib/$1.pgm
<Directory
/qsys.lib/MYRXS.lib>
allow from all
order allow,deny
options +ExecCGI
</Directory>
Is
the program you are calling in library MYRXS? If not you can use the RXS_addLibLE
and RXS_rmvLibLE and RXS_libLEExists API’s to
manipulate the library list. Is the program you are calling that is in another
library a SRVPGM? If so then we will need to take different measures because
*SRVPGM objects are attempted to be resolved when the caller program is invoked
so you don’t have a chance to alter your library list. To facillitate this you
need to add a directive to your Apache server configuration. The directive you
need to add is the SetEnv QIBM_CGI_LIBRARY_LIST as shown below. With that in
place, library CUSTOM will be added to the library list while the request is
executing. Take note that the library list will only be modified while the
request is being processed, so if you look at the library list of the job when
a request is not being processed, you will not see the library you added.
<Directory
/qsys.lib/MYRXS.lib>
allow from all
order allow,deny
SetEnv QIBM_CGI_LIBRARY_LIST
"CUSTOM"
options +ExecCGI
</Directory>
Debugging
- How do I find the job that is being used to run the service program so that I can run debug over it?
If you do a WRKACTJOB SBS(QHTTPSVR) you will see something similar to the below jobs. Note the
QZSRCGI job is the one that is servicing requests. If you make a request using
the Web Service Tester and get a server 500 error back then you can do a
WRKSPLF QTMHHTTP to see what error may have occurred. To run debug over the
service program from a green screen, you must first start a service job over
the job running QZSRCGI. See Debug
Web Services from Green Screen on our downloads page for a quick tutorial; or if you
are a WDSC user, see this tutorial Debug
Web Services with WDSC Service Entry Points (also on our downloads page).

Permissions/Security
- What does an HTTP response of 403 mean:
- For HTTP-based requests, what profiles need to have permissions set and to what objects?
- How do I specify HTTP basic auth with RPG-XML Suite and SOAPUI?
A
HTTP response of 403 basically means you ran into permission issues. Below is a
URL where you can learn more about it if you care too (note it is not AS400
specific):
http://en.wikipedia.org/wiki/HTTP_403
What
you need to do is ensure that any custom folder(s) and IFS files that you are
using for your webservice, have the same authorities
as folder /www/myrxs/. Also make sure that any program objects and library
being used by any custom programs, have the same authorities as the MYRXS
instance.
When
the request is coming in via Apache then profile QTMHHTP1 and/or QTMHHTTP is
being used. Profile QTMHHTP1 is the profile used for CGI requests (i.e. when an
RPG program is being called) and QTMHHTTP is more used for other tasks within
Apache (i.e. the log jobs are running under this profile, and if spool files
are created because of a failed CGI job then it will be created with QTMHHTTP
as the owning user). We are actively working on a new feature that allows you
to quickly/easily have a different user be used based on the program that is
called.
So in the end you will need to allow QTMHHTP1 and QTMHHTTP to have permission to the different resources used for your web service. Those resources are libraries (i.e. MYRXS), IFS files (i.e. /www/myrxs/templates/mytemplate.tpl), programs in MYRXS, and any DB tables used by your MYRXS programs, as well as any custom objects (Libraries, IFS folders, DB2 tables) that you may have created that use RPG-XML Suite.
When using RPG-XML Suite, before you make your call
to RXS_getURI you need to populate the BUSR and BPW subfields in the gInCfg
data structure.
gInCfg.BUser = 'username';
gInCfg.BPW = 'password';
RXS_getURI(.....);
SOAPUI has a tab associated with the request for authentication. From the window for the request, select 'Aut' from the lower selection bar:
This will bring up a
window where you can enter the profile and associated password:
You should now be able
to submit your request normally to the secure server.
License Keys / Versions / Upgrading
- How do I handle the following error: "RXSBASE temporary key expired. Contact rpg-xml.com for a permanent key." if I have already applied my permanent license key?
- How do I find out what version of RPG-XML Suite I am currently running?
- I'm upgrading my iSeries from a 520 to a 525. Is there anything I need to do to keep RPG-XML Suite enabled?
- I am upgrading to V6R1. Are there any patches that I need to install for RPG-XML Suite?
To date this has meant two things:
1)
You incorrectly entered the license key.
Solution:
Try to copy-and-paste the license code from the email sent to you from Krengel
Tech.
2)
The profile running the program that checks for the key
doesn’t have authority to the QGPL/RXSBASE object.
Solution:
Please check to make sure that *PUBLIC has *USE authority to the data area
object QGPL/RXSBASE
If your company disallows the use of public
authorities, assign two users: QTMHHTTP and QTMHHTP1 to *USE. This will take care of
requests from remote users attempting to consume your webservice. You will also
need to assign the same authority for any internal user profiles that are using
RPG-XML Suite to send requests. Be sure to include the user profiles of any
batch jobs that use RPG-XML Suite objects. If you have a lot of profiles that
fall into this category you may want to set up a group profile instead.
CALL RXS/VERRXSBASE
Whenever you upgrade
your iSeries you need to do the following:
1.
Install RPG-XML Suite on the
new system
2.
Run the following command
from a command line on both the old and new systems (make sure that library RXS
is in your LIBL):
RXS/DSPMCHINF
You
will get a display that looks like this:
If the displays on both machines show the same information you will not need a
new key. However if any of the information does not match, you need to send us
screen prints of both screens so that we can get a new key issued to you and
have your contract updated accordingly.
If the new machine/partition that the license is being transferred to has a larger processor group than the initial machine/partition, you will need to pay the difference in the license price between the larger processor group and the initial machine/partition licensed. The processor group can be found by running command WRKLICINF.
After you have migrated to V6R1 there is some
maintenance that needs to be performed if you are on V1.41 (or prior) of
RPG-XML Suite:
1) From a command line, execute the following
command:
WRKOBJ OBJ(*ALL/QZHBCGI)
You
should see a screen similar to the following:
2) Make note of all
the RPG-XML Suite libraries (including any of your custom libraries that use
RPG-XML Suite)
3) Delete QZHBCGI in all the RPG-XML Suite libraries. Do not delete the object in QHTTPSVR!!!
4) Copy the QZHBCGI object in QHTTPSVR back into each of the RPG-XML Suite
libraries that you noted in Step 2.
5) You are good to go. No need to recompile any objects.
SOAPUI
- How do I specify HTTP basic auth with RPG-XML Suite and SOAPUI?
- We have created several programs that present SOAP-based webservices and tested them successfully with SoapUI. However the consuming applications appear unable to work with our programs.
When using RPG-XML Suite, before you make your call
to RXS_getURI you need to populate the BUSR and BPW subfields in the gInCfg
data structure.
gInCfg.BUser = 'username';
gInCfg.BPW = 'password';
RXS_getURI(.....);
SOAPUI has a tab associated with the request for
authentication. From the window for the request, select 'Aut' from the lower
selection bar:
This will bring up a
window where you can enter the profile and associated password:
You should now be able to submit your request normally to the secure server.
Other
- Does RPG-XML Suite use any of IBM's "XML Toolkit - 5733XT1" LPP ?
- I've made some changes to my webservice program, but they don't appear to be taking effect.
- We created an Apache server instance to run RPG-XML Suite. I brought the instance down, but traffic still goes from our iSeries to an outside webservice. Is the (Apache server) instance only used for inbound requests? Which job is sending the requests?
- I am setting up mirroring on my iSeries. Are there any special considerations for RPG-XML Suite?
- We have created several programs that present SOAP-based webservices and tested them successfully with SoapUI. However the consuming applications appear unable to work with our programs.
- I'm composing an XML document with RPG-XML Suite and placing it in the IFS. My problem is that I don't seem to be able to read the composed document with my PC applications.
This is most likely a caching issue, where the
server is effectively running off the older version of the program. There are a
couple of ways to handle this issue.
1.
If your changes were made in
a *SRVPGM, you may need to recompile the top level program that is using the
exports.
2.
And to guarantee that the
server cache is cleared you can always stop the web server and restart it. Be
sure to wait until the server instances have fully ended before restarting.
·
ENDTCPSVR SERVER(*HTTP)
HTTPSVR(MYRXS)
· STRTCPSVR SERVER(*HTTP) HTTPSVR(MYRXS)
This
is most often an issue with the CCSID that is being used to translate your
document to the IFS. Try changing your RXS_initTplEng to specify CCSID 819
(ISO-8859-1). This will solve this problem most of the time.
RXS_initTplEng(RXS_STMF: gReqFile: 819: *omit: *omit:
*on);