Wednesday, 13 June 2012

Sending SOAP message as plain XML with java

 

There are many Java implementations for working with web services, but all of them request having some heavy framework (e.g. AXIS).  You need to generate proxy classes figure how to use them and eventually you finish with 20MB program that maybe does something very simple like calling a web  - service that converts money from US dollar to Euro.

So I will show how can you use only Java core classes without any additional libraries and send SOAP message as plain XML text.

//create URL object
URL url = new URL( "http://someurl.com/soap" );
rc
= (HttpURLConnection)url.openConnection();
//you need to check if server expects POST or GET
//but to be honest I never saw web-service expecting GET reqiest

rc.setRequestMethod(
"POST");
rc.setDoOutput(
true );
rc.setDoInput(
true );
//it is very important to specify the content type. Web-service will reject the request if it is
//not XML
rc.setRequestProperty( "Content-Type", "text/xml; charset=utf-8" );
//and here comes some dummy SOAP message
String reqStr = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ord=\"http://someurl.com/OfflineBatchSync/Order\">"+
"<soapenv:Header/>"+
"<soapenv:Body>"+
" <ord:CreateOrderHeader_Input>"+
" <ord:CustomerPO></ord:CustomerPO>"+
" <ord:SubOrderType>VMI</ord:SubOrderType>"+
" <ord:PreSaleFlg></ord:PreSaleFlg>"+
" <ord:DistributorId></ord:DistributorId>"+
" <ord:AccountId>1-6T4N</ord:AccountId>"+
" <ord:OrderStatus></ord:OrderStatus>"+
" <ord:RequestedDate></ord:RequestedDate>"+
" <ord:ShipInstructions></ord:ShipInstructions>"+
" <ord:PriceListId></ord:PriceListId>"+
" </ord:CreateOrderHeader_Input>"+
"</soapenv:Body>"+
"</soapenv:Envelope>";
//several more definitions to request
int len = reqStr.length();
rc.setRequestProperty(
"SOAPAction:", "\"document/http://someurl.com/OfflineBatchSync/Order:CreateOrderHeader\"" );
rc.setRequestProperty(
"Content-Length", Integer.toString( len ) );
rc.setRequestProperty(
"Connection:", "Keep-Alive" );
rc.connect();
//write XML to the server
OutputStreamWriter outStr = new OutputStreamWriter( rc.getOutputStream() );
outStr.write( reqStr,
0, len );
outStr.flush();

/* Here is the important part, if something goes wrong and excetion will
* be thrown and you will have some meaningless exception saying blah.. blahh HTTP 500
* which actually doesn't tell you a lot about what happen.
* However most web-services provide as a response some error page that displays what
* was wrong. It whould be nice to see this page instead of stupid HTTP 500.
* It is not difficult . All you need is actually read not the response stream , but the error stream
*/

try
{
read
= new InputStreamReader( rc.getInputStream() );
}
catch(Exception exception)
{
//if something wrong instead of the output, read the error
read = new InputStreamReader( rc.getErrorStream() );
}

//read server response
StringBuilder sb = new StringBuilder();
int ch = read.read();
while( ch != -1 ){
sb.append((
char)ch);
ch
= read.read();
}
String responseTr
= sb.toString();



Basically this is all you need . After execution of the code above responseTr  variable will hold the response SOAP message in case of success or response error (In case of error it will be HTML script so you may want to display it in browser or to strip HTML tags)

Sunday, 13 May 2012

Accessing remote Oracle DB from Siebel server script and executing insert with bind variables

 

It is very common to be asked to develop an interface between Siebel and other systems. It could be that other system has some kind of API or maybe it doesn’t . In my case , remote system doesn’t has any API, but you can access its database. So how can you do it from Siebel server side script?

First of all lets create  some dummy table that will be used as insert target

create table test_insert (data varchar2)


Now define in some Business Service new server script.

Explanation of the code can be found in the code comments


function Service_PreInvokeMethod (MethodName, Inputs, Outputs) {
if (MethodName=="Connect")
{
//obtain connection object
var oConnection = COMCreateObject("ADODB.Connection");
//connection objects
var cmd;
var myparam;
var res;
var adVarChar =200;
var adParamInput =1;
var adCmdText = 1;

try
{
//here I use TNS style connection string to connect to remote Oracle database
oConnection.ConnectionString
= "Driver={Microsoft ODBC for Oracle}; CONNECTSTRING=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=130.39.120.58)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)));
uid
=system;pwd=manager;";
oConnection.
Open();
//create command object
cmd
= COMCreateObject("ADODB.Command");
//assign connection to command
cmd.ActiveConnection
= oConnection;
//this is SQL statement that I am about to execute
var insertStmt = "INSERT INTO TEST_INSERT (DATA) VALUES (?)";

cmd.CommandText
= insertStmt;
// command type is - text
cmd.CommandType
= adCmdText;
//create and append new parameter
// 1 = first parameter
// adVarChar = database column type
// adParamInput = parameter direction (input)
// 5 - the lenght of the parameter value
// TEST2 - parameter value
cmd.Parameters.Append(cmd.CreateParameter(
1, adVarChar, adParamInput,5,"TEST2"));

// Now, inserting into the data source...
cmd.Prepared
= true;
//execute update - no commit is needed
res
= cmd.Execute();

Outputs.SetProperty("DONE","DONE");


}
catch(e)
{
Outputs.SetProperty("DONE","
NOT OK "+e.toString());
}
finally
{
//release variables
adCmdText
=null;
adParamInput
= null;
adVarChar
= null;
myparam
= null;
cmd
= null;
oConnection
= null;
}
return (CancelOperation);
}
return (ContinueOperation);
}