Prepared for JSR-224 F2F meeting Proposed...
Transcript of Prepared for JSR-224 F2F meeting Proposed...
Copyright © 2004 NTT DATA Corporation
Prepared for JSR-224 F2F meeting
Proposed Architecture for Asynchronous Web Services
in JAX-RPC 2.0
March 11th, 2004
Toshiyuki KIMURAR&D Headquarters
NTT DATA Corporation
2
What's the need for Async Web Services ?
WebWeb ServiceServiceClient impl.Client impl.
Blocks future Blocks future processingprocessing
WebWeb Service Service impl.impl.
ClientClient SOAP ServerSOAP Server
■ Synchronous Web Services by using HTTP
Just 1 HTTP Just 1 HTTP connectionconnection
RequestRequest
ResponseResponse
Unsuitable for long-term processon server-side
Unsuitable for Unsuitable for longlong--term processterm processon serveron server--side
○ Easy to build a service end-point and client.
× Blocking stuff gives us unwelcome eventson both client-side and server-side. side
3
What's the Async Web Services ?
■ Types of Async Web Services
■ Callback type (Push)
■ Polling type (Pull)• “Request” and “Response” are transferred
by over two different HTTP connections.
• The result is picked up by the client with
several times of polling.
• “Request” and “Response” are transferred
by two different HTTP connections.
• The result is pushed back by server-sidewhen the request has been completed.
4
How to implement Async Web Services ?
Polling type of Async Web Services
J2EE PlatformJ2EE Platform
Web containerWeb container
ClientClient SOAP ServerSOAP Server
JMSJMS EJB containerEJB container
DBMS/EIS
J2EE PlatformJ2EE Platform
※※ MDB (MessageMDB (Message--Driven Bean)Driven Bean)
※※ JMS (Java Message Service)JMS (Java Message Service)
※※ SLSB (Stateless Session Bean) SLSB (Stateless Session Bean)
MDBMDB
SLSBSLSB
Queue/
Topic
Queue/
Topic
WebWeb serviceserviceClient impl.Client impl.
JAX-RPCJAXJAX--RPCRPCJAX-RPCJAXJAX--RPCRPC
EndEnd--pointpoint
InvokeInvokeInvoke
Receive IDReceive IDReceive ID
Get resultGet resultGet result
Issue 1: Server load-up
Issue 2: Difficulty of client impl.
Order requestOrder request
Get resultGet result
5
ClientClient SOAP ServerSOAP Server
WebWeb Service impl.Service impl.WebWeb Service client impl.Service client impl.
Web ServiceWeb ServiceWeb Service
Control info DB
AA
BBCC
Order requestOrder request
Get resultGet result
<<asyncWorkflow> asyncWorkflow> <asyncStaticParam><asyncStaticParam>
<firstInteval><firstInteval>36003600</firstInterval></firstInterval> <iterateInterval><iterateInterval>360360</iterateInterval></iterateInterval>
<timeoutInterval><timeoutInterval>100000100000</timeoutInterval></timeoutInterval><maxRetryCount>50</maxRetryCount><maxRetryCount>50</maxRetryCount>
</asyncStaticParam></asyncStaticParam><asyncWorkflow><asyncWorkflow>
Measure of issue-1, Server load-upServer sends control info for poll-timing to clients
Server gets the initiative to control its QoS.Server gets the initiative to control its QoS.Server gets the initiative to control its QoS.
6
Measure for issue-2, difficulty of client impl.Create a utility layer for Async Web Services
ClientClient
J2EE PlatformJ2EE Platform
WebWeb ServiceServiceClient impl.Client impl.
JAX-RPCJAXJAX--RPCRPC
SOAP ServerSOAP Server
J2EE PlatformJ2EE Platform
JAX-RPCJAXJAX--RPCRPC
WebWeb Service impl.Service impl.
Utility layerUtility layer
InvokeInvokeInvoke
Get resultGet resultGet result
AP
Is (Syn
c/A
sync)
AP
Is (Syn
c/A
sync)
Main controllerMain controller
TimerTimermangermanger
Control infoControl infomanagermanager
Status mangerStatus manger
7
Feasibility Study of Async Web Services
J2EEJ2EE PlatformPlatform
Com. layerCom. layer
Sync APISync API
Client impl.Client impl.
Com. layerCom. layer
Web ServiceWeb Service
AXISAXISAXISAXIS
ClientClient SOAP ServerSOAP Server
Async APIAsync API
WorkflowWorkflowcontrolcontrol
EnhancedEnhanced[Legend] ExistingExisting
8
The result of the Feasibility Study (1/4)Benefit #1
//処理要求用の設定
Servcie service = new Service(serviceName);
Call call = service.createCall();
call.setOperationName(startOperationName);
call.addParameter("in0", XMLType.XSD_STRING,ParameterMode.IN);
call.addParameter("in1", XMLType.XSD_LONG,ParameterMode.IN);
call.setReturnType(XSD_ANY);
call.setTargetEndpointAddress(endpointURL);
call.setMaintainSession(true);
call.invoke(new Object[]{"HELLO", new Integer(10)});//処理要求呼び出し
//パーサの準備
try{
DocumentBuilderFactory d = DocumentBuilderFactory.newInstance();
DocumentBuilderFactory factory = new org.apache.xerces.jaxp.DocumentBuilderFactoryImpl();
boolean isValidate = true;
factory.setValidating(isValidate);
factory.setNamespaceAware(true);
factory.setAttribute("http://apache.org/xml/features/validation/schema" ,new Boolean(true));
builder = factory.newDocumentBuilder();
builder.setErrorHandler(new ValidationErrorHandler());
}catch(ParserConfigurationException e){
throw new InternalException(e);
}
//ヘッダ要素の抽出開始
MessageContext msgContext = call.getMessageContext();
Message msg = (Message)msgContext.getMessage();
SOAPEnvelope envelope = msg.getSOAPEnvelope();
SOAPHeaderElement asyncSOAPHeader = envelope.getHeaderByName(Constants.ASYNCSOAP_NS,Constants.ASYNCSOAPHEADER_LOCAL);
MessageElement asyncSOAPElement = (MessageElement)asyncSOAPHeader.getChildren().get(0);
Document headerDoc = asyncSOAPElement.getAsDocument();
String headerString = new XMLUtils().DocumentToString(headerDoc);
ByteArrayInputStream headerStream = new ByteArrayInputStream(headerString.getBytes());
builder.parse(headerStream);//パース
headerStream.close();
//ステータスを取得
Element asyncServerStatusElement = (Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCSERVERSTATUS_LOCAL).item(0);
Element asyncWorkflowElement =(Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCWORKFLOW_LOCAL).item(0);
String statusCode = asyncServerStatusElement.getElementsByTagName(Constants.STATUSCODE_LOCAL).item(0).getFirstChild().getNodeValue();
String statusString = asyncServerStatusElement.getElementsByTagName(Constants.STATUSSTRING_LOCAL).item(0).getFirstChild().getNodeValue();
Element detail = (Element)asyncServerStatusElement.getElementsByTagName(Constants.DETAIL_LOCAL).item(0);
NodeList asyncStaticParamNodeList = headerDoc.getElementsByTagName(Constants.ASYNCSTATICPARAM_LOCAL);
//静的パラメータを取得
Element asyncStaticParamElement = (Element)asyncStaticParamNodeList.item(0);
Text firstIntervalText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.FIRSTINTERVAL_LOCAL).item(0).getFirstChild();
long firstInterval = Long.parseLong(firstIntervalText.getNodeValue());
Text iterateIntervalText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.ITERATEINTERVAL_LOCAL).item(0).getFirstChild();
long iterateInterval = Long.parseLong(iterateIntervalText.getNodeValue());
Text timeoutIntervalText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.TIMEOUTINTERVAL_LOCAL).item(0).getFirstChild();
long timeoutInterval = Long.parseLong(timeoutIntervalText.getNodeValue());
Text maxRetryCountText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.MAXRETRYCOUNT_LOCAL).item(0).getFirstChild();
int maxRetryCount = Integer.parseInt(maxRetryCountText.getNodeValue());
//ポーリング用の準備
Call pollingCall = service.createCall();
pollingCall.setOperationName(endOperationName);
pollingCall.setReturnType(XSD_STRING);
//第一回目のポーリングまで待機
Thread.sleep(firstInterval * 1000);//待機
//ポーリングのループ開始
boolean completed = false;//処理完了フラグ
int loop_count = 0;
while(completed){//処理が完了するまでループ
Object ret = pollingCall.invoke(new Object[]{"HELLO", new Integer(10)});//結果確認呼び出し
loop_count++;
//ヘッダ要素の抽出開始
MessageContext msgContext = call.getMessageContext();
Message msg = (Message)msgContext.getMessage();
SOAPEnvelope envelope = msg.getSOAPEnvelope();
SOAPHeaderElement asyncSOAPHeader = envelope.getHeaderByName(Constants.ASYNCSOAP_NS,Constants.ASYNCSOAPHEADER_LOCAL);
MessageElement asyncSOAPElement = (MessageElement)asyncSOAPHeader.getChildren().get(0);
Document headerDoc = asyncSOAPElement.getAsDocument();
String headerString = new XMLUtils().DocumentToString(headerDoc);
ByteArrayInputStream headerStream = new ByteArrayInputStream(headerString.getBytes());
builder.parse(headerStream);
headerStream.close();
//パラメータの抽出
Element asyncServerStatusElement = (Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCSERVERSTATUS_LOCAL).item(0);
Element asyncWorkflowElement =(Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCWORKFLOW_LOCAL).item(0);
String statusCode = asyncServerStatusElement.getElementsByTagName(Constants.STATUSCODE_LOCAL).item(0).getFirstChild().getNodeValue();
String statusString = asyncServerStatusElement.getElementsByTagName(Constants.STATUSSTRING_LOCAL).item(0).getFirstChild().getNodeValue();
Element detail = (Element)asyncServerStatusElement.getElementsByTagName(Constants.DETAIL_LOCAL).item(0);
//ステータスの確認
if(!statusCode.equals("RUNNING")){
completed = true;
}
//最大リトライ数のチェック
if(loop_count >= maxRetryCount){
throw new Exception("最大ポーリング回数を超過しました.");
}
Thread.sleep(iterateInterval * 1000);
}
//結果の表示
System.out.println("return : " + ret);
//処理要求用の設定
Servcie service = new Service(serviceName);
Call call = service.createCall();
call.setOperationName(startOperationName);
call.addParameter("in0", XMLType.XSD_STRING,ParameterMode.IN);
call.addParameter("in1", XMLType.XSD_LONG,ParameterMode.IN);
call.setReturnType(XSD_ANY);
call.setTargetEndpointAddress(endpointURL);
call.setMaintainSession(true);
call.invoke(new Object[]{"HELLO", new Integer(10)});//処理要求呼び出し
//パーサの準備
try{
DocumentBuilderFactory d = DocumentBuilderFactory.newInstance();
DocumentBuilderFactory factory = new org.apache.xerces.jaxp.DocumentBuilderFactoryImpl();
boolean isValidate = true;
factory.setValidating(isValidate);
factory.setNamespaceAware(true);
factory.setAttribute("http://apache.org/xml/features/validation/schema" ,new Boolean(true));
builder = factory.newDocumentBuilder();
builder.setErrorHandler(new ValidationErrorHandler());
}catch(ParserConfigurationException e){
throw new InternalException(e);
}
//ヘッダ要素の抽出開始
MessageContext msgContext = call.getMessageContext();
Message msg = (Message)msgContext.getMessage();
SOAPEnvelope envelope = msg.getSOAPEnvelope();
SOAPHeaderElement asyncSOAPHeader = envelope.getHeaderByName(Constants.ASYNCSOAP_NS,Constants.ASYNCSOAPHEADER_LOCAL);
MessageElement asyncSOAPElement = (MessageElement)asyncSOAPHeader.getChildren().get(0);
Document headerDoc = asyncSOAPElement.getAsDocument();
String headerString = new XMLUtils().DocumentToString(headerDoc);
ByteArrayInputStream headerStream = new ByteArrayInputStream(headerString.getBytes());
builder.parse(headerStream);//パース
headerStream.close();
//ステータスを取得
Element asyncServerStatusElement = (Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCSERVERSTATUS_LOCAL).item(0);
Element asyncWorkflowElement =(Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCWORKFLOW_LOCAL).item(0);
String statusCode = asyncServerStatusElement.getElementsByTagName(Constants.STATUSCODE_LOCAL).item(0).getFirstChild().getNodeValue();
String statusString = asyncServerStatusElement.getElementsByTagName(Constants.STATUSSTRING_LOCAL).item(0).getFirstChild().getNodeValue();
Element detail = (Element)asyncServerStatusElement.getElementsByTagName(Constants.DETAIL_LOCAL).item(0);
NodeList asyncStaticParamNodeList = headerDoc.getElementsByTagName(Constants.ASYNCSTATICPARAM_LOCAL);
//静的パラメータを取得
Element asyncStaticParamElement = (Element)asyncStaticParamNodeList.item(0);
Text firstIntervalText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.FIRSTINTERVAL_LOCAL).item(0).getFirstChild();
long firstInterval = Long.parseLong(firstIntervalText.getNodeValue());
Text iterateIntervalText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.ITERATEINTERVAL_LOCAL).item(0).getFirstChild();
long iterateInterval = Long.parseLong(iterateIntervalText.getNodeValue());
Text timeoutIntervalText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.TIMEOUTINTERVAL_LOCAL).item(0).getFirstChild();
long timeoutInterval = Long.parseLong(timeoutIntervalText.getNodeValue());
Text maxRetryCountText = (Text)asyncStaticParamElement.getElementsByTagName(Constants.MAXRETRYCOUNT_LOCAL).item(0).getFirstChild();
int maxRetryCount = Integer.parseInt(maxRetryCountText.getNodeValue());
//ポーリング用の準備
Call pollingCall = service.createCall();
pollingCall.setOperationName(endOperationName);
pollingCall.setReturnType(XSD_STRING);
//第一回目のポーリングまで待機
Thread.sleep(firstInterval * 1000);//待機
//ポーリングのループ開始
boolean completed = false;//処理完了フラグ
int loop_count = 0;
while(completed){//処理が完了するまでループ
Object ret = pollingCall.invoke(new Object[]{"HELLO", new Integer(10)});//結果確認呼び出し
loop_count++;
//ヘッダ要素の抽出開始
MessageContext msgContext = call.getMessageContext();
Message msg = (Message)msgContext.getMessage();
SOAPEnvelope envelope = msg.getSOAPEnvelope();
SOAPHeaderElement asyncSOAPHeader = envelope.getHeaderByName(Constants.ASYNCSOAP_NS,Constants.ASYNCSOAPHEADER_LOCAL);
MessageElement asyncSOAPElement = (MessageElement)asyncSOAPHeader.getChildren().get(0);
Document headerDoc = asyncSOAPElement.getAsDocument();
String headerString = new XMLUtils().DocumentToString(headerDoc);
ByteArrayInputStream headerStream = new ByteArrayInputStream(headerString.getBytes());
builder.parse(headerStream);
headerStream.close();
//パラメータの抽出
Element asyncServerStatusElement = (Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCSERVERSTATUS_LOCAL).item(0);
Element asyncWorkflowElement =(Element)headerDoc.getElementsByTagNameNS(Constants.ASYNCSOAP_NS, Constants.ASYNCWORKFLOW_LOCAL).item(0);
String statusCode = asyncServerStatusElement.getElementsByTagName(Constants.STATUSCODE_LOCAL).item(0).getFirstChild().getNodeValue();
String statusString = asyncServerStatusElement.getElementsByTagName(Constants.STATUSSTRING_LOCAL).item(0).getFirstChild().getNodeValue();
Element detail = (Element)asyncServerStatusElement.getElementsByTagName(Constants.DETAIL_LOCAL).item(0);
//ステータスの確認
if(!statusCode.equals("RUNNING")){
completed = true;
}
//最大リトライ数のチェック
if(loop_count >= maxRetryCount){
throw new Exception("最大ポーリング回数を超過しました.");
}
Thread.sleep(iterateInterval * 1000);
}
//結果の表示
System.out.println("return : " + ret);
BeforeBefore// ポーリングによる実装例
ServiceFactory factory = ServiceFactory.newInstance();
Service service = ServiceFactory.createService(serviceName);
Call call = service.createCall();
call.setOperationName(new QName(targetNS, operationName));
call.setTargetEndpointAddress(endpointURL);
call.addParameter("in0", XMLType.XSD_STRING, ParameterMode.IN);
call.addParameter("in1", XMLType.XSD_LONG, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setOperationModel(OperationModel.ASYNC_PULL);
call.invokeAsync(new Object[]{inputData});
long pollingInterval = 2000;
AsyncStatus status = call.getAsyncStatus();
while(status.isRunnging()){
Thread.sleep(pollingInterval);
status = call.getAsyncStatus();
}
String ret = (String)call.getAsyncReturnValue();
System.out.println(ret);
// ポーリングによる実装例
ServiceFactory factory = ServiceFactory.newInstance();
Service service = ServiceFactory.createService(serviceName);
Call call = service.createCall();
call.setOperationName(new QName(targetNS, operationName));
call.setTargetEndpointAddress(endpointURL);
call.addParameter("in0", XMLType.XSD_STRING, ParameterMode.IN);
call.addParameter("in1", XMLType.XSD_LONG, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setOperationModel(OperationModel.ASYNC_PULL);
call.invokeAsync(new Object[]{inputData});
long pollingInterval = 2000;
AsyncStatus status = call.getAsyncStatus();
while(status.isRunnging()){
Thread.sleep(pollingInterval);
status = call.getAsyncStatus();
}
String ret = (String)call.getAsyncReturnValue();
System.out.println(ret);
AfterAfter
75 lines75 lines Just 17 linesJust 17 lines
Reduces user implementationabout 4.5 times.
Reduces user implementationReduces user implementationabout 4.5 times.about 4.5 times.
9
The result of the Feasibility Study (2/4)Benefit #2
Syn
c/A
sync In
terfac
eSyn
c/A
sync In
terfac
e
ClientClient
WebWeb ServiceServiceClient impl.Client impl. JAXJAX--RPC 1.0, 1.1RPC 1.0, 1.1
Call . Invoke ()Call . Invoke ()Call . Invoke ()
Call . invokeOneWay ()Call . invokeOneWay ()Call . invokeOneWay ()
{ Call . invokeAsync () } ?{ { Call . invokeAsync () Call . invokeAsync () } ?} ?
JAXJAX--RPC 2.0RPC 2.0
SyncSyncSync
One-wayOneOne--wayway
AsyncAsyncAsync
An asynchronous invocation will be possible at the usage according to the existing synchronous type API.
An asynchronous invocation will be possible at the usage An asynchronous invocation will be possible at the usage according to the existing synchronous type API.according to the existing synchronous type API.
10
ClientClient SOAP ServerSOAP Server
WebWeb service impl.service impl.WebWeb Service client impl.Service client impl.
Syn
c/A
sync In
terfac
eSyn
c/A
sync In
terfac
e
Async APIAsync APIAsync API
Callback APICallback APICallback API
Polling APIPolling APIPolling API
Sync WSSync WSSync WS
Polling WSPolling WSPolling WS
The result of the Feasibility Study (3/4)Benefit #3
The access model of API layer and transport layeris separated, completely.
The access model of API layer and transport layerThe access model of API layer and transport layeris separated, completely.is separated, completely.
11
The result of the Feasibility Study (4/4)
Server gets the initiative to control its QoS.Server gets the initiative to control its QoS.Server gets the initiative to control its QoS.
ClientClient SOAP ServerSOAP Server
WebWeb Service impl.Service impl.WebWeb Service client impl.Service client impl.
Web ServiceWeb ServiceWeb Service
Control info DB
AA
BBCC
Order requestOrder request
Get resultGet result
<<asyncWorkflow> asyncWorkflow> <asyncStaticParam><asyncStaticParam>
<firstInteval><firstInteval>36003600</firstInterval></firstInterval> <iterateInterval><iterateInterval>360360</iterateInterval></iterateInterval>
<timeoutInterval><timeoutInterval>100000100000</timeoutInterval></timeoutInterval><maxRetryCount>50</maxRetryCount><maxRetryCount>50</maxRetryCount>
</asyncStaticParam></asyncStaticParam><asyncWorkflow><asyncWorkflow>
Benefit #4
12
Conclusion
■ Three levels to support asynchronous Web Services
■ Level1: Client-side only(Microsoft has already supported it as “Delegate”.)
■ Level2: Both Client-side and Server-sideexcept the poll timing control(Some of vendors has tried to support it in their ownproducts by the original way.)
■ Level3: Both Client-side and Server-sidewith the poll timing control(This is my proposal.)
13
ー The End -
Thank you for your attention.