SCA

Service Injection Example

multiworldclock/multiworldclock.c
Example service implementation code for a service calling another service (where the called service implementation code isn't shown and is identical to the code in the previous example)
multiworldclock/multiworldclock.wsdl
WSDL file for multiworldclock service
multiworldclock/multiworldclock.composite
SCA composite file for multiworldclock service
multiworldclock/META-INF/sca-contribution.xml
SCA contribution file for multiworldclock contribution
worldclock/worldclock.c
Service implementation being called by multiworldclock component (identical to the code in the previous example)
worldclock/worldclock.wsdl
WSDL file for (local) worldclock service/library
worldclock/worldclock.composite
SCA composite file for (local) worldclock service/library
worldclock/META-INF/sca-contribution.xml
SCA contribution file for worldclock service/library

multiworldclock/multiworldclock.c

#include "SCA.h"
#include "SDO.h"

// forward decl
static DATAOBJECT assembleBaseWorldclockRequest(char *city, int hour,
	char *cityToRequestTypeFor);
static DATAOBJECT extractResultTime(DATAOBJECT worldclockResponse);

DATAOBJECT getLocalTimesForCities(DATAOBJECT request) {

	SDOFACTORY df = getDataFactory();

	SDOTYPE requestType =
		findType(df,
			"http://www.example.com/multiworldclock.xsd",
			"worldclockRequest");

	SDOPROPERTY requestTimeProp =
		getTypePropertyByName(requestType, "localTime");

	DATAOBJECT requestTimeObj = getDataObject(request, requestTimeProp);

	SDOPROPERTY cityProp =
		getTypePropertyByName(getPropertyType(requestTimeProp), "city");
	SDOPROPERTY hourProp =
		getTypePropertyByName(getPropertyType(requestTimeProp), "hour");

	char* requestCity = getCString(requestTimeObj, cityProp);
	int requestTime = getInt(requestTimeObj, hourProp);

	SDOPROPERTY otherCitiesProp =
		getTypePropertyByName(requestType, "cityToRequestTimeFor");

	SDOLIST otherCities = getList(request, otherCitiesProp);

	// Locate service reference to invoke
	SCAREF worldclockServiceRef;
	token_t worldclockServiceRefToken;
	worldclockServiceRef = &worldclockServiceRefToken;
	int compCode;
	int reason;
	SCAGetReference("worldclock", worldclockServiceRef, &compCode, &reason);

	// TODO: handle error

	SDOLIST resultList = listAlloc();

	for (int i = 0; i < getCountList(otherCities); i++) {
		int compCode, reason;
		DATAOBJECT otherCity = getDataObjectList(otherCities, i);
		char *otherCityStr = getCString(otherCity, otherCitiesProp);

		// assemble (base, single-city) worldclockRequest for each requested
		// city in list
		DATAOBJECT baseWorldclockRequest =
			assembleBaseWorldclockRequest(requestCity, requestTime, otherCityStr);

		DATAOBJECT baseWorldclockResponse;
		SCAInvoke(worldclockServiceRef, "getLocalTimeForCity",
			0, baseWorldclockRequest,
			0, &baseWorldclockResponse,
			&compCode, &reason);

		if (compCode != SCACC_OK) continue;

		// TODO: handle error

		// dig out result (city, hour) pair,
		// re-assemble, and append to aggregate result 
		DATAOBJECT multiWorldclockTime = extractResultTime(baseWorldclockResponse);
		appendDataObjectList(resultList, multiWorldclockTime);
	}


	// construct aggregate response
	SDOTYPE multiWorldclockResponseType =
		findType(df,
			"http://www.example.com/multiworldclock.xsd",
			"worldclockResponse");

	SDOPROPERTY multiWorldclockResponseTimeProp =
		getTypePropertyByName(multiWorldclockResponseType, "remoteTime");

	DATAOBJECT multiWorldclockResponse =
		doAllocByType(getDataFactory(), multiWorldclockResponseType);
	setList(multiWorldclockResponse, multiWorldclockResponseTimeProp, resultList);

	return multiWorldclockResponse;
}

// returns a request obj for base (non-multi) worldclock service
static DATAOBJECT assembleBaseWorldclockRequest(char *city, int hour, char *cityToRequestTimeFor) {

	SDOFACTORY df = getDataFactory();

	SDOTYPE baseWorldclockRequestType =
		findType(df,
			"http://www.example.com/worldclock.xsd",
			"worldclockRequest");

	SDOTYPE baseWorldclockRequestTimeType =
		findType(df,
			"http://www.example.com/worldclock.xsd",
			"time");

	DATAOBJECT baseWorldclockRequest =
		doAllocByType(getDataFactory(), baseWorldclockRequestType);

	SDOPROPERTY baseWorldclockRequestTimeProp =
		getTypePropertyByName(baseWorldclockRequestType, "local-time");

	DATAOBJECT baseWorldclockRequestTime =
		doAllocByType(getDataFactory(), baseWorldclockRequestTimeType);

	setCStringByName(baseWorldclockRequestTime, "city", city);
	setIntByName(baseWorldclockRequestTime, "hour", hour);

	setDataObject(baseWorldclockRequest, baseWorldclockRequestTimeProp,
		baseWorldclockRequestTime);

	setCStringByName(baseWorldclockRequest, "city-to-request-time-for", cityToRequestTimeFor);

	return baseWorldclockRequest;
}

DATAOBJECT extractResultTime(DATAOBJECT worldclockResponse) {

	SDOFACTORY df = getDataFactory();

	SDOTYPE responseType = findType(df,
		"http://www.example.com/worldclock.xsd",
		"worldclockResponse");

	SDOTYPE timeType = findType(df,
		"http://www.example.com/worldclock.xsd",
		"time");

	SDOPROPERTY responseTimeProp = getTypePropertyByName(responseType, "remote-time");

	DATAOBJECT responseTime = getDataObject(worldclockResponse, responseTimeProp);

	char *city = getCStringByName(responseTime, "city");
	int hour = getIntByName(responseTime, "hour");

	SDOTYPE multiworldclockTimeType = findType(df,
		"http://www.example.com/multiworldclock.xsd",
		"time");

	DATAOBJECT multiworldclockTime =
		doAllocByType(getDataFactory(), multiworldclockTimeType);

	// set city, hour in result obj
	SDOPROPERTY multiworldclockTimeCityProp =
        	getTypePropertyByName(multiworldclockTimeType, "city");
	SDOPROPERTY multiworldclockTimeHourProp =
        	getTypePropertyByName(multiworldclockTimeType, "hour");
	setCString(multiworldclockTime, multiworldclockTimeCityProp, city);

	setInt(multiworldclockTime, multiworldclockTimeHourProp, hour);

	return multiworldclockTime;
}

multiworldclock/multiworldclock.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://www.example.com/multiworldclock.wsdl"
  xmlns="http://www.example.com/multiworldclock.wsdl"
  xmlns:t="http://www.example.com/multiworldclock.xsd"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
  xmlns:sca-c="http://docs.oasis-open.org/ns/opencsa/sca-c-cpp/c/200901"
  xsi:schemaLocation="http://www.w3.org/ns/wsdl http://www.w3.org/2007/06/wsdl/wsdl20.xsd">

	<wsdl:types>

		<xs:schema targetNamespace="http://www.example.com/multiworldclock.xsd"
			          elementFormDefault="qualified">

			<xs:import namespace="http://www.example.com/worldclock.xsd" schemaLocation="worldclock.xsd"/>

			<xs:complexType name="time">
				<xs:sequence>
					<xs:element name="city" type="xs:string"/>
					<xs:element name="hour" type="xs:int"/>
				</xs:sequence>
			</xs:complexType>

			<xs:complexType name="worldclockRequest">
				<xs:sequence>
					<xs:element name="localTime" type="t:time"/>
					<xs:element name="cityToRequestTimeFor" type="xs:string" maxOccurs="unbounded"/>
				</xs:sequence>
			</xs:complexType>

			<xs:complexType name="worldclockResponse">
				<xs:sequence>
					<xs:element name="remoteTime" type="t:time" maxOccurs="unbounded"/>
				</xs:sequence>
			</xs:complexType>

			<xs:element name="worldclockRequest" type="t:worldclockRequest"/>
			<xs:element name="worldclockResponse" type="t:worldclockResponse"/>
		</xs:schema>

	</wsdl:types>

	<wsdl:message name="worldclockRequest">
  		<wsdl:part name="request" element="t:worldclockRequest"/>
	</wsdl:message>

	<wsdl:message name="worldclockResponse">
  		<wsdl:part name="response" element="t:worldclockResponse"/>
	</wsdl:message>

	<wsdl:message name="worldclockFaultResponse">
  		<wsdl:part name="message" element="xs:string"/>
</wsdl:message>

<wsdl:portType name="worldclock-ops">
	<sca-c:bindings>
		<sca-c:enableWrapperStyle>false</sca-c:enableWrapperStyle>
	</sca-c:bindings>
	<wsdl:operation name="getLocalTimesForCities">
		<wsdl:input message="worldclock-request"
		            wsaw:Action="http://www.example.com/multiworldclock/getLocalTimesForCities"/>
		<wsdl:output message="worldclock-response"/>
		<wsdl:fault name="worldclock-fault" message="worldclock-fault-response"/>
	</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="soap-binding" type="worldclock-ops">

  	<soap:binding style="document"
		              transport="http://schemas.xmlsoap.org/soap/http"/>

		<wsdl:operation name="getLocalTimesForCities">
    			<soap:operation soapAction="http://www.example.com/multiworldclock.wsdl/getLocalTimesForCities"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
    			</wsdl:output>
			<wsdl:fault name="worldclock-fault">
				<soap:fault name="worldclock-fault" use="literal"/>
			</wsdl:fault>
		</wsdl:operation>
</wsdl:binding>

<wsdl:service name="worldclock-service">
	<wsdl:port name="workdclock-ops" binding="soap-binding">
		<soap:address location="http://localhost/services/multiworldclock"/>
	</wsdl:port>
</wsdl:service>

</wsdl:definitions>

multiworldclock/multiworldclock.composite

<?xml version="1.0" encoding="ASCII"?>
<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" targetNamespace="http://www.pmsca.com" name="WorldclockComposite">

	<!-- only contains multiworldclock stuff; is expected to be included
	     into a composite where base worldlock is defined -->

	<!-- expose multiworldclock via SOAP -->
	<service name="multiworldclock" promote="multiworldclock-impl">
		<interface.wsdl interface="http://www.pmsca.com/multiworldclock.wsdl#wsdl.interface(multiworldclock-ops)"/>
		<binding.ws wsdlElement="http://www.pmsca.com/multiworldclock.wsdl#wsdl.port(worldclock-service/workdclock-ops)"/>
	</service>

	<!-- multiworldclock impl (aggregates worldclock service) -->
	<component name="multiworldclock-impl">
		<implementation.c module="multiworldclock" library="true" componentType=""/>
		<service name="multiworldclock"/>
		<reference name="worldclock" target="worldclock-impl/worldclock">
			<binding.sca/>
		</reference>
	</component>
</composite>

multiworldclock/META-INF/sca-contribution.xml

<?oasis-xml-catalog catalog="catalog.xml"?>
<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
              xmlns:multiworldclock="http://www.pmsca.com/multiworldclock">
	<deployable composite="multiworldclock:MultiWorldclockComposite.composite"/>
	<import namespace="http://www.pmsca.com/worldclock.wsdl" location="../worldclock.wsdl"/>
	<!-- TODO: FIXME: export composite namespace automatically -->
	<export namespace="http://www.pmsca.com/multiworldclock"/>

	<!-- WSDL -->
	<export namespace="http://www.pmsca.com/multiworldclock.wsdl"/>
</contribution>

worldclock/worldclock.c

#include <stdio.h>

#include "SDO.h"
#include "SCA.h"

static int utc_timezone_offset(char *city);
static int calculate_time_diff(int hour, char *city, char *otherCity);

/*
 * Implementation of worldclock service. 
 */
DATAOBJECT getLocalTimeForCity(DATAOBJECT request) {
		
	SDOFACTORY df = getDataFactory();

	SDOTYPE requestType = getType(request);
	if (requestType == 0) {
		requestType = findType(df,
			"http://www.example.com/worldclock.xsd",
			"worldclockRequest");
	}
	
	SDOPROPERTY requestTimeProp = getTypePropertyByName(requestType, "local-time");
	DATAOBJECT requestTimeObj = getDataObject(request, requestTimeProp);

	SDOPROPERTY cityProp = getTypePropertyByName(getPropertyType(requestTimeProp), "city");
	char* requestCity = getCString(requestTimeObj, cityProp);
	SDOPROPERTY hourProp = getTypePropertyByName(getPropertyType(requestTimeProp), "hour");
	int requestTime = getInt(requestTimeObj, hourProp);
	SDOPROPERTY otherCityProp = getTypePropertyByName(requestType, "city-to-request-time-for");
	char *requestOtherCity = getCString(request, otherCityProp);
	int time_diff = calculate_time_diff(requestTime, requestCity, requestOtherCity);

	// error handling: create a SOAP fault
	if (time_diff < -24 || time_diff > 24) {
		int compcode, reason;
		DATAOBJECT faultResponse = doAlloc(df,
			"http://www.w3.org/2001/XMLSchema",
			"anyType");
		setCStringByName(faultResponse,
			"faultstring",
			"unrecognized city name");
		setCStringByName(faultResponse,
			"faultcode",
			"soap:Client");
		SCASetFaultMessage("worldclock",
			"getLocalTimeForCity",
			"worldclock-fault",
			0,
			faultResponse,
			&compcode,
			&reason);
		return 0;
	}

	SDOTYPE responseType = findType(df,
		/* "http://www.example.com/worldclock.xsd", */
		getURI(requestType),
		"worldclockResponse");

	SDOTYPE timeType = findType(df,
		/* "http://www.example.com/worldclock.xsd", */
		getURI(requestType),
		"time");

	DATAOBJECT response = doAllocByType(getDataFactory(), responseType);
	DATAOBJECT responseTime = doAllocByType(getDataFactory(), timeType);

	setCStringByName(responseTime, "city", requestOtherCity);
	setIntByName(responseTime, "hour", time_diff);

	SDOPROPERTY responseTimeProp = getTypePropertyByName(responseType, "remote-time");
	setDataObject(response, responseTimeProp, responseTime);

	return response;
}

static int calculate_time_diff(int hour, char *city, char *otherCity) {
	return hour + utc_timezone_offset(city) - utc_timezone_offset(otherCity); 
}

static int utc_timezone_offset(char *city) {
	if (!strcmp("Bangalore", city)) return +5;
	if (!strcmp("Berlin", city)) return +1;
	if (!strcmp("San Francisco", city)) return -8;

	// ...

	// return 100 to indicate unknown argument city
	return 100;
}

worldclock/worldclock.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://www.example.com/worldclock.wsdl"
  xmlns="http://www.example.com/worldclock.xsd"
  xmlns:t="http://www.example.com/worldclock.xsd"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
  xmlns:sca-c="http://docs.oasis-open.org/ns/opencsa/sca-c-cpp/c/200901"
  xsi:schemaLocation="http://www.w3.org/ns/wsdl http://www.w3.org/2007/06/wsdl/wsdl20.xsd">

	<wsdl:types>
		<xs:schema targetNamespace="http://www.example.com/worldclock.xsd"
			          elementFormDefault="qualified">

			<!--
			<xs:include schemaLocation="worldclock.xsd"/>
			-->

			<xs:complexType name="time">
				<xs:sequence>
					<xs:element name="city" type="xs:string"/>
					<xs:element name="hour" type="xs:int"/>
				</xs:sequence>
			</xs:complexType>

			<xs:complexType name="getLocalTimeForCity">
				<xs:sequence>
					<xs:element name="local-time" type="t:time"/>
					<xs:element name="city-to-request-time-for" type="xs:string"/>
				</xs:sequence>
			</xs:complexType>

			<xs:complexType name="worldclockResponse">
				<xs:sequence>
					<xs:element name="remote-time" type="t:time"/>
				</xs:sequence>
			</xs:complexType>

			<xs:element name="getLocalTimeForCity" type="t:getLocalTimeForCity"/>
			<xs:element name="worldclockResponse" type="t:worldclockResponse"/>
		</xs:schema>

	</wsdl:types>

	<wsdl:message name="worldclockRequest">
  		<wsdl:part name="request" element="t:getLocalTimeForCity"/>
	</wsdl:message>

	<wsdl:message name="worldclockResponse">
  		<wsdl:part name="response" element="t:worldclockResponse"/>
	</wsdl:message>

	<wsdl:message name="worldclockFaultResponse">
  		<wsdl:part name="message" element="xs:string"/>
</wsdl:message>

<wsdl:portType name="worldclock-ops">
	<!--
        Note: don't need enableWrapperStyle here, won't be deployed as
        remote service hence not checked for enableWrapperStyle presence
	<sca-c:bindings>
		<sca-c:enableWrapperStyle>false</sca-c:enableWrapperStyle>
	</sca-c:bindings>
	-->
	<wsdl:operation name="getLocalTimeForCity">
		<wsdl:input message="worldclock-request"
		            wsaw:Action="http://www.example.com/worldclock/getLocalTimeForCity"/>
		<wsdl:output message="worldclock-response"/>
		<wsdl:fault name="worldclock-fault" message="worldclock-fault-response"/>
	</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="soap-binding" type="worldclock-ops">

  	<soap:binding style="document"
		              transport="http://schemas.xmlsoap.org/soap/http"/>

		<wsdl:operation name="getLocalTimeForCity">
    			<soap:operation soapAction="http://www.example.com/worldclock.wsdl/getLocalTimeForCity"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
    			</wsdl:output>
			<wsdl:fault name="worldclock-fault">
				<soap:fault name="worldclock-fault" use="literal"/>
			</wsdl:fault>
		</wsdl:operation>
</wsdl:binding>

<wsdl:service name="worldclock-service">
	<wsdl:port name="workdclock-ops" binding="soap-binding">
		<soap:address location="http://localhost:9090/services/worldclock"/>
	</wsdl:port>
</wsdl:service>

</wsdl:definitions>

worldclock/worldclock.composite

<?xml version="1.0" encoding="ASCII"?>
<!DOCTYPE composite [
	<!ENTITY AXIS2C_HOME "/home/marcus/Repositories/pmsca/target/x86_64-redhat-linux-gnu">
	<!-- 32bit:
	<!ENTITY AXIS2C_HOME "/home/marcus/Repositories/pmsca/target/i386-redhat-linux-gnu">
	-->
]>
<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
           targetNamespace="http://www.pmsca.com"
           name="WorldclockComposite">

	<!-- expose base worldclock via SOAP -->
	<service name="worldclock" promote="worldclock-impl">
		<interface.wsdl interface="http://www.pmsca.com/worldclock.wsdl#wsdl.interface(worldclock-ops)"/>

		<binding.sca/>
	</service>

	<!-- worldclock impl -->
	<component name="worldclock-impl">
		<implementation.c module="worldclock" library="true" componentType=""/>
		<service name="worldclock"/>
	</component>

</composite>

worldclock/META-INF/sca-contribution.xml

<?oasis-xml-catalog catalog="catalog.xml"?>
<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
	      xmlns:worldclock="http://www.pmsca.com/worldclock">
	<!-- make component available for deployment/to other components -->
	<deployable composite="worldclock:WorldclockComposite.composite"/>
	<!-- TODO: FIXME: export composite namespace automatically -->
	<export namespace="http://www.pmsca.com/worldclock"/>
	<!-- export namespaces of wsdl and xsd -->
	<export namespace="http://www.pmsca.com/worldclock.wsdl"/>
</contribution>