Single Port-Type

From GCube System
Revision as of 23:29, 24 March 2008 by Manuele.simi (Talk | contribs) (Putting all together: a richer Stateless Port-Type implementation)

Jump to: navigation, search

From configuration to testing with a single Port-Type

Even if not compulsory, we strongly suggest to adopt the Eclipse 3.3 as development platform. In such an IDE, open a new workspace with a Java 1.5 compiler and create a new Java project by specifying a source folder (named from now on, SERVICE folder). Then, fill a user-library with all JARs in gCore lib and name it CONTAINERLIB.

Structuring the service code

Prepare the SERVICE folder structure as follows:

  1. create a etc folder where to place your configuration files
  2. create a org/acme/sample folder where to place your source code
  3. create a schema folder where to place the remote interface files
  4. copy the share/gcube_tools/build.xml file into your SERVICE folder

Profiling for the infrastructure

Create a new XML file named Profile.xml and place it in the SERVICE/etc folder. This file profiles the service in such a way that the instance of a service can be discovered by others and eventually dynamically deployed in a gCube infrastructure.

<Resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<ID></ID>
	<Type>Service</Type>
	<Profile>
		<Description>A very simple gCube Service</Description>
		<Class>Samples</Class>
		<Name>SampleService</Name>
		<Packages>
			<Main>
				<Description>Describes port-types</Description>
				<Name>Main</Name>
				<Dependencies>
					<Dependency>
						<Service>
							<Class>Samples</Class>
							<Name>SampleService</Name>
						</Service>
						<Package>Stubs</Package>
						<Version>1.0</Version>
						<Scope level="GHN"/>
						<Optional>false</Optional>
					</Dependency>
				</Dependencies>
				<GARArchive>org.acme.sample.gar</GARArchive>
				<PortType>
					<Name>acme/sample/stateless</Name>
					<WSDL/>
				</PortType>
			</Main>
			<Software>
				<Description>Describes port-type stubs</Description>
				<Name>Stubs</Name>
				<Files><File>org.acme.sample.stubs.jar</File></Files>
			</Software>
		</Packages>
	</Profile>
</Resource>

The file identifies our service by assigning it a ServiceClass and a ServiceName. It also describes the service decomposition: it is composed by two packages, the service itself and its stubs and that the first one has a GHN-scoped dependency against the second one. Finally, it indicates that the service has a single Port-Type named acme/sample/stateless.

JNDI configuration

Create a new XML file named deploy-jndi-config.xml and and place it in the SERVICE/etc folder. It will include either the global service configuration and the all the Port-Type ones. The file has a two-fold role:

  1. tells to the gCube framework about the service
  2. makes available to the service at runtime the information included there
<jndiConfig xmlns="http://wsrf.globus.org/jndi/config">
	<service name="acme/sample">
	
		<environment 
		name="profile" 
	 	value="@config.dir@/profile.xml" 
	 	type="java.lang.String"
	 	override="false" />
		 	
	</service>
</jndiConfig>

Notes:

  • at this stage, the file only include a service section reporting the name of the service ("acme/sample") and the name of the profile created
  • the @config.dir@ is a placeholder replaced at deployment time with the real path of the SERVICE/etc folder

Sketching Port-type Interfaces

WSDL structure

The following is the basic skeleton of any WSDL interface:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:tns="...." xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
name="Stateless" targetNamespace=".....">
	<types>
		<xsd:schema targetNamespace=".....">
			<!-- REQUEST AND RESPONS TYPE DEFINITIONS -->
		</xsd:schema>
	</types>
	
	<!-- MESSAGES  -->

	<portType name=".....">

		<!-- OPERATION -->

	</portType>
</definitions>

Defining the Stateless Port-Type

Create a new WSDL file, name it Stateless.wsdl and place the file in the SERVICE/etc folder.

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:tns="http://acme.org/sample" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"  name="Stateless" targetNamespace="http://acme.org/sample">

	<types>
		<xsd:schema targetNamespace="http://acme.org/sample">
			<xsd:element name="about" type="xsd:string"/>
			<xsd:element name="aboutResponse" type="xsd:string"/>
		</xsd:schema>
	</types>
	<message name="aboutInputMessage">
		<part name="request" element="tns:about"/>
	</message>
	<message name="aboutOutputMessage">
		<part name="response" element="tns:aboutResponse"/>
	</message>
	<portType name="StatelessPortType">
		<operation name="about">
			<input message="tns:aboutInputMessage"/>
			<output message="tns:aboutOutputMessage"/>			
		</operation>
	</portType>
