Implementing Web Services and running Orchestrations

Preview:

DESCRIPTION

Implementing Web Services and running Orchestrations. Mario Caruso Claudio Di Ciccio Vincenzo Forte Ettore Iacomussi Massimo Mecella. From the Offline Synthesis Engine we obtained a composition Now the composition will be orchestrated . System Overview. Onine Phase. Offline Phase. - PowerPoint PPT Presentation

Citation preview

Implementing Web Servicesand running Orchestrations

Mario CarusoClaudio Di CiccioVincenzo Forte

Ettore IacomussiMassimo Mecella

• From the Offline Synthesis Engine we obtained a composition

• Now the composition will be orchestrated

System Overview

OffSen

Orchestrator

Light Service Bed Service

Cont

ext A

war

enes

s

sdd

TargetService

OrchestratorClient

map

Alarm Service

composition

composition

Offline Phase Onine Phase

Orchestrator Client

• Its only role is to trigger an orchestration by passing a composition to the Orchestrator Engine

System Overview

OffSen

Orchestrator

Light Service Bed Service

Cont

ext A

war

enes

s

sdd

TargetService

OrchestratorClient

map

Alarm Service

composition

composition

Offline Phase Onine Phase

Orchestrator engine

• Given – a composition – a map of the available services – and the current state of the services (thanks to the

Context Awareness)• Produces an orchestration and invokes the

proper services operations <transition action="doSwitchOnLight" invoke="BedroomLight">

<target state="lightSwitchedOn"/><postcondition variable="lightStatus">

<set-value value="1"/></postcondition>

</transition>

Context Awareness

• The Context Awareness is a publish/subscribe component– Services play the role of publishers, they publish

events related to their conversational state and their variables whenever an update occurs

– Orchestration Engine (and other SM4All components) are subscribers, they are always aware of the service’s changes trough the CA notifications

Context Awareness

Service

ContextAwareness

OrchestratorEngine

Service

ContextAwareness

OrchestratorEngine

System Overview

OffSen

Orchestrator

Light Service Bed Service

Cont

ext A

war

enes

s

sdd

TargetService

OrchestratorClient

map

Alarm Service

composition

composition

Offline Phase Onine Phase

The role of the map• In the SM4All project there is a Repository, a system component in charge

of dynamically maintain and provide information about the currently available services

• For the sake of simplicity such component has been replaced by the map file, a static description of the available services in the form of a dictionary:

<service_key, service_endpoint> • It plays the role of a bridge between the offline phase and the online phase

– the offline synthesis engine produces compositions containing service’s keys (it doesn’t know where the services are deployed)

– the orchestrator engine invokes services by replacing keys with the endpoints where the services are deployed

• Example:

BedroomLight = http://127.0.0.1:9697/BedroomLight?wsdlAlarm = http://127.0.0.1:9697/Alarm?wsdlBed = http://127.0.0.1:9697/Bed?wsdl

Sdd -> Cbl -> Map -> Services

<conversational-orchestration-state><community-state>

<service-conversational-state service="Alarm" state="unique"/>

<service-conversational-state service="Bed" state="up"/><service-conversational-state service="BedroomLight"

state="on"/><variable-value name="lightStatus" value="1"/><variable-value name="bedStatus" value="1"/>

</community-state>...<transition action="doSwitchOnLight" invoke="BedroomLight">

<target state="lightSwitchedOn"/><postcondition variable="lightStatus">

<set-value value="1"/></postcondition>

</transition>

BedroomLight = http://127.0.0.1:9697/BedroomLight?wsdlAlarm = http://127.0.0.1:9697/Alarm?wsdlBed = http://127.0.0.1:9697/Bed?wsdl

<home …<service-instance name="BedroomLight" description="Light in the bedroom" type="blightServiceType.sbl.xml" siid="bedroom_light" wsa="BedroomLight"><properties><service-property name="room" value="bedroom"/></properties></service-instance><service-instance name="Bed" description="Bed in the bedroom" type="bedServiceType.sbl.xml" siid="bedroom_bed" wsa="Bed"></service-instance><service-instance name="BedRoomAlarm" description="Alarm in the bedroom" type="alarmServiceType.sbl.xml" siid="bedroom_alarm" wsa="Alarm"></service-instance></home>

sdd

cbl

map

Services

off

on

doSwitchOffLight, E2

doSwitchO

ffLight, E2doSw

itchO

nLig

ht, E

1

doSwitchOnLight, E1

Variables:lightStatus ∈ {0.1}

