fabio.simeoni 11 years ago
commit 404690f2c6

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-sources/stubs">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>common-gcore-stubs</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

@ -0,0 +1,6 @@
gCube System - License
------------------------------------------------------------
The gCube/gCore software is licensed as Free Open Source software conveying to the EUPL (http://ec.europa.eu/idabc/eupl).
The software and documentation is provided by its authors/distributors "as is" and no expressed or
implied warranty is given for its use, quality or fitness for a particular case.

@ -0,0 +1 @@
* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy

@ -0,0 +1,38 @@
The gCube System - ${name}
----------------------
This work has been partially supported by the following European projects: DILIGENT (FP6-2003-IST-2), D4Science (FP7-INFRA-2007-1.2.2),
D4Science-II (FP7-INFRA-2008-1.2.2), iMarine (FP7-INFRASTRUCTURES-2011-2), and EUBrazilOpenBio (FP7-ICT-2011-EU-Brazil).
Authors
-------
* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy
Version and Release Date
------------------------
${version}
Description
-----------
${description}
Download information
--------------------
Source code is available from SVN:
${scm.url}
Binaries can be downloaded from:
Documentation
-------------
Documentation is available on-line from the Projects Documentation Wiki:
https://gcube.wiki.gcube-system.org/gcube/index.php
Licensing
---------
This software is licensed under the terms you may find in the file named "LICENSE" in this directory.

@ -0,0 +1,5 @@
<ReleaseNotes>
<Changeset component="${build.finalName}" date="11/01/2013">
<Change>First Release</Change>
</Changeset>
</ReleaseNotes>

@ -0,0 +1,38 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>servicearchive</id>
<formats>
<format>tar.gz</format>
</formats>
<baseDirectory>/</baseDirectory>
<fileSets>
<fileSet>
<directory>${distroDirectory}</directory>
<outputDirectory>/</outputDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>README</include>
<include>LICENSE</include>
<include>INSTALL</include>
<include>MAINTAINERS</include>
<include>changelog.xml</include>
<include>profile.xml</include>
</includes>
<fileMode>755</fileMode>
<filtered>true</filtered>
</fileSet>
</fileSets>
<files>
<file>
<source>target/${build.finalName}.jar</source>
<outputDirectory>/${artifactId}</outputDirectory>
</file>
<file>
<source>${distroDirectory}/svnpath.txt</source>
<outputDirectory>/${artifactId}</outputDirectory>
<filtered>true</filtered>
</file>
</files>
</assembly>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ID />
<Type>Service</Type>
<Profile>
<Description>${description}</Description>
<Class>Common</Class>
<Name>${artifactId}</Name>
<Version>1.0.0</Version>
<Packages>
<Software>
<Name>${artifactId}</Name>
<Version>${version}</Version>
<MavenCoordinates>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
</MavenCoordinates>
<Files>
<File>${build.finalName}.jar</File>
</Files>
</Software>
</Packages>
</Profile>
</Resource>

@ -0,0 +1 @@
${scm.url}

@ -0,0 +1,208 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.gcube.tools</groupId>
<artifactId>maven-parent</artifactId>
<version>1.0.0</version>
</parent>
<groupId>org.gcube.core</groupId>
<artifactId>common-gcore-stubs</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>GCore Stubs</name>
<description>JAXWS Stub Support for gCore Service</description>
<scm>
<connection>scm:svn:http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId}</connection>
<developerConnection>scm:svn:https://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId}</developerConnection>
<url>http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId}</url>
</scm>
<properties>
<distroDirectory>distro</distroDirectory>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope</artifactId>
<version>[1.1.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
</dependency>
<!-- test dependencies -->
<!-- provided because it is needed to build test resources -->
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>gcf</artifactId>
<version>[1.5.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
<!-- my-container runtime for integration testing -->
<dependency>
<groupId>org.gcube.tools</groupId>
<artifactId>my-container</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<!-- my-container distribution for integration testing -->
<dependency>
<groupId>org.gcube.tools</groupId>
<artifactId>my-container</artifactId>
<version>1.0.0</version>
<type>tar.gz</type>
<classifier>distro</classifier>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>copy-profile</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target</outputDirectory>
<resources>
<resource>
<directory>${distroDirectory}</directory>
<filtering>true</filtering>
<includes>
<include>profile.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${distroDirectory}/descriptor.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>servicearchive</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- test logic -->
<plugin>
<groupId>org.gcube.tools</groupId>
<artifactId>maven-service-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<basePackage>org.acme.sample</basePackage>
<wsdlDirectory>src/test/resources/test-service/wsdl</wsdlDirectory>
<configurationDirectory>src/test/resources/test-service/etc</configurationDirectory>
<wsdls>
<wsdl>
<name>Stateless</name>
<namespace>http://acme.org</namespace>
</wsdl>
<wsdl>
<name>Stateful</name>
<namespace>http://acme.org</namespace>
</wsdl>
</wsdls>
</configuration>
<executions>
<execution>
<id>generate-stubs</id>
<phase>generate-test-resources</phase>
<goals>
<goal>stub-gen</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Adds stub folder as source folder after stub generation -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/target/generated-sources/stubs</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- installs my-container distribution for integration testing -->
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>install-my-container</id>
<phase>generate-test-resources</phase><!-- runs before tests -->
<configuration>
<includeArtifactIds>my-container</includeArtifactIds>
<includeTypes>tar.gz</includeTypes>
<overWriteIfNewer>false</overWriteIfNewer>
<outputDirectory>${project.basedir}</outputDirectory>
<markersDirectory>${project.basedir}</markersDirectory>
</configuration>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,108 @@
/**
*
*/
package org.gcube.common.clients.stubs.jaxws;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* @author fabio
*
*/
@XmlRootElement(namespace="http://gcube-system.org",name="stacktrace")
public class ExceptionProxy {
static {
try {
context=JAXBContext.newInstance(ExceptionProxy.class);
}
catch(Throwable t) {
throw new AssertionError(t);
}
}
@XmlType(name="e")
static class StackTraceElementProxy {
@XmlAttribute public String cn;
@XmlAttribute public String mn;
@XmlAttribute public String fn;
@XmlAttribute public int ln;
}
private static JAXBContext context;
private static final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
public static ExceptionProxy newInstance(Element e) throws Exception {
return (ExceptionProxy) context.createUnmarshaller().unmarshal(e);
}
public static ExceptionProxy newInstance(Throwable t) {
ExceptionProxy p = new ExceptionProxy();
p.msg=t.getMessage();
p.name=t.getClass().getCanonicalName();
for (StackTraceElement e : t.getStackTrace()) {
StackTraceElementProxy ep = new StackTraceElementProxy();
ep.cn= e.getClassName();
ep.mn=e.getMethodName();
ep.fn=e.getFileName();
ep.ln=e.getLineNumber();
p.el.add(ep);
}
if (t.getCause()!=null)
p.c= newInstance(t.getCause());
return p;
}
@XmlAttribute public String name;
@XmlAttribute public String msg;
@XmlElement public List<StackTraceElementProxy> el = new ArrayList<StackTraceElementProxy>();
@XmlElement public ExceptionProxy c;
public Throwable toThrowable() {
String msg = "remote cause: ("+(this.msg==null?name:this.msg)+")";
Throwable t = c==null? new Throwable(msg):
new Throwable(msg,c.toThrowable());
List<StackTraceElement> elements = new ArrayList<StackTraceElement>();
for (StackTraceElementProxy ep : el)
elements.add(new StackTraceElement(ep.cn, ep.mn, ep.fn, ep.ln));
t.setStackTrace(elements.toArray(new StackTraceElement[0]));
return t;
}
public Element toElement() throws Exception {
Document d = domFactory.newDocumentBuilder().newDocument();
context.createMarshaller().marshal(this,d);
return d.getDocumentElement();
}
}

@ -0,0 +1,84 @@
package org.gcube.common.clients.stubs.jaxws;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.EndpointReference;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* Used internally by {@link StubFactory} to bridge {@link EndpointReference}s to gCore instances which comply with the
* older Member Specification of WS-Addressing (e.g. as returned by a gCore factory service) with
* {@link EndpointReference}s to same instances that comply with W3C's specification of WS-Addressing.
* <p>
* Since JAX-WS does not support Member Addressing directly, nor does the RI embedded in the JDK, reference to gCore
* instances that are produced by gCore services must be manually transformed into a standard form. This requires
* extracting endpoint address and resource key from the references and use them to build a standard reference.
*
* @author Fabio Simeoni
*
*/
class GCoreEndpointReference {
private static final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
private static final String addressLocalName = "Address";
private static final String keyLocalName = "ResourceKey";
String address;
Element key;
static {
factory.setNamespaceAware(true);
}
GCoreEndpointReference(EndpointReference reference) {
this(serialise(reference));
}
GCoreEndpointReference(String reference) {
try {
Document document = factory.newDocumentBuilder().parse(new InputSource(new StringReader(reference)));
NodeList addresses = document.getElementsByTagNameNS("*", addressLocalName);
if (addresses.getLength() == 0)
throw new RuntimeException("reference does not contain an address");
address = addresses.item(0).getTextContent();
NodeList keys = document.getElementsByTagNameNS("*", keyLocalName);
if (keys.getLength() >1)
throw new RuntimeException("reference contains " + keys.getLength() + " resource key(s)");
if (keys.getLength()==1)
key = (Element) keys.item(0);
} catch (Exception e) {
throw new IllegalArgumentException("reference is not a gCore reference", e);
}
}
@Override
public String toString() {
return address + ":" + key.getTextContent();
}
// helper
private static String serialise(EndpointReference reference) {
StringWriter writer = new StringWriter();
reference.writeTo(new StreamResult(writer));
return writer.toString();
}
}

@ -0,0 +1,127 @@
package org.gcube.common.clients.stubs.jaxws;
import java.util.Iterator;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.gcube.common.scope.api.ScopeProvider;
/**
* A {@link SOAPHandler} that adds gCube headers to outgoing calls.
*
* @author Fabio Simeoni
*
*/
public class GCoreJAXWSHandler implements SOAPHandler<SOAPMessageContext> {
/** Namespace of scope-related headers */
public static final String SCOPE_NS = "http://gcube-system.org/namespaces/scope";
/** Name of the scope call header. */
public static final String SCOPE_HEADER_NAME = "scope";
public static final QName SCOPE_QNAME = new QName(SCOPE_NS,SCOPE_HEADER_NAME);
/** Name of the service class call header. */
public static final String SERVICECLASS_HEADER_NAME = "serviceClass";
public static final QName SERVICECLASS_QNAME = new QName(SCOPE_NS,SERVICECLASS_HEADER_NAME);
/** Name of the service name call header. */
public static final String SERVICENAME_HEADER_NAME = "serviceName";
public static final QName SERVICENAME_QNAME = new QName(SCOPE_NS,SERVICENAME_HEADER_NAME);
/** Name of the scope call header. */
public static final String CALLER_HEADER_NAME = "caller";
/** Namespace of scope-related headers */
public static final String CALLER_NS = "http://gcube-system.org/namespaces/caller";
public static final QName CALLER_QNAME = new QName(CALLER_NS,CALLER_HEADER_NAME);
private final GCoreService<?> target;
GCoreJAXWSHandler(GCoreService<?> target) {
this.target=target;
}
public boolean handleMessage(SOAPMessageContext context) {
Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound)
try {
SOAPHeader header = context.getMessage().getSOAPPart().getEnvelope().getHeader();
if (header == null)
header = context.getMessage().getSOAPPart().getEnvelope().addHeader();
addCurrentScope(header);
addTargetServiceCoordinates(header);
addClientIdentity(header);
correctWSAddressingHeader(header);
} catch (Exception e) {
throw new RuntimeException("cannot configure outgoing message", e);
}
return true;
};
public Set<QName> getHeaders() {
return null;
}
public boolean handleFault(SOAPMessageContext context) {
return true;
}
public void close(MessageContext context) {}
//helper
private void addClientIdentity(SOAPHeader header) throws Exception {
addHeader(header,CALLER_QNAME, target.clientId());
}
//helper
private void addTargetServiceCoordinates(SOAPHeader header) throws Exception {
addHeader(header,SERVICECLASS_QNAME, target.gcubeClass());
addHeader(header,SERVICENAME_QNAME, target.gcubeName());
}
//helper
private void addCurrentScope(SOAPHeader header) throws Exception {
String scope = ScopeProvider.instance.get();
if (scope==null)
throw new IllegalStateException("no scope is defined for this call");
addHeader(header,SCOPE_QNAME, scope);
}
//helper: adapts ws-addressing headers to member submission's. brutal but there is no support for member submission in
//jdk 1.6
private void correctWSAddressingHeader(SOAPHeader header) throws Exception {
Iterator<?> it = header.examineAllHeaderElements();
while (it.hasNext()) {
SOAPHeaderElement e = (SOAPHeaderElement) it.next();
if (e.getElementQName().getNamespaceURI().equals("http://www.w3.org/2005/08/addressing")) {
e.detachNode();
addHeader(header,new QName("http://schemas.xmlsoap.org/ws/2004/03/addressing",e.getElementQName().getLocalPart()), e.getTextContent());
}
}
}
// helper
private void addHeader(SOAPHeader header,QName name, String value) throws Exception {
header.addHeaderElement(name).addTextNode(value);
}
}

@ -0,0 +1,93 @@
package org.gcube.common.clients.stubs.jaxws;
import java.net.InetAddress;
import javax.xml.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Groups information required to generate a stub for a gCore service.
*
* @author Fabio Simeoni
*
* @param <T> the interface of the stub
*
* @see StubFactory
*/
public final class GCoreService<T> {
Logger logger = LoggerFactory.getLogger(GCoreService.class);
private final String serviceClass;
private final String serviceName;
private String identity;
private final QName name;
private final Class<T> type;
/**
* Creates an instance for a given gCore service.
*
* @param gcubeClass the gCube class of the service, as specified in its gCube profile
* @param gcubeName the gCUbe name of the service, as specified in its gCube profile
* @param qname the qualified name of the service, as specified in its WSDL
* @param type the interface of the service stub
*/
public GCoreService(String gcubeClass, String gcubeName, QName qname, Class<T> type) {
this.serviceClass=gcubeClass;
this.serviceName=gcubeName;
this.name=qname;
this.type=type;
try {
this.identity=InetAddress.getLocalHost().getHostAddress();
}
catch(Exception e) {
logger.warn("cannot determine local address as a client identity",e);
this.identity="uknown";
}
}
/**
* Returns the gCube class of the service,, as specified in the service profile.
* @return the name
*/
public String gcubeClass() {
return serviceClass;
}
/**
* Returns the gCube name of the service, as specified in the service profile.
* @return the name
*/
public String gcubeName() {
return serviceName;
}
/**
* Returns the identity of the service client.
* @return the client identity
*/
public String clientId() {
return identity;
}
/**
* Returns the name of the service, as specified in the service WSDL.
* @return the class.
*/
public QName qName() {
return name;
}
/**
* Returns the interface of the service stub.
* @return the interface
*/
public Class<T> type() {
return type;
}
}

@ -0,0 +1,61 @@
package org.gcube.common.clients.stubs.jaxws;
import static org.gcube.common.clients.stubs.jaxws.JAXWSUtils.*;
import javax.xml.namespace.QName;
import org.gcube.common.clients.stubs.jaxws.GCoreServiceDSL.CoordinateClause;
import org.gcube.common.clients.stubs.jaxws.GCoreServiceDSL.NameClause;
import org.gcube.common.clients.stubs.jaxws.GCoreServiceDSL.StubClause;
/**
* Builds {@link GCoreService} instances.
*
* @author Fabio Simeoni
*
*/
public class GCoreServiceBuilder implements NameClause, CoordinateClause, StubClause {
private QName name;
private String gcubeclass;
private String gcubename;
/**
* Starts the bulding process for a {@link GCoreService}.
* @return the service
*/
public static NameClause service() {
return new GCoreServiceBuilder();
}
@Override
public CoordinateClause withName(QName name) {
notNull("service name", name);
this.name=name;
return this;
}
@Override
public StubClause coordinates(String gcubeClass, String gcubeName) {
notNull("service class", gcubeClass);
notNull("service name", gcubeName);
this.gcubeclass=gcubeClass;
this.gcubename=gcubeName;
return this;
}
@Override
public <T> GCoreService<T> andInterface(Class<T> type) {
notNull("service interface", type);
return new GCoreService<T>(gcubeclass, gcubename, name, type);
}
}

@ -0,0 +1,64 @@
package org.gcube.common.clients.stubs.jaxws;
import javax.xml.namespace.QName;
/**
* The clauses of a simple DSL to build {@link GCoreService}.
*
* @author Fabio Simeoni
*
*/
public interface GCoreServiceDSL {
/**
* The clause that sets the name of the target service.
*
* @author Fabio Simeoni
*
*/
static interface NameClause {
/**
* Sets the qualified name of the target service.
*
* @param name the qualified name of the target service
* @return the next clause
*/
CoordinateClause withName(QName name);
}
/**
* The clause that sets the gCube coordinates of the target service.
*
* @author Fabio Simeoni
*
*/
static interface CoordinateClause {
/**
* Sets the gCube coordinates of the target service
* @param gcubeClass the gCube class of the target service
* @param gcubeName the gCube name of the target service
* @return
*/
StubClause coordinates(String gcubeClass, String gcubeName);
}
/**
* The clause that sets the stub interface of the target service.
*
* @author Fabio Simeoni
*
*/
static interface StubClause {
/**
* Sets the stub interface of the target service.
* @param type the interface
* @return the {@link GCoreService} that described the target service.
*/
<T> GCoreService<T> andInterface(Class<T> type);
}
}

@ -0,0 +1,66 @@
package org.gcube.common.clients.stubs.jaxws;
import java.util.Iterator;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.soap.DetailEntry;
import javax.xml.soap.SOAPFault;
import javax.xml.ws.soap.SOAPFaultException;
/**
* Library-wide utilities.
*
* @author Fabio Simeoni
*
*/
public class JAXWSUtils {
@XmlRootElement
public static class Empty{}
public static final Empty empty = new Empty();
/**
* Returns the remote cause of a {@link SOAPFaultException} as a {@link Throwable}.
*
* @param e the exception
* @return a {@link Throwable} deserialised from the stacktrace found in the {@link SOAPFault} inside the exception,
* or the input exception itself if the stacktrace cannot be found.
*/
public static Throwable remoteCause(SOAPFaultException e) {
// if we cannt do better, we throw this
Throwable throwable = e;
SOAPFault faultBean = e.getFault();
// if a serialised stacktrace is available, parse it and convert it into a throwable
Iterator<?> details = faultBean.getDetail().getDetailEntries();
while (details.hasNext()) {
DetailEntry detail = (DetailEntry) details.next();
String ns = detail.getNamespaceURI();
String local = detail.getLocalName();
boolean match = ns != null && ns.equals("http://gcube-system.org") && local != null
&& local.equals("stacktrace");
if (match)
try {
ExceptionProxy proxy = ExceptionProxy.newInstance(detail);
throwable = proxy.toThrowable();
} catch (Throwable t) {
throwable = new Exception("could not parse remote fault", t);
}
}
return throwable;
}
static void notNull(String message,Object o) {
if (o==null)
throw new IllegalArgumentException(o+" cannot be null");
}
}

@ -0,0 +1,107 @@
package org.gcube.common.clients.stubs.jaxws;
import java.util.LinkedHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Privately used by a {@link StubFactory}, caches {@link Service} instances for services with given names.
* <p>
* The cache is LRU and bounded at a maximum size of {@link LRUCache#max}. It is also thread-safe, though synchronisation
* occurs on a per-key basis.
*
* @author Fabio Simeoni
* @see StubFactory
*/
class StubCache {
private static final Logger log = LoggerFactory.getLogger(StubCache.class);
private volatile LRUCache cache = new LRUCache();
//holds key locks for LRU map
private ConcurrentHashMap<QName,Lock> nameLocks = new ConcurrentHashMap<QName, Lock>();
Service get(QName name,Callable<Service> task) {
//obtain a lock for current key
Lock nameLock = lockFor(name);
nameLock.lock();
try {
Service service = cache.get(name);
if (service==null)
try {
service= task.call();
log.trace("caching stub for "+name);
cache.put(name,service);
}
catch(Exception e) {
throw new RuntimeException("could not build service",e);
}
else {
log.trace("using cached stub for "+name);
}
return service;
}
finally {
nameLock.unlock();
}
}
//helper
private Lock lockFor(QName name) {
Lock nameLock = nameLocks.get(name);
//no need to create a new lock a priori
if (nameLock==null) {
Lock newLock = new ReentrantLock();
//get name lock, creating it if it doesn't exist
//this is where we first synchronise: second-come thread waits for new one to have put a lock
//then it gets that same shared lock
nameLock = nameLocks.putIfAbsent(name,newLock);
nameLock = nameLock == null? newLock : nameLock;
}
return nameLock;
}
private class LRUCache extends LinkedHashMap<QName,Service> {
private static final long serialVersionUID = 1L;
public static final int max = 50;
public LRUCache() {
//use defaults, but indicate accessor-order as 3rd parameter (rather than default insertion order)
super(16,.75f,true);
}
@Override
protected boolean removeEldestEntry(java.util.Map.Entry<QName, Service> eldest) {
if (size()>=max) {
nameLocks.remove(eldest.getKey());
return true;
}
return false;
}
}
}

@ -0,0 +1,189 @@
package org.gcube.common.clients.stubs.jaxws;
import static org.gcube.common.clients.stubs.jaxws.JAXWSUtils.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.concurrent.Callable;
import javax.xml.namespace.QName;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.Service;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
import org.gcube.common.clients.stubs.jaxws.StubFactoryDSL.AtClause;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Generates JAXWS stubs for endpoints or instances of gCore service at given addresses.
*
* <p>
* Factories are instantiated with descriptions of target services (cf. {@link GCoreService}) and use them to perform the
* following tasks:
*
* <ul>
* <li>interact with the JAXWS APIs to dynamically implement stub interfaces.
* <li>resolve service WSDLs to enable the interactions above, as per JAXWS client model.
* <li>avoid unnecessary WSDL resolution through a shared LRU cache.
* <li>configure stub implementations with JAXWS handlers which turn outgoing service calls into gCore calls (i.e. add headers for current scope and service coordinates).
* </ul>
*
* Note that all factories can be configured to go through a proxy, e.g. for debugging purposes (cf.
* {@link StubFactory#setProxy(String, int)}).
* <p>
*
* @author Fabio Simeoni
* @see StubCache
* @see GCoreJAXWSHandler
*/
public class StubFactory<T> implements StubFactoryDSL.AtClause<T> {
private static final Logger log = LoggerFactory.getLogger(StubFactory.class);
// note that using the standard http.hostProxy and http.hostPort would have been clearner, but it creates problems,
// for example when wsdls with imports must be resolved. better to offer ad-hoc support with confined effect in the JVM.
private static String proxyHost;
private static int proxyPort;
private static StubCache cache = new StubCache();
private final GCoreService<T> target;
/**
* Creates an instance for a given {@link GCoreService}.
*
* @param target the service
*/
public StubFactory(GCoreService<T> target) {
notNull("gCore Service", target);
this.target = target;
}
public T at(EndpointReference reference) {
notNull("instance reference", reference);
GCoreEndpointReference epr = new GCoreEndpointReference(reference);
String proxied = setProxyOn(epr.address);
W3CEndpointReferenceBuilder builder = new W3CEndpointReferenceBuilder().address(proxied);
reference = epr.key==null?
builder.build():
builder.referenceParameter(epr.key).build();
return at(proxied,reference,new AddressingFeature());
}
public T at(URI address) {
notNull("endpoint address", address);
//build reference from address
EndpointReference reference = new W3CEndpointReferenceBuilder().address(address.toString()).build();
return at(reference);
}
private T at(String endpointAddress, EndpointReference reference, AddressingFeature ... features) {
try {
// get JAXWS service from endpoint address
Service service = buildService(endpointAddress+"?wsdl", target.qName());
// get JAXWS stub
T stub = service.getPort(reference,target.type(),features);
BindingProvider provider = (BindingProvider) stub;
// configure stub for gCube calls
registerHandler(provider, target);
return stub;
} catch (Exception e) {
throw new RuntimeException("could not configure discovery service", e);
}
}
/**
* Creates a stub for a given {@link GCoreService}
*
* @param service information about the service
* @return the next clause for the creation of the stub
*/
public static <T> AtClause<T> stubFor(GCoreService<T> service) {
return new StubFactory<T>(service);
}
// helper
private synchronized Service buildService(final String wsdlAddress, final QName name) throws Exception {
Callable<Service> task = new Callable<Service>() {
@Override
public Service call() throws Exception {
log.info("fetching wsdl for {} at {}", name.getLocalPart(),wsdlAddress);
return Service.create(new URL(wsdlAddress), name);
}
};
Service service = cache.get(name,task);
return service;
}
// helper
private void registerHandler(BindingProvider provider, GCoreService<?> context) {
Binding binding = provider.getBinding();
@SuppressWarnings("rawtypes")
List<Handler> currentChain = binding.getHandlerChain();
GCoreJAXWSHandler handler = new GCoreJAXWSHandler(context);
currentChain.add(handler);
binding.setHandlerChain(currentChain);
}
/**
* Configures a proxy for client interactions through this factory.
*
* @param host the proxy host
* @return port the proxy port
*/
public static void setProxy(String host, int port) {
StubFactory.proxyHost = host;
StubFactory.proxyPort = port;
}
// helper
private String setProxyOn(String address) {
if (proxyHost != null)
try {
//pass through URI for replacing host and port with proxy's
URI u = URI.create(address);
return new URI(u.getScheme(), u.getUserInfo(), proxyHost, Integer.valueOf(proxyPort), u.getPath(),
u.getQuery(), u.getFragment()).toString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
return address;
}
}

@ -0,0 +1,39 @@
package org.gcube.common.clients.stubs.jaxws;
import java.net.URI;
import javax.xml.ws.EndpointReference;
/**
* Simple DSL for the {@link StubFactory}
*
* @author Fabio Simeoni
*
*/
public interface StubFactoryDSL {
/**
* Selects the address of the service endpoint or service instance.
*
* @author Fabio Simeoni
*
* @param <T>
*/
interface AtClause<T> {
/**
* Returns a stub for a service endpoint at a given address.
* @param address the address
* @return the stub
*/
T at(URI address);
/**
* Returns a stub for a service endpoint or service instance at a given address.
* @param ref a reference to the endpoint or instance
* @return the stub
*/
T at(EndpointReference ref);
}
}

@ -0,0 +1,258 @@
package org.acme;
import static org.acme.jaxws.stubs.StatefulStub.*;
import static org.acme.jaxws.stubs.StatelessStub.*;
import static org.gcube.common.clients.stubs.jaxws.StubFactory.*;
import static org.junit.Assert.*;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.soap.SOAPFaultException;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import org.acme.jaxws.stubs.BarInput;
import org.acme.jaxws.stubs.BarOutput;
import org.acme.jaxws.stubs.FooException;
import org.acme.jaxws.stubs.StatefulStub;
import org.acme.jaxws.stubs.StatelessStub;
import org.acme.jaxws.stubs.Types.AnyElement;
import org.acme.jaxws.stubs.Types.ChoiceOne;
import org.acme.jaxws.stubs.Types.PolyWrapped;
import org.acme.jaxws.stubs.Types.Sometype;
import org.acme.jaxws.stubs.Types.Subone;
import org.acme.jaxws.stubs.Types.Subtwo;
import org.acme.jaxws.stubs.VoidWrapper;
import org.gcube.common.clients.stubs.jaxws.JAXWSUtils;
import org.gcube.common.mycontainer.Deployment;
import org.gcube.common.mycontainer.Gar;
import org.gcube.common.mycontainer.MyContainerTestRunner;
import org.gcube.common.scope.api.ScopeProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@RunWith(MyContainerTestRunner.class)
public class StubTest {
@Deployment
static Gar testservice = new Gar("test-service").addConfigurations("src/test/resources/test-service/etc").addInterfaces("src/test/resources/test-service/wsdl");
static StatelessStub stub;
@BeforeClass
public static void setup() {
//setProxy("localhost",8081); //comment after on-the-wire analysis
ScopeProvider.instance.set("/gcube/devsec");
stub = stubFor(stateless).at(URI.create("http://localhost:9999/wsrf/services/acme/service/stateless"));
}
@Test
public void fooTest() {
String input = "input";
String output = stub.foo(input);
assertEquals(input, output);
}
@Test
public void fooWrappedTest() {
String input = "input";
String output = stub.fooWrapped(input);
assertEquals(input, output);
}
@Test
public void fooMixedTest() {
String input = "input";
String output = stub.fooMixed(input).ret;
assertEquals(input, output);
}
@Test
public void fooBulkTest() {
String[] input = new String[]{"1","2","3"};
String output = stub.fooBulk(Arrays.asList(input));
assertEquals(Arrays.deepToString(input), output);
}
@Test
public void fooContingencyTest() {
try {
stub.fooFault("contingency");
fail();
}
catch(FooException e) {
}
}
@Test
public void fooOutageTest() throws Exception {
try {
stub.fooFault("outage");
fail();
}
catch(SOAPFaultException e) {
}
}
@Test
public void fooProperOutageTest() throws Exception {
try {
stub.fooFault("proper");
fail();
}
catch(SOAPFaultException e) {
new RuntimeException(JAXWSUtils.remoteCause(e)).printStackTrace();
}
}
@Test
public void barTest() throws Exception {
String input = "input";
BarInput request = new BarInput();
request.in1 = input;
request.in2 = 3;
BarOutput response = stub.bar(request);
List<String> expected = Arrays.asList(input,input);
assertEquals(expected, response.output);
}
@Test
public void bazTest() {
String response = stub.baz(new VoidWrapper());
assertNotNull(response);
}
@Test
public void nothingTest() {
stub.nothing();
}
@Test
public void barWrappedTest() throws Exception {
String in1 = "input";
Integer in2 = 3;
List<String> response = stub.barWrapped(in1,in2);
List<String> expected = Arrays.asList(in1,in1);
assertEquals(expected, response);
}
@Test
public void createWithEPRTest() throws Exception {
W3CEndpointReference ref = stub.create("input");
assertNotNull(ref);
}
@Test
public void callsTest() throws Exception {
EndpointReference ref = stub.create("input");
StatefulStub stub = stubFor(stateful).at(ref);
assertNotNull(stub.calls());
}
@Test
public void anyTypeTest() throws Exception {
String ref = stub.any("input");
assertEquals(String.class.getName(),ref);
Sometype st = new Sometype();
st.some="hello";
ref = stub.any(st);
assertEquals(org.acme.sample.stubs.Sometype.class.getName(),ref);
}
@Test
public void anyElementTest() throws Exception {
Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element root = d.createElement("root");
root.appendChild(d.createElement("empty"));
root.setAttribute("foo", "val");
AnyElement e = new AnyElement();
e.some=root;
stub.anyElement(e);
}
@Test
public void poly() throws Exception {
stub.poly(new Subone());
stub.poly(new Subtwo());
}
@Test
public void polyWrapped() throws Exception {
Subone one = new Subone();
one.one="one";
PolyWrapped wrapped = new PolyWrapped();
wrapped.param=one;
stub.polyWrapped(wrapped);
}
@Test
public void choice() throws Exception {
Subone sub = new Subone();
ChoiceOne one = new ChoiceOne();
one.one=sub;
stub.choice(one);
}
}

@ -0,0 +1,15 @@
package org.acme.jaxws.stubs;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class BarInput {
@XmlElement
public String in1;
@XmlElement
public int in2;
}

@ -0,0 +1,13 @@
package org.acme.jaxws.stubs;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class BarOutput {
@XmlElement
public List<String> output;
}

@ -0,0 +1,13 @@
package org.acme.jaxws.stubs;
import javax.xml.ws.WebFault;
@WebFault(name="SampleFault")
public class FooException extends Exception {
private static final long serialVersionUID = 1L;
public FooException(String s) {
super(s);
}
}

@ -0,0 +1,33 @@
package org.acme.jaxws.stubs;
import static org.acme.jaxws.stubs.StatefulStub.*;
import static org.gcube.common.clients.stubs.jaxws.GCoreServiceBuilder.*;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import org.gcube.common.clients.stubs.jaxws.GCoreService;
@WebService(name=porttype,targetNamespace=porttypeNS)
public interface StatefulStub {
public static final String namespace = "http://acme.org/service";
public static final String localname = "StatefulService";
public static final QName name = new QName(namespace,localname);
public static final String porttypeNS = "http://acme.org";
static final String porttype = "StatefulPortType";
static final String port = "StatefulPortTypePort";
public static String service_class="samples";
public static String service_name="test-service";
static final GCoreService<StatefulStub> stateful = service().
withName(name).
coordinates(service_class,service_name).
andInterface(StatefulStub.class);
@WebResult(name="output")
String calls();
}

@ -0,0 +1,82 @@
package org.acme.jaxws.stubs;
import static javax.jws.soap.SOAPBinding.ParameterStyle.*;
import static org.acme.jaxws.stubs.StatelessStub.*;
import static org.gcube.common.clients.stubs.jaxws.GCoreServiceBuilder.*;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.namespace.QName;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import org.acme.jaxws.stubs.Types.AnyElement;
import org.acme.jaxws.stubs.Types.Base;
import org.acme.jaxws.stubs.Types.Choice;
import org.acme.jaxws.stubs.Types.MixedWrapper;
import org.acme.jaxws.stubs.Types.PolyWrapped;
import org.acme.jaxws.stubs.Types.Sometype;
import org.gcube.common.clients.stubs.jaxws.GCoreService;
@WebService(name=porttypeLN,targetNamespace=porttypeNS)
@SOAPBinding(parameterStyle=BARE)
@XmlSeeAlso(Sometype.class)
public interface StatelessStub {
public static final QName name = new QName("http://acme.org/service","StatelessService");
public static final String porttypeNS = "http://acme.org";
static final String porttypeLN = "StatelessPortType";
public static String service_class="samples";
public static String service_name="test-service";
static final GCoreService<StatelessStub> stateless = service().
withName(name).
coordinates(service_class,service_name).
andInterface(StatelessStub.class);
String foo(String s);
@SOAPBinding(parameterStyle=WRAPPED)
@WebResult(name="anything")
String fooWrapped(@WebParam(name="param") String s);
MixedWrapper fooMixed(String s);
@SOAPBinding(parameterStyle=WRAPPED)
@WebResult(name="return")
String fooBulk(@WebParam(name="param") List<String> elements);
String fooFault(String s) throws FooException;
String baz(VoidWrapper v);
@SOAPBinding(parameterStyle=WRAPPED)
void nothing();
BarOutput bar(BarInput s);
@SOAPBinding(parameterStyle=WRAPPED)
@WebMethod(operationName="bar")
@WebResult(name="output")
List<String> barWrapped(@WebParam(name="in1")String s,@WebParam(name="in2")int i);
W3CEndpointReference create(String s);
String any(Object o);
void anyElement(AnyElement e);
void poly(Base one);
void polyWrapped(PolyWrapped one);
public void choice(Choice c);
}

@ -0,0 +1,61 @@
package org.acme.jaxws.stubs;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import org.w3c.dom.Element;
public class Types {
public static class MixedWrapper{
@XmlElement(name="anything")
public String ret;
}
public static class AnyElement {
@XmlAnyElement
public Element some;
}
public static class Sometype {
@XmlElement
public String some;
}
public static class SomeElement {
@XmlAnyElement
public Element some;
}
@XmlRootElement
public static class PolyWrapped {
@XmlElement
public Base param;
}
@XmlSeeAlso({Subone.class,Subtwo.class})
public static class Base{}
@XmlRootElement
public static class Subone extends Base {
@XmlElement
public String one;
}
@XmlRootElement
public static class Subtwo extends Base {
@XmlElement
public String two;
}
@XmlSeeAlso({ChoiceOne.class})
public static abstract class Choice {}
public static class ChoiceOne extends Choice {
@XmlElement
public Subone one;
}
}

@ -0,0 +1,8 @@
package org.acme.jaxws.stubs;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class VoidWrapper {
}

@ -0,0 +1,39 @@
package org.acme.service;
import org.apache.axis.message.addressing.EndpointReferenceType;
import org.gcube.common.core.contexts.GCUBEStatefulPortTypeContext;
import org.gcube.common.core.faults.GCUBEFault;
import org.gcube.common.core.faults.GCUBEUnrecoverableException;
import org.gcube.common.core.porttypes.GCUBEPortType;
import org.gcube.common.core.state.GCUBEWSHome;
import org.gcube.common.core.state.GCUBEWSResource;
import org.gcube.common.core.state.GCUBEWSResourceKey;
import org.gcube.common.core.utils.logging.GCUBELog;
public class Factory extends GCUBEPortType {
GCUBELog logger = new GCUBELog(this);
@Override
protected ServiceContext getServiceContext() {
return ServiceContext.getContext();
}
public EndpointReferenceType create(String name) throws GCUBEFault {
//create/reuse the resource
try {
GCUBEStatefulPortTypeContext ptcxt = StatefulContext.getContext();
GCUBEWSHome home = ptcxt.getWSHome();
GCUBEWSResourceKey key = ptcxt.makeKey(name);
GCUBEWSResource ws = home.create(key,name);
ws.store();
return ws.getEPR();
} catch (Exception e) {
logger.error("unable to logon", e);
throw new GCUBEUnrecoverableException(e).toFault();
}
}
}

@ -0,0 +1,11 @@
package org.acme.service;
import org.gcube.common.core.contexts.GCUBEStatefulPortTypeContext;
import org.gcube.common.core.state.GCUBEWSHome;
public class Home extends GCUBEWSHome {
@Override
public GCUBEStatefulPortTypeContext getPortTypeContext() {return StatefulContext.getContext();}
}

@ -0,0 +1,50 @@
package org.acme.service;
import org.gcube.common.core.state.GCUBEWSResource;
import org.globus.wsrf.ResourceProperty;
public class Resource extends GCUBEWSResource {
private static final String NAME_RP_NAME = "Name";
/** Client visits.*/
int calls;
/** Client name. */
String name;
/**{@inheritDoc}*/
public void initialise(Object... args) throws Exception {
if (args == null || args.length!=1) throw new IllegalArgumentException();
this.setName((String) args[0]);
}
/** Returns the number of client visits.
* @return the visits.*/
public synchronized int getVisits() {return calls;}
/** Returns the client name.
* @return the name.*/
public synchronized String getName() {
return (String) this.getResourcePropertySet().get(NAME_RP_NAME).get(0);
}
/** Sets the client name.
* @params the name.*/
public synchronized void setName(String name) {
ResourceProperty property = this.getResourcePropertySet().get(NAME_RP_NAME);
property.clear();
property.add(name);
}
/**Sets the number of client visits.
* the visits.*/
protected synchronized void addVisit() {this.calls++;}
@Override
protected String[] getPropertyNames() {
return new String[]{NAME_RP_NAME};
}
}

@ -0,0 +1,25 @@
package org.acme.service;
import static org.acme.service.Utils.*;
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} */
protected String getJNDIName() {return NAME;}
}

@ -0,0 +1,35 @@
package org.acme.service;
import org.acme.sample.stubs.CallsResponse;
import org.gcube.common.core.porttypes.GCUBEPortType;
import org.gcube.common.core.types.VOID;
import org.globus.wsrf.ResourceException;
public class Stateful extends GCUBEPortType {
@Override
protected ServiceContext getServiceContext() {return ServiceContext.getContext();}
public CallsResponse calls(VOID voidType) {
try {
Resource resource = this.getResource();
return new CallsResponse(resource.getVisits()+" for "+resource.getName());
}
catch (Exception e) {
throw new RuntimeException("problem",e);
}
}
/**
*
* @return the stateful resource
* @throws ResourceException if no resource was found in the current context
*/
private Resource getResource() throws ResourceException {
return (Resource) StatefulContext.getContext().getWSHome().find();
}
}

@ -0,0 +1,34 @@
package org.acme.service;
import static org.acme.service.Utils.*;
import org.gcube.common.core.contexts.GCUBEServiceContext;
import org.gcube.common.core.contexts.GCUBEStatefulPortTypeContext;
public class StatefulContext extends GCUBEStatefulPortTypeContext {
/** Single context instance, created eagerly */
private static GCUBEStatefulPortTypeContext cache = new StatefulContext();
/**Create an instance, privately */
private StatefulContext(){}
/** Returns singleton context.
* @return the context. */
public static GCUBEStatefulPortTypeContext getContext() {return cache;}
/** {@inheritDoc} **/
public String getJNDIName() {return STATEFUL_NAME;}
/** {@inheritDoc} **/
public String getNamespace() {return NS;}
/** {@inheritDoc} **/
public GCUBEServiceContext getServiceContext() {return ServiceContext.getContext();}
}

@ -0,0 +1,158 @@
/**
*
*/
package org.acme.service;
import java.io.StringWriter;
import java.util.Arrays;
import javax.xml.namespace.QName;
import org.acme.sample.stubs.AnyElement;
import org.acme.sample.stubs.AnyElementResponse;
import org.acme.sample.stubs.Bar;
import org.acme.sample.stubs.BarResponse;
import org.acme.sample.stubs.Base;
import org.acme.sample.stubs.Choice;
import org.acme.sample.stubs.ChoiceResponse;
import org.acme.sample.stubs.FooBulk;
import org.acme.sample.stubs.FooBulkResponse;
import org.acme.sample.stubs.FooWrapped;
import org.acme.sample.stubs.FooWrappedResponse;
import org.acme.sample.stubs.Nothing;
import org.acme.sample.stubs.PolyResponse;
import org.acme.sample.stubs.PolyWrapped;
import org.acme.sample.stubs.SampleFault;
import org.apache.axis.message.addressing.EndpointReferenceType;
import org.gcube.common.core.contexts.GCUBEServiceContext;
import org.gcube.common.core.contexts.GCUBEStatefulPortTypeContext;
import org.gcube.common.core.faults.FaultUtils;
import org.gcube.common.core.faults.GCUBEFault;
import org.gcube.common.core.porttypes.GCUBEPortType;
import org.gcube.common.core.state.GCUBEWSHome;
import org.gcube.common.core.state.GCUBEWSResource;
import org.gcube.common.core.state.GCUBEWSResourceKey;
import org.gcube.common.core.types.VOID;
import org.globus.wsrf.encoding.ObjectSerializer;
/**
* @author Fabio Simeoni
*
*/
public class Stateless extends GCUBEPortType {
public String foo(String s) {
return s;
}
public FooWrappedResponse fooWrapped(FooWrapped wrapped) {
return new FooWrappedResponse(wrapped.getParam());
}
public FooWrappedResponse fooMixed(String s) {
return new FooWrappedResponse(s);
}
public FooBulkResponse fooBulk(FooBulk bulk) {
System.out.println(Arrays.asList(bulk.getParam()));
return new FooBulkResponse(Arrays.deepToString(bulk.getParam()));
}
public Nothing nothing(Nothing n) {
System.err.println("invoked NOTHING "+n);
return new Nothing();
}
public String fooFault(String flag) throws SampleFault, GCUBEFault {
if (flag.equals("contingency"))
throw new SampleFault();
else if (flag.equals("proper"))
throw FaultUtils.newFault(new GCUBEFault(), new RuntimeException("generic problem"));
else
throw new RuntimeException("generic problem");
}
public BarResponse bar(Bar s) {
return new BarResponse(new String[] { s.getIn1(), s.getIn1() });
}
public String baz(VOID v) {
return "called";
}
public EndpointReferenceType create(String input) {
try {
GCUBEStatefulPortTypeContext ptcxt = StatefulContext.getContext();
GCUBEWSHome home = ptcxt.getWSHome();
GCUBEWSResourceKey key = ptcxt.makeKey(input);
GCUBEWSResource ws = home.create(key, input);
ws.store();
return ws.getEPR();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String createAsString(String input) {
try {
GCUBEStatefulPortTypeContext ptcxt = StatefulContext.getContext();
GCUBEWSHome home = ptcxt.getWSHome();
GCUBEWSResourceKey key = ptcxt.makeKey(input);
GCUBEWSResource ws = home.create(key, input);
ws.store();
StringWriter w = new StringWriter();
ObjectSerializer.serialize(w,ws.getEPR(), new QName("http://foo","test"));
return w.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String any(Object o) {
System.err.println(o);
return o.getClass().getName();
}
public AnyElementResponse anyElement(AnyElement o) {
System.out.println(Arrays.deepToString(o.get_any()));
return new AnyElementResponse();
}
public PolyResponse poly(Base b) {
System.err.println(b.getClass());
return new PolyResponse();
}
public PolyResponse polyWrapped(PolyWrapped w) {
System.err.println(w.getParam().getClass());
return new PolyResponse();
}
public ChoiceResponse choice(Choice c) {
System.err.println("one:"+c.getOne());
System.err.println("two:"+c.getTwo());
return new ChoiceResponse();
}
/** {@inheritDoc} */
@Override
public GCUBEServiceContext getServiceContext() {
return ServiceContext.getContext();
}
}

@ -0,0 +1,28 @@
package org.acme.service;
import static org.acme.service.Utils.*;
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 StatelessContext cache = new StatelessContext();
private StatelessContext(){}
/** Returns cached instance */
public static StatelessContext getContext() {return cache;}
/**{@inheritDoc}*/
public String getJNDIName() {return STATELESS_NAME;}
/** {@inheritDoc}*/
public String getNamespace() {return NS;}
/** {@inheritDoc}*/
public GCUBEServiceContext getServiceContext() {return ServiceContext.getContext();}
}

@ -0,0 +1,17 @@
/**
*
*/
package org.acme.service;
/**
* @author Fabio Simeoni
*
*/
public class Utils {
public static final String NS="http://acme.org/service";
public static final String NAME="acme/service";
public static final String STATELESS_NAME="acme/service/stateless";
public static final String STATEFUL_NAME="acme/service/stateful";
}

@ -0,0 +1,10 @@
log4j.appender.ROOT=org.apache.log4j.ConsoleAppender
log4j.appender.ROOT.layout=org.apache.log4j.PatternLayout
log4j.appender.ROOT.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %c{2} [%t,%M:%L] %m%n
log4j.rootLogger=DEBUG,ROOT
log4j.appender.SAMPLE=org.apache.log4j.ConsoleAppender
log4j.appender.SAMPLE.layout=org.apache.log4j.PatternLayout
log4j.appender.SAMPLE.layout.ConversionPattern=[SAMPLE] %d{HH:mm:ss,SSS} %-5p %c{2} [%t,%M:%L] %m%n
log4j.category.org.acme=TRACE,SAMPLE

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<jndiConfig xmlns="http://wsrf.globus.org/jndi/config">
<service name="acme/service">
<environment name="configDir" value="@config.dir@" type="java.lang.String"
override="false" />
</service>
<service name="acme/service/stateless"/>
<service name="acme/service/stateful">
<resource name="home" type="org.acme.service.Home">
<resourceParams>
<parameter>
<name>factory</name>
<value>org.globus.wsrf.jndi.BeanFactory</value>
</parameter>
<parameter>
<name>resourceClass</name>
<value>org.acme.service.Resource</value>
</parameter>
</resourceParams>
</resource>
</service>
</jndiConfig>

@ -0,0 +1,32 @@
<?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/service/stateless" provider="Handler" use="literal"
style="document">
<parameter name="className" value="org.acme.service.Stateless" />
<wsdlFile>share/schema/test-service/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" />
<beanMapping xmlns:ns="http://acme.org" qname="ns:subone" type="java:org.acme.sample.stubs.Subone" />
<beanMapping xmlns:ns="http://acme.org" qname="ns:subtwo" type="java:org.acme.sample.stubs.Subtwo" />
<beanMapping xmlns:ns="http://acme.org" qname="ns:sometype" type="java:org.acme.sample.stubs.Sometype" />
</service>
<service name="acme/service/stateful" provider="Handler" use="literal"
style="document">
<parameter name="className" value="org.acme.service.Stateful" />
<wsdlFile>share/schema/test-service/Stateful_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="providers" value="GCUBEProvider" />
</service>
</deployment>

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<Resource>
<ID></ID>
<Type>Service</Type>
<Profile>
<Class>samples</Class>
<Name>test-service</Name>
<Version>1.0.0</Version>
<Packages>
<Main>
<Name>test-service</Name>
<Version>1.0.0-SNAPSHOT</Version>
<MavenCoordinates>
<groupId>org.gcube.samples</groupId>
<artifactId>test-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
</MavenCoordinates>
<GARArchive>test-service-1.0.0-SNAPSHOT.gar</GARArchive>
<PortType>
<Name>acme/sample/stateless</Name>
</PortType>
</Main>
<Software>
<Name>test-service-stubs</Name>
<Version>1.0.0-SNAPSHOT</Version>
<MavenCoordinates>
<groupId>org.gcube.samples</groupId>
<artifactId>test-service-stubs</artifactId>
<version>1.0.0-SNAPSHOT</version>
</MavenCoordinates>
<Type>library</Type>
<Files>
<File>test-service-stubs-1.0.0-SNAPSHOT.jar</File>
</Files>
</Software>
</Packages>
</Profile>
</Resource>

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="Stateful"
targetNamespace="http://acme.org"
xmlns:tns="http://acme.org"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdlpp="http://www.globus.org/namespaces/2004/10/WSDLPreprocessor"
xmlns:wsrp="http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd"
xmlns:coretypes="http://gcube-system.org/namespaces/common/core/types"
xmlns:corefaults="http://gcube-system.org/namespaces/common/core/faults"
xmlns:provider="http://gcube-system.org/namespaces/common/core/porttypes/GCUBEProvider">
<import namespace="http://gcube-system.org/namespaces/common/core/porttypes/GCUBEProvider" location="../gcube/common/core/providers/GCUBEProvider.wsdl"/>
<import namespace="http://gcube-system.org/namespaces/common/core/faults" location="../gcube/common/core/faults/GCUBEFaults.wsdl"/>
<types>
<xsd:schema targetNamespace="http://acme.org">
<xsd:import namespace="http://gcube-system.org/namespaces/common/core/types" schemaLocation="../gcube/common/core/types/GCUBETypes.xsd"/>
<xsd:element name="calls" type="coretypes:VOID" />
<xsd:element name="callsResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="output" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="callsInputMessage">
<part name="request" element="tns:calls"/>
</message>
<message name="callsOutputMessage">
<part name="response" element="tns:callsResponse"/>
</message>
<portType name="StatefulPortType" wsdlpp:extends="provider:GCUBEProvider">
<operation name="calls">
<input message="tns:callsInputMessage"/>
<output message="tns:callsOutputMessage"/>
</operation>
</portType>
</definitions>

@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="Stateless"
targetNamespace="http://acme.org"
xmlns:tns="http://acme.org"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:coretypes="http://gcube-system.org/namespaces/common/core/types"
xmlns:corefaults="http://gcube-system.org/namespaces/common/core/faults"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing">
<import namespace="http://gcube-system.org/namespaces/common/core/faults" location="../gcube/common/core/faults/GCUBEFaults.wsdl"/>
<types>
<xsd:schema targetNamespace="http://acme.org">
<xsd:import namespace="http://schemas.xmlsoap.org/ws/2004/03/addressing" schemaLocation="../ws/addressing/WS-Addressing.xsd" />
<xsd:import namespace="http://gcube-system.org/namespaces/common/core/types" schemaLocation="../gcube/common/core/types/GCUBETypes.xsd"/>
<xsd:element name="foo" type="xsd:string" />
<xsd:element name="fooResponse" type="xsd:string" />
<xsd:element name="fooWrapped">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="param" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="fooWrappedResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="anything" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="fooMixed" type="xsd:string" />
<xsd:element name="fooMixedResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="return" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="fooBulk">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="param" maxOccurs="unbounded" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="fooBulkResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="return" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="bar">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="in1" type="xsd:string"/>
<xsd:element name="in2" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="barResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="output" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="baz" type="coretypes:VOID" />
<xsd:element name="bazResponse" type="xsd:string"/>
<xsd:element name="nothing">
<xsd:complexType />
</xsd:element>
<xsd:element name="create" type="xsd:string" />
<xsd:element name="createResponse" type="wsa:EndpointReferenceType"/>
<xsd:element name="createAsStringResponse" type="xsd:string"/>
<xsd:element name="SampleFault">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="corefaults:GCUBEUnrecoverableFault"/>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="any" type="xsd:anyType" />
<xsd:element name="anyResponse" type="xsd:string"/>
<xsd:element name="poly" type="tns:base"/>
<xsd:element name="polyResponse">
<xsd:complexType />
</xsd:element>
<xsd:element name="polyWrapped">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="param" type="tns:base"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="base" abstract="true" />
<xsd:complexType name="subone">
<xsd:complexContent>
<xsd:extension base="tns:base">
<xsd:sequence>
<xsd:element name="one" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="subtwo">
<xsd:complexContent>
<xsd:extension base="tns:base">
<xsd:sequence>
<xsd:element name="two" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="Sometype">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="some" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="anyElement">
<xsd:complexType>
<xsd:sequence>
<xsd:any/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="anyElementResponse">
<xsd:complexType />
</xsd:element>
<xsd:element name="choice">
<xsd:complexType>
<xsd:choice>
<xsd:element name="one" type="tns:subone"/>
<xsd:element name="two" type="tns:subtwo"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
<xsd:element name="choiceResponse">
<xsd:complexType />
</xsd:element>
</xsd:schema>
</types>
<message name="fooWrappedInputMessage">
<part name="request" element="tns:fooWrapped"/>
</message>
<message name="fooWrappedOutputMessage">
<part name="response" element="tns:fooWrappedResponse"/>
</message>
<message name="fooMixedInputMessage">
<part name="request" element="tns:fooMixed"/>
</message>
<message name="fooMixedOutputMessage">
<part name="response" element="tns:fooMixedResponse"/>
</message>
<message name="fooInputMessage">
<part name="request" element="tns:foo"/>
</message>
<message name="fooOutputMessage">
<part name="response" element="tns:fooResponse"/>
</message>
<message name="fooBulkInputMessage">
<part name="request" element="tns:fooBulk"/>
</message>
<message name="fooBulkOutputMessage">
<part name="response" element="tns:fooBulkResponse"/>
</message>
<message name="fooFaultInputMessage">
<part name="request" element="tns:foo"/>
</message>
<message name="fooFaultOutputMessage">
<part name="response" element="tns:fooResponse"/>
</message>
<message name="barInputMessage">
<part name="request" element="tns:bar"/>
</message>
<message name="barOutputMessage">
<part name="response" element="tns:barResponse"/>
</message>
<message name="bazInputMessage">
<part name="request" element="tns:baz"/>
</message>
<message name="bazOutputMessage">
<part name="response" element="tns:bazResponse"/>
</message>
<message name="emptyMessage">
<part name="part" element="tns:nothing"/>
</message>
<message name="createInputMessage">
<part name="request" element="tns:create"/>
</message>
<message name="createOutputMessage">
<part name="response" element="tns:createResponse"/>
</message>
<message name="createAsStringOutputMessage">
<part name="response" element="tns:createAsStringResponse"/>
</message>
<message name="anyElementInputMessage">
<part name="response" element="tns:anyElement"/>
</message>
<message name="anyElementOutputMessage">
<part name="response" element="tns:anyElementResponse"/>
</message>
<message name="polyInputMessage">
<part name="response" element="tns:poly"/>
</message>
<message name="polyOutputMessage">
<part name="response" element="tns:polyResponse"/>
</message>
<message name="polyWrappedInputMessage">
<part name="request" element="tns:polyWrapped"/>
</message>
<message name="anyInputMessage">
<part name="request" element="tns:any"/>
</message>
<message name="anyOutputMessage">
<part name="response" element="tns:anyResponse"/>
</message>
<message name="SampleFaultMessage">
<part name="fault" element="tns:SampleFault"/>
</message>
<message name="choiceInputMessage">
<part name="request" element="tns:choice"/>
</message>
<message name="choiceOutputMessage">
<part name="response" element="tns:choiceResponse"/>
</message>
<portType name="StatelessPortType">
<operation name="foo">
<input message="tns:fooInputMessage"/>
<output message="tns:fooOutputMessage"/>
</operation>
<operation name="fooWrapped">
<input message="tns:fooWrappedInputMessage"/>
<output message="tns:fooWrappedOutputMessage"/>
</operation>
<operation name="fooMixed">
<input message="tns:fooMixedInputMessage"/>
<output message="tns:fooMixedOutputMessage"/>
</operation>
<operation name="fooBulk">
<input message="tns:fooBulkInputMessage"/>
<output message="tns:fooBulkOutputMessage"/>
</operation>
<operation name="fooFault">
<input message="tns:fooFaultInputMessage"/>
<output message="tns:fooFaultOutputMessage"/>
<fault name="sampleFault" message="tns:SampleFaultMessage"/>
</operation>
<operation name="bar">
<input message="tns:barInputMessage"/>
<output message="tns:barOutputMessage"/>
</operation>
<operation name="baz">
<input message="tns:bazInputMessage"/>
<output message="tns:bazOutputMessage"/>
</operation>
<operation name="nothing">
<input message="tns:emptyMessage"/>
<output message="tns:emptyMessage"/>
</operation>
<operation name="create">
<input message="tns:createInputMessage"/>
<output message="tns:createOutputMessage"/>
</operation>
<operation name="createAsString">
<input message="tns:createInputMessage"/>
<output message="tns:createAsStringOutputMessage"/>
</operation>
<operation name="any">
<input message="tns:anyInputMessage"/>
<output message="tns:anyOutputMessage"/>
</operation>
<operation name="poly">
<input message="tns:polyInputMessage"/>
<output message="tns:polyOutputMessage"/>
</operation>
<operation name="polyWrapped">
<input message="tns:polyWrappedInputMessage"/>
<output message="tns:polyOutputMessage"/>
</operation>
<operation name="anyElement">
<input message="tns:anyElementInputMessage"/>
<output message="tns:anyElementOutputMessage"/>
</operation>
<operation name="choice">
<input message="tns:choiceInputMessage"/>
<output message="tns:choiceOutputMessage"/>
</operation>
</portType>
</definitions>
Loading…
Cancel
Save