</definitions>

This file defines the interface of the first stateless Port-Type of the Sample Service. The interface has a single operation, named about that accepts as input a string and returns a string as output. Moreover, the operation can throw three types of fault, that are defined in the imported GCUBEFaults.wsdl. Each fault has a specific semantic within a gCube infrastructure:

  • GCUBEUnrecoverableFaultMessage ...
  • GCUBERetrySameFaultMessage...
  • GCUBERetryEquivalentFaultMessage ...

Namespace mappings

To successfully generate the stub classes from the WSDL inteface, we need to tell to gCore where (i.e. in what Java package) to place the stub classes. This is done with a mappings file, which maps WSDL namespaces to Java packages, named namespace2package.mappings and placed in the SERVICE root folder.

http\://acme.org/sample=org.acme.sample.stubs
http\://acme.org/sample/bindings=org.acme.sample.stubs.bindings
http\://acme.org/sample/service=org.acme.sample.stubs.service

Delving into the implementation

The Service Context

The fist thing to implement is the Service Context. It is a static component which represents the whole service within the GHN and the rest of its implementation. It has multi-fold role:

  • a provider of service-wide information & utilities
  • bootstraps the service within the GHN
  • gives access to JNDI configuration & profile information
  • manages security and scope
  • …and more

The role of the service context it's very complex role, but fortunately it’s all transparently catered for by the gCore Framework. What is needed it's just derive your context it from GCUBEServiceContext class and fill in the blanks.

Create a ServiceContext.java class in your SERVICE source root folder.

package org.acme.sample;

import org.gcube.common.core.contexts.GCUBEServiceContext;

public class ServiceContext extends GCUBEServiceContext {

	
	/** Single context instance, created eagerly */
	private static ServiceContext cache = new ServiceContext();
	
	/** Returns cached instance */
	public static ServiceContext getContext() {return cache;}
	
	/** Prevents accidental creation of more instances */
	private ServiceContext(){};
		
	/**
	 * {@inheritDoc}
	 */
	public String getJNDIName() {return "acme/sample";}
	
}

Notes:

  • the class adopts the singleton pattern. As best practice, it is strongly suggested to always adopt it for ANY context defined in a gCube service
  • the getJNDIName() method identifies the configuration in the JNDI file and must return the name given to the service there (acme/sample in this example). It MUST be implemented

A first implementation for the Stateless Port-Type

The implementation of the Stateless Port-Type provides a mean to bootstrap the service by extending the GCUBEStartupPortType and to serve the Port-Type clients.

package org.acme.sample.stateless;
import org.acme.sample.ServiceContext;
import org.gcube.common.core.contexts.GCUBEServiceContext;
import org.gcube.common.core.porttypes.GCUBEStartupPortType;

public class Stateless extends GCUBEStartupPortType {

	/** {@inheritDoc} */
	protected GCUBEServiceContext getServiceContext() {return ServiceContext.getContext();}
	
	public String about(String name) {
		
		return ("Hello " + name + ", you have invoked service ")+
		this.getServiceContext().getName() + " ("+
		this.getServiceContext().getServiceClass() + ")";				
	}
}

Notes:

  • the GCUBEStartupPortType is a class defined in the gCore Framework performing the Service instance initialisation. In any gCube service, there MUST be ONE (and only ONE) Port-Type that extends this class.
  • the getServiceContext() method MUST be implemented. It connects the Port-Type to the Service Context
  • the about(String name) method provides an implementation of the about operation defined in the WSDL interface

Towards Deployment: the WSDD descriptor

A gCube service is deployed into an Axis message processing node using an XML-based deployment descriptor file known as a Web Service Deployment Descriptor (WSDD). WSDD describes how the various components installed in the Axis node are to be chained together to process incoming and outgoing messages to the service. These chain definitions are (somehow) compiled and made available at runtime through registries. Each service section reports deployment instructions about a Port-Type. In our Sample service, the first version of the WSDD instructs the Axis engine about how to deploy and activate the Stateless Port-Type of the Sample Service. It must be placed in the SERVICE/etc folder and named deploy-server.wsdd.