Effects:E1 : lightStatus = 1E2 : lightStatus = 0

@WebService@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL)public interface LightServer {

/*In this case we specify the operation name to match the name of the operation declared of the sbl*/

@WebMethod(operationName="doSwitchOnLight") boolean turnOn();

@WebMethod(operationName="doSwitchOffLight") boolean turnOff();

/*In this case we don't need to explicitly specify the operation name because the java method

has the same name of the operation declared of the sbl*/

@WebMethod String getState();@WebMethod int getValue();

}

The service has • all the operations defined in its behaviour• two aditional operations (getState and getValue)

used to synchronously retrieve the internal state of the service (the asynchronous way is implemented trough the Context Awareness component)

Services

• The service maintains its internal state by updating a state data member and some variables members according to its behaviour.

@WebService(endpointInterface = "it.uniroma1.dis.caruso.light.LightServer") public class LightServerImpl implements LightServer{

...//The value of the variableprivate int value;//The conversational state of the serviceprivate String state;...

State and variables

<variable-model ..<value value="0" id="0"/><value value="1" id="1"/> ..

<variable name="lightStatus" type="custom" model="blight_status.vml.xml" />

blightServiceType.sbl

variables.vdd

blight_status.vml

public class LightServerImpl implements LightServer{public static final String STATE_A = "off";public static final String STATE_B = "on";

public static final int valueOn = 1;public static final int valueOff = 0;

static final String variableEventTypeName = "lightStatus";

<involved-variables><involved-variables>

<variable name="lightStatus”..<state name="off" type="initial-final">

<transition action="doSwitchOnLight"><target state="on" /><postcondition

variable="lightStatus"><set-value

value="1" /></postcondition>

</transition><transition action="doSwitchOffLight">

<target state="off" /><postcondition

variable="lightStatus"><set-value

value="0" /></postcondition>

</transition></state>

Operation names@WebService@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL)public interface LightServer {

@WebMethod(operationName="doSwitchOnLight") boolean turnOn();@WebMethod(operationName="doSwitchOffLight") boolean turnOff(); @WebMethod String getState();@WebMethod int getValue();

}

<involved-variables><involved-variables>

<variable name="lightStatus”..<state name="off" type="initial-final">

<transition action="doSwitchOnLight"><target state="on" /><postcondition

variable="lightStatus"><set-value

value="1" /></postcondition>

</transition><transition action="doSwitchOffLight">

<target state="off" /><postcondition

variable="lightStatus"><set-value

value="0" /></postcondition>

</transition></state>

blightServiceType.sbl

Service lifecycle

Initialization

Running

Termination

Set initial stateand variables values

Register event types In CA (state and variables)

Register the serviceas a publisher wrt CA

Whenever an operation is invoked, and the state/variables changes, publish events accordingly

Gracefully shutdown: Unregister the publisher Unregister event types(state, variables)

NOTE: do not stop the service abruptly, in case you must restart the CA and consequently the whole system (or manually perform unregistrations)

Publish initial stateand variables values

Service lifecycle@WebService(endpointInterface = "it.uniroma1.dis.caruso.light.LightServer") public class LightServerImpl implements LightServer{

public LightServerImpl(String name){state = STATE_A;value = valueOff;System.out.println("Registering events");eventTypeService.type(MediaType.APPLICATION_XML).put(ClientResponse.class,

CopalClient.eventType(stateEventTypeName));eventTypeService.type(MediaType.APPLICATION_XML).put(ClientResponse.class,

CopalClient.eventType(variableEventTypeName));System.out.println("Setting ttl");WebResource test =

service.path(EVENTS_PATH+"/"+stateEventTypeName+"/ttl");response = test.type(MediaType.TEXT_PLAIN).put(ClientResponse.class,

""+Integer.MAX_VALUE);test = service.path(EVENTS_PATH+"/"+variableEventTypeName+"/ttl");response = test.type(MediaType.TEXT_PLAIN).put(ClientResponse.class,

""+Integer.MAX_VALUE);String[] eventNames = {stateEventTypeName, variableEventTypeName};System.out.println("Registering publisher");publishersService.type(MediaType.APPLICATION_XML).put(ClientResponse.class,

CopalClient.publisher(publisherName,eventNames));myPublisher.type(MediaType.APPLICATION_XML).post(ClientResponse.class,

CopalClient.event(stateEventTypeName,state));myPublisher.type(MediaType.APPLICATION_XML).post(ClientResponse.class,

CopalClient.event(variableEventTypeName,""+value));

Service lifecycle@Override

public boolean turnOff() {System.out.println(name + " turning off");state = STATE_A;value = valueOff;ClientResponse response =

myPublisher.type(MediaType.APPLICATION_XML).post(ClientResponse.class, CopalClient.event(stateEventTypeName,state));

myPublisher.type(MediaType.APPLICATION_XML).post(ClientResponse.class, CopalClient.event(variableEventTypeName,""+value));

return true;}@Overridepublic boolean turnOn() {

System.out.println(name + " turning on");state = STATE_B;value = valueOn;myPublisher.type(MediaType.APPLICATION_XML).post(ClientResponse.class,

CopalClient.event(stateEventTypeName,state));myPublisher.type(MediaType.APPLICATION_XML).post(ClientResponse.class,

CopalClient.event(variableEventTypeName,""+value));return true;

}

Service lifecycleRuntime.getRuntime().addShutdownHook(new Thread() {

public void run() {//Remove publisherSystem.out.println("Removing publisher");ClientResponse response =

myPublisher.delete(ClientResponse.class);System.out.println(response.toString());

System.out.println(response.getEntity(String.class).toString());

System.out.println("Removing events");WebResource wr =

service.path(EVENTS_PATH+"/"+stateEventTypeName);response = wr.delete(ClientResponse.class);System.out.println(response.toString());

System.out.println(response.getEntity(String.class).toString());

wr = service.path(EVENTS_PATH+"/"+variableEventTypeName);

response = wr.delete(ClientResponse.class);System.out.println(response.toString());

System.out.println(response.getEntity(String.class).toString());}

});

Since we are deploying web services without using any application server we terminate them by sending a termination signal (ctrl + c). It is not possible to catch such signal from the Eclipse environment, that’s why we create a jar to be launched from a console.

Publishing servicespublic class ServicesPublisher {

public static void main(String[ ] args) {if (args.length<2){

System.out.println("usage: java -jar LightServices.jar ip-address port\nexample: java -jar LightServices.jar 127.0.0.1 9697");

}else{

String address = args[0];String port = args[1];String endpointBase = "http://"+address+":"+port;String endpoint1 = endpointBase+"/BedroomLight";Endpoint ep = Endpoint.publish(endpoint1, new

LightServerImpl("BedroomLight"));System.out.println("Web service published @ " + endpoint1);

String endpoint2 = endpointBase+"/Bed";Endpoint ep2 = Endpoint.publish(endpoint2, new

BedServerImpl("Bed"));System.out.println("Web service published @ " + endpoint2);

String endpoint3 = endpointBase+"/Alarm";Endpoint ep3 = Endpoint.publish(endpoint3, new

AlarmServerImpl("Alarm"));System.out.println("Web service published @ " + endpoint3);

}}

}

Endpoint

String endpointBase = "http://"+address+":"+port;..String endpoint1 = endpointBase+"/BedroomLight”;Endpoint ep = Endpoint.publish(endpoint1, new LightServerImpl("BedroomLight"));System.out.println("Web service published @ " + endpoint1);

BedroomLight = http://127.0.0.1:9697/BedroomLight?wsdlAlarm = http://127.0.0.1:9697/Alarm?wsdlBed = http://127.0.0.1:9697/Bed?wsdl

Map file

Services publisher

Services must be published to the endpoints declared in the map file. When the Orchestrator Engine finds a service symbolic name it looks at the map and replaces such name with the corresponding endpoint.

<transition action="doSwitchOnLight" invoke="BedroomLight"><target state="lightSwitchedOn"/><postcondition variable="lightStatus">

<set-value value="1"/></postcondition>

</transition> 127.0.0.1:9697/BedroomLight

Contains useful methods to communicate with COPAL through REST servicesMain class in charge of deploying web services without an application server

Light Service Interface

Light Service Implementation

Different services belong to different packages

Libraries needed to implement the communication whith the REST Copal services

These files constitute the service/variable archives.They are not needed to build the project, but they are useful to continously check that the service you are implementing complies with the specifications.

Inspecting Web Services

Avoid Target Namespace collision

Target Namespacesdo not collide:

http://alarm.caruso.dis.uniroma1.it/

http://bed.caruso.dis.uniroma1.it/

http://light.caruso.dis.uniroma1.it/

Exporting runnable jar

Exporting runnable jar

Make sureIt is checked

A tool to test WS: SoapUI

A free generic graphical client to test Web services:• Given a web service definition (wsdl) it automatically generates all the request for

each operation.• Then you can invoke the operation with just one click

http://www.soapui.org

The tool is already installed in the Orchestrator Engine Virtual Machine @ /home/sm4all/Desktop/Tools/soapui-3.6.1

Invoking an operation

Context Awareness REST interface• http://localhost:7878/copal/events

– return current context event types• http://localhost:7878/copal/events/{name}

– return context event type with specified name• http://localhost:8080/copal/events/{name}/schema

– return schema in context event type with specified name• http://localhost:8080/copal/publishers

– return current context publishers registered• http://localhost:8080/copal/publishers/{sourceID}

– return context publisher with specified source ID• http://localhost:8080/copal/publishers/{sourceID}/publishedTypes

– return all published types in context publisher with specified source ID

Context Awareness REST via browser

Start the whole system• Starting from the sdd file build your Web Services and export the runnable jar

file (e.g. Services.jar)• Start the Orchestrator Engine Virtual Machine (VM)• Copy the composition file obtained from the Offline Composition Engine in

any location of the VM (e.g. /home/sm4all/Desktop/OrchestratorClient/mycomposition.xml)

• Copy the jar in any location of the VM (e.g. /home/sm4all/ServicesExamples/)• Configure the mapping file

/usr/share/jboss-6.0.0.Final/server/default/deploy/Sm4allUorOrchestrator.war/WEB-INF/classes/ServiceRepository.prop according to the sdd filee.g.BedroomLight = http://127.0.0.1:9697/light?wsdlBedRoomAlarm = http://127.0.0.1:9697/alarm?wsdlBed = http://127.0.0.1:9697/bed?wsdl

Start the whole system

• Start Context Awareness System (COPAL):– open a new console – cd /home/sm4all/OSGI_Copal_0.5.2/– ./run.sh– wait few seconds until the log will display in the

last line something similar to "endpoint.service.id=38}”

– COPAL will we available @ http://localhost:7878

Start the whole system• [OPTIONAL] set the Orchestration Engine properties that you can find

in: /usr/share/jboss-6.0.0.Final/server/default/deploy/Sm4allUorOrchestrator.war/WEB-INF/classes/Orchestrator.prop– change the COPAL base address and the OrchestratorStateManager address;

by default they are set to http://localhost:7878 and http://localhost:8081 respectively

• [OPTIONAL] set the StateManager properties that you can find in: /usr/share/jboss-6.0.0.Final/server/default/deploy/Sm4allUorOrchestratorStatesManager.war/WEB-INF/classes/OrchestratorStatesManager.prop– change the COPAL base address and the OrchestratorStateManager address;

by default they are set to http://localhost:7878 and http://localhost:8081 respectively

Start the whole system

• Start the Orchestrator Engine– open a new console– cd /usr/share/jboss-6.0.0.Final/bin– ./run.sh -b 0.0.0.0– wait few seconds until the log will display in the

last line something similar to "Started in 40s:384ms”

Start the whole system

• Start the Services– open a new console– move to the directory where you copied the jar (e.g. cd /home/sm4all/ServicesExamples/)

– java -jar LightServices.jar address port (e.g. java -jar Services.jar 127.0.0.1 9697)• NOTE: the address and the port of the base endpoint must be

specified according to the map file:

BedroomLight = http://127.0.0.1:9697/BedroomLight?wsdlBedRoomAlarm = http://127.0.0.1:9697/Alarm?wsdlBed = http://127.0.0.1:9697/Bed?wsdl

Start the whole system

• Start the Orchestrator Client– cd ~/Desktop/OrchestratorClient/– java -jar OrchestratorClient.jar <cblPath> e.g. java -jar OrchestratorClient.jar mycomposition.xml • you may either specify an absolute or relative path

– [OPTIONAL] if you want to run a client on a location different from localhost: java -jar OrchestratorClient.jar <cblPath> <orchestratorWsdlLocation>

Orchestration results

• The Orchestrator Client passes the composition file to the orchestrator

• The Orchestrator Engine start to invoke the operations offered by the services

• In the web services console see how services are orchestrated (which operations are invoked)

Context Awareness (COPAL)

Web Services

Orchestrator ClientOrchestrator Engine

Shutdown the whole system

You can run the orchestration client as many times as you want …When you finally want to stop the whole system:1. Shutdown the services (ctrl+c)2. Shutdown the Orchestrator Engine (ctrl+c)3. Shutdown the Context Awareness System

(ctrl+c and then Enter)

Recommended