<?xml version="1.0" encoding="UTF-8"?>
<deployment name="defaultServerConfig" 
    xmlns="http://xml.apache.org/axis/wsdd/" 
    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <service name="acme/sample/stateless" provider="Handler" use="literal" style="document">
        <parameter name="className" value="org.acme.sample.stateless.Stateless"/>
        <wsdlFile>share/schema/SampleService/Stateless_service.wsdl</wsdlFile>
        <parameter name="allowedMethods" value="*"/>
        <parameter name="handlerClass" value="org.globus.axis.providers.RPCProvider"/>
        <parameter name="scope" value="Application"/>
        <parameter name="loadOnStartup" value="true"/>
        <parameter name="securityDescriptor" value="@config.dir@/security_descriptor.xml"/> 
    </service>
    	  
</deployment>

Notes:

  • the value of the name attribute of the service element, together with the base URL of gCore, will form the URI at which our Port-Type listens the incoming requests (in this example, the complete URL will result ''http://localhost:8080/wsrf/services/acme/sample/stateless'' ). This value MUST be the same reported as name of the Port-Type in the service profile.
  • the value of the className parameter is the Port-Type implementation class
  • the loadOnStartup parameter MUST be set to true for the bootstrapping Port-Type (i.e. the one that implements the GCUBEStartupPortType)

Building & Deploying

The overall build and deployment process is done with the facilities offered by the Ant build tool and thanks to the support of the gCore scripts. Before to start the build process, type:

source $GLOBUS_LOCATION/bin/gcore-load-env

This loads all the needed files in your development environment.

Configuring the build process

To configure the build process, create a build.properties file and place it into the SERVICE root folder.

name = SampleService
package = org.acme.sample
package.dir = org/acme/sample
lib.dir = SERVICELIBS/SampleService
wsdl.1 = Stateless

Notes:

  • the name parameter is the name of the service
  • the package parameter is the root Java package
  • the package.dir parameter is the root folder of the implementation files
  • the lib.dir points to external dependencies (relative to the BUILD_LOCATION)
  • the wsdl.X parameters provide a list of the service Port-Types

Before to build, you have to define a BUILD_LOCATION environment variable

export BUILD_LOCATION=<your build location>

The BUILD_LOCATION/lib.dir folder is used to place the produced stubs to be then exploited for compile time dependencies. This is also a simple way to collect all the produced stubs in a single location and to easily share them among developers. The BUILD_LOCATION/build folder is used to store temporary files created during the build process.

Building the stubs

In the BUILD_LOCATION folder, type

${BUILD_LOCATION}> ant -f <SERVICE folder>/build.xml stubs

This performs a temporary build in the BUILD_LOCATION/build folder. Then, the generated Jar is:

  • deployed in the GLOBUS_LOCATION/lib folder for runtime deployment
  • deployed in the SERVICELIBS/SampleService folder to be used as compile-time dependency. From the Java Build Path configuration of the Eclipse project, you should add this file as an External Jar and see resolved the dependencies against the stub classes.

Building the service

In the BUILD_LOCATION folder, type

${BUILD_LOCATION}> ant -f <SERVICE folder>/build.xml

This implicitly uses the service target. The command above performs a temporary build in the BUILD_LOCATION/build folder, a packaging of the service in a GAR archive and a local deployment in the SERVICE folder. If everything works, the contents of the GAR archive should look like the following:

org.acme.sample.gar
|
|-etc
   |
   |-deploy-jndi-config.xml
   |-deploy-server.wsdd
   |-profile.xml
|
|-lib
   |
   |-org.acme.sample.jar
|
|-META-INF
   |
   |-MANIFEST.MF
|
|-schema
   |
   |-Stateless_bindings.wsdl
   |-Stateless_flattened.wsdl
   |-Stateless_service.wsdl
   |-Stateless.wsdl

(Un)Deploying the Service

To deploy the SampleService, type in your BUILD_LOCATION folder:

${BUILD_LOCATION}> gcore-deploy-service SAMPLESERVICE/org.acme.sample.gar

This preforms a runtime deployment of the service by:

  • assigning it the ID org.acme.sample
  • creating a new GLOBUS_LOCATION/etc/org.acme.sample and copying there the service configuration files
  • copying the compiled code in the GLOBUS_LOCATION/lib folder
  • creating a new GLOBUS_LOCATION//share/schema/SampleService and copying there all the service interfaces (WSDLs)

To undeploy the SampleService, just type:

gcore-undeploy-service org.acme.sample

gCore Logging & Restart

Once a service is deployed, one might want to configure the service container to log the service activity. In order to do that, edit the GLOBUS_LOCATION/container-log4j.properties and add the following category line for org.acme

# Display any warnings generated by our code
log4j.category.org.globus=WARN
log4j.category.org.gcube=DEBUG
[...]
log4j.category.org.acme=DEBUG

This enables the debug level for every code under the org.acme package.

Then, by typing the following

${BUILD_LOCATION}> gcore-start-container -nosec 

or

${BUILD_LOCATION}> gcore-start-container -nosec -debug

it is possible to start the gContainer. The second option (-debug) enable the container to run in the debug mode, so it logs as much as possible all the activities. The log output is appended to the container.log file generated in the working folder (i.e. the folder from which you start the container).

A Test Client for Stateless Port-Type

The StatelessTest class is a simple client for the Stateless Port-Type.

package org.acme.sample.tests;


import org.acme.sample.stubs.StatelessPortType;
import org.acme.sample.stubs.service.StatelessServiceAddressingLocator;
import org.apache.axis.message.addressing.AttributedURI;
import org.apache.axis.message.addressing.EndpointReferenceType;
import org.gcube.common.core.scope.GCUBEScope;
import org.gcube.common.core.scope.GCUBEScopeManager;
import org.gcube.common.core.scope.GCUBEScopeManagerImpl;
import org.gcube.common.core.utils.logging.GCUBEClientLog;

public class StatelessTest {

	static GCUBEClientLog logger = new GCUBEClientLog(StatelessTest.class);
	
	public static void main(String[] args) throws Exception {
		
		GCUBEScopeManager manager = new GCUBEScopeManagerImpl();
		manager.setScope(GCUBEScope.getScope(args[1]));
		
		logger.debug("Stateless Client is running...");
		EndpointReferenceType endpoint = new EndpointReferenceType();
		endpoint.setAddress(new AttributedURI(args[0]));
		
		StatelessPortType statelessPT = new StatelessServiceAddressingLocator().getStatelessPortTypePort(endpoint);
		manager.prepareCall(statelessPT, "Samples", "SampleService");
		System.out.println(statelessPT.about(args[2]));
		
	}
}

Notes:

  • the GCUBEScopeManager manages call scope for the client
  • GCUBEScope.getScope() parses the input scope e creates a GCUBEScope object
  • the usage of EndPointReferenceType and AddressingLocator is the standard way to access a service hosted on an Axis message processing node

Refining the implementation

In this section, we see how to improve the implementation of the Stateless Port-Type by exploiting other parts of the gCore Framework.

Faults

A fault is a Java Exception that escapes the service implementation. More precisely, it wraps one: by default, the wrapper is a generic SOAP fault, but services may specialise faults to enable better recovery strategies. The gCore Framework pre-defines 3 specialisations upon which even generic clients may usefully act:

  • GCUBEUnrecoverableFault → forget about it
  • GCUBERetryEquivalentFault → try another instance of this service
  • GCUBERetrySameFault → try again in a bit

All of them are rooted in a GCUBEFault. Other specialisations can be freely created by the services with their own semantic.

Faults are heavy-weight exceptions and ought to be created and thrown only at the ‘edge’ of a service. Fortunately, the gCF does most of the work for you by mirroring faults with equivalent exceptions for use ‘inside’ the service implementation:

  • GCUBEUnrecoverableFault is mirrored in a GCUBEUnrecoverableException
  • GCUBERetryEquivalentFault is mirrored in a GCUBERetryEquivalentException
  • GCUBERetrySameFault is mirrored in a GCUBERetrySameException

and all of them are rooted in a GCUBEException.

gCube exceptions and faults are freely convertible; all gCube services ought to convert from exception to faults,some may do the opposite when talking to other services. There are gCore Framework components which do this transparently.

A Fault-ful Port-Type

The definition of the Stateless Port-Type can be refined to throw specialised faults:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:tns="http://acme.org/sample" xmlns="http://schemas.xmlsoap.org/wsdl/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:corefaults="http://gcube-system.org/namespaces/common/core/faults" name="Stateless" targetNamespace="http://acme.org/sample">
	<import namespace="http://gcube-system.org/namespaces/common/core/faults" 
location="../gcube/common/core/faults/GCUBEFaults.wsdl"/>
	<types>
		<xsd:schema targetNamespace="http://acme.org/sample">
			<xsd:element name="about" type="xsd:string"/>
			<xsd:element name="aboutResponse" type="xsd:string"/>
		</xsd:schema>
	</types>
	<message name="aboutInputMessage">
		<part name="request" element="tns:about"/>
	</message>
	<message name="aboutOutputMessage">
		<part name="response" element="tns:aboutResponse"/>
	</message>
	<portType name="StatelessPortType">
		<operation name="about">
			<input message="tns:aboutInputMessage"/>
			<output message="tns:aboutOutputMessage"/>
			<fault name="fault" message="corefaults:GCUBEUnrecoverableFaultMessage"/>
			<fault name="fault" message="corefaults:GCUBERetrySameFaultMessage"/>
			<fault name="fault" message="corefaults:GCUBERetryEquivalentFaultMessage"/>
		</operation>
	</portType>
</definitions>

Notes:

  • the corefaults is the namespace where the GCUBEFaults are defined
  • the ../gcube/common/core/faults/GCUBEFaults.wsdl defines the GCUBEFaults and must be imported in order to throw any GCUBEFault.


And this is the new implementation of the Stateless Port-Type:

package org.acme.sample.stateless;
import org.acme.sample.ServiceContext;
import org.gcube.common.core.contexts.GCUBEServiceContext;
import org.gcube.common.core.faults.GCUBEException;
import org.gcube.common.core.faults.GCUBEFault;
import org.gcube.common.core.faults.GCUBERetryEquivalentException;
import org.gcube.common.core.faults.GCUBERetrySameException;
import org.gcube.common.core.faults.GCUBEUnrecoverableException;
import org.gcube.common.core.porttypes.GCUBEStartupPortType;

public class Stateless extends GCUBEStartupPortType {

	/** {@inheritDoc} */
	protected GCUBEServiceContext getServiceContext() {return ServiceContext.getContext();}
	
	protected static void simulateProcessRequest() throws Exception {
		if (Math.random()<.20) { //simulating an error
			switch ((int) (Math.random()*4+1)) {//randomly choosing error type
				case 1 : throw new GCUBEUnrecoverableException("just give up");
				case 2 : throw new GCUBERetryEquivalentException("maybe someone else?");
				case 3: throw new GCUBERetrySameException("maybe in a bit?");
				case 4: throw new Exception("some problem with unclear semantics");
	}}}
	
	public String about(String name) throws GCUBEFault {

		try {
			simulateProcessRequest();
		}
		catch(GCUBEException e) {
		  throw e.toFault();
		}
		catch(Exception e) {
		  this.getServiceContext().getDefaultException("Problem of unknown semantics", e).toFault();
		}

		return ("Hello " + name + ", you have invoked service ")+
		this.getServiceContext().getName() + " ("+
		this.getServiceContext().getServiceClass() + ")";				
	}
}

Notes:

  • the simulateProcessRequest() method is just a trick to randomly choose a fault type (since there is no way to get a real error inside the about method)
  • the getDefaultException() method of the ServiceContext creates and returns a GCubeException starting from a generic Java Exception; then, it is converted into a GCUBEFault by invoking the toFault() method

More Contexts

Other entities but the service may be associated with context components:

  • the GHN itself makes available its own context for node-wide information and utilities: the GHNContext
    • mediates between services during bootstrapping, particularly between the GHNManager and other services
    • exposes a wide gamut of information about the GHN and the machine on which it runs
  • individual port-types might have contexts (and typically will)
    • gives access to port-type specific configuration and other port-type wide utilities

Port-Type Context

So far, the Stateless Port-Type does not have its own context. But this is the most uncommon situation, since typically they have one. The gCore Framework requires that the Port-Type configuration is placed in the JNDI file and it offers facilities to read and expose such a configuration within the Java implementation of the Port-Type

Configuration

Let's see how to extend the SERVICE/etc/deploy-jndi-config.xml to add a Port-Type configuration.

<?xml version="1.0" encoding="UTF-8"?>
<jndiConfig xmlns="http://wsrf.globus.org/jndi/config">

	<service name="acme/sample">	
		<environment 
		name="profile" 
	 	value="@config.dir@/profile.xml" 
	 	type="java.lang.String"
	 	override="false" />		 	
	</service>
	
	<service name="acme/sample/stateless">
		<environment 
		name="name" 
	 	value="StatelessPortType" 
	 	type="java.lang.String"
	 	override="false" /> 	

		<environment 
		name="displayServiceProfile" 
	 	value="true" 
	 	type="java.lang.Boolean"
	 	override="false" /> 	

		<environment 
		name="displayNodeProfile" 
	 	value="true" 
	 	type="java.lang.Boolean"
	 	override="false" /> 	

	</service>
</jndiConfig>

Notes:

  • the name property is optional and is used by the framework for logging purposes
  • the displayServiceProfile and displayNodeProfile are two service-specific properties
Implementation

The context of a Port-Type is modelled through a class that extends the gCore-supplied GCUBEPortType.

package org.acme.sample.stateless;

import org.acme.sample.ServiceContext;
import org.gcube.common.core.contexts.GCUBEPortTypeContext;
import org.gcube.common.core.contexts.GCUBEServiceContext;

public class StatelessContext extends GCUBEPortTypeContext {
	
	/** Single context instance, created eagerly */
	private static GCUBEPortTypeContext cache = new StatelessContext();
	
	/** Returns cached instance */
	public static GCUBEPortTypeContext getContext() {return cache;}
	
	/**{@inheritDoc}*/
	public String getJNDIName() {return "acme/sample/stateless";}

	/** {@inheritDoc}*/
	public String getNamespace() {return "http://acme.org/sample";}

	/** {@inheritDoc}*/
	public GCUBEServiceContext getServiceContext() {return ServiceContext.getContext();}

}

Notes:

  • the StatelessContext class adopts the singleton pattern, as suggested for any context
  • the getJNDIName() returns the resource name specified in the JNDI
  • the getNamespace() returns the namespace of the Port-Type as defined in the WSDL interface


Logging

The gCore Framework provide a GCUBELog logging system allowing to add logging functionalities to a gCube service. Each logger can be connected to a context (Port-Type, Service, GHN and so on): in this way all the messages produced by a logger are tailored on that context.

Putting all together: a richer Stateless Port-Type implementation

Now we can refine the Stateless implementation but putting all the new information to have in order to make it aware of the various contexts in which it is acting.

package org.acme.sample.stateless;
import org.acme.sample.ServiceContext;
import org.gcube.common.core.contexts.GCUBEPortTypeContext;
import org.gcube.common.core.contexts.GCUBEServiceContext;
import org.gcube.common.core.contexts.GHNContext;
import org.gcube.common.core.faults.GCUBEException;
import org.gcube.common.core.faults.GCUBEFault;
import org.gcube.common.core.faults.GCUBERetryEquivalentException;
import org.gcube.common.core.faults.GCUBERetrySameException;
import org.gcube.common.core.faults.GCUBEUnrecoverableException;
import org.gcube.common.core.porttypes.GCUBEStartupPortType;

public class Stateless extends GCUBEStartupPortType {

	GCUBELog logger = new GCUBELog(this);
	GCUBELog loggerPT = new GCUBELog(this, StatelessContext.getContext());
	GCUBELog loggerService = new GCUBELog(this, ServiceContext.getContext());

	/** {@inheritDoc} */
	protected GCUBEServiceContext getServiceContext() {return ServiceContext.getContext();}
	
	protected static void simulateProcessRequest() throws Exception {
		if (Math.random()<.20) { //simulating an error
			switch ((int) (Math.random()*4+1)) {//randomly choosing error type
				case 1 : throw new GCUBEUnrecoverableException("just give up");
				case 2 : throw new GCUBERetryEquivalentException("maybe someone else?");
				case 3: throw new GCUBERetrySameException("maybe in a bit?");
				case 4: throw new Exception("some problem with unclear semantics");
	}}}
	
	public String about(String name) throws GCUBEFault {
		loggerPT.debug("about operation just invoked");
		StringBuilder output = new StringBuilder();		
		GHNContext nctx = GHNContext.getContext();
		ServiceContext sctx = ServiceContext.getContext();
		GCUBEPortTypeContext pctx = StatelessContext.getContext();
		try {
			simulateProcessRequest();
			output.append("Hello "+name).append(", you have invoked porttype ").
			append(pctx.getName()+" of service "+sctx.getName()).append(", which you found at ").
			append(pctx.getEPR()+" in the gCube infrastructure "+nctx.getGHN().getInfrastructure());
		}
		catch(GCUBEException e) {
		   throw e.toFault();}
		catch(Exception e) {
		   sctx.getDefaultException("Problem of unknown semantics", e).toFault();
		}
		loggerPT.debug("about operation is quitting...");
		return output.toString();
	}

}


Manuele.simi 01:23, 25 March 2008 (EET)