diff --git a/distro/changelog.xml b/distro/changelog.xml
index f09bc6d..85d2c92 100644
--- a/distro/changelog.xml
+++ b/distro/changelog.xml
@@ -1,5 +1,9 @@
-
+
First Release
+
+ Modular handler discovery and delegation
+ Fix: WSDL cache now releases the lock it acquires when clearing
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index da5018c..a87e7b1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
org.gcube.core
common-gcore-stubs
- 1.0.0-SNAPSHOT
+ 1.1.0-SNAPSHOT
GCore Stubs
JAXWS Stub Support for gCore Service
@@ -59,7 +59,7 @@
org.gcube.tools
my-container
- 1.0.0
+ 2.0.0-SNAPSHOT
test
@@ -67,7 +67,7 @@
org.gcube.tools
my-container
- 1.0.0
+ 2.0.0-SNAPSHOT
tar.gz
distro
test
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/GCoreJAXWSHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/GCoreJAXWSHandler.java
deleted file mode 100644
index 4c55e76..0000000
--- a/src/main/java/org/gcube/common/clients/stubs/jaxws/GCoreJAXWSHandler.java
+++ /dev/null
@@ -1,127 +0,0 @@
-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 {
-
- /** 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 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);
- }
-}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/StubCache.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/StubCache.java
index 7980393..4f2468d 100644
--- a/src/main/java/org/gcube/common/clients/stubs/jaxws/StubCache.java
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/StubCache.java
@@ -35,8 +35,9 @@ class StubCache {
//obtain a lock for current key
Lock nameLock = lockFor(name);
+ nameLock.lock();
+
try {
-
cache.remove(name);
}
finally {
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/StubFactory.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/StubFactory.java
index fd4ff8d..6db647a 100644
--- a/src/main/java/org/gcube/common/clients/stubs/jaxws/StubFactory.java
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/StubFactory.java
@@ -18,6 +18,7 @@ import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
import org.gcube.common.clients.stubs.jaxws.StubFactoryDSL.AtClause;
+import org.gcube.common.clients.stubs.jaxws.handlers.GCoreJAXWSHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/AbstractHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/AbstractHandler.java
new file mode 100644
index 0000000..1de19b4
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/AbstractHandler.java
@@ -0,0 +1,36 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+
+/**
+ * Adapter implementation of {@link CallHandler} for selective implementations (handle only outgoing calls, or only responses).
+ *
+ * @author Fabio Simeoni
+ *
+ */
+public class AbstractHandler implements CallHandler {
+
+ @Override
+ public void handleRequest(GCoreService> target, SOAPHeader header, SOAPMessageContext context) throws Exception {
+ }
+
+ @Override
+ public void handleResponse(GCoreService> target, SOAPMessageContext context) throws Exception {
+ }
+
+ /**
+ * Helper to set an element on the SOAP header of the outgoing call
+ * @param header the SOAP header
+ * @param name the name the element's name
+ * @param value the element's value
+ * @throws SOAPException if the element cannot be added to the header
+ */
+ protected final void addHeader(SOAPHeader header,QName name, String value) throws SOAPException {
+ header.addHeaderElement(name).addTextNode(value);
+ }
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/CallHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/CallHandler.java
new file mode 100644
index 0000000..65c493e
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/CallHandler.java
@@ -0,0 +1,32 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+
+/**
+ * Handles outgoing calls and their responses.
+ *
+ * @author Fabio Simeoni
+ *
+ */
+public interface CallHandler {
+
+ /**
+ * Handles an outgoing call.
+ * @param target information about the target service
+ * @param header the SOAP header of the call
+ * @param context the JAX-WS call context
+ * @throws Exception if the call cannot be handled
+ */
+ void handleRequest(GCoreService> target,SOAPHeader header,SOAPMessageContext context) throws Exception;
+
+ /**
+ * Handles the response to a call.
+ * @param target information about the target service
+ * @param context the JAX-WS call context
+ * @throws Exception if the response cannot be handled
+ */
+ void handleResponse(GCoreService> target,SOAPMessageContext context) throws Exception;
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/ClientInfoHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/ClientInfoHandler.java
new file mode 100644
index 0000000..37fa209
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/ClientInfoHandler.java
@@ -0,0 +1,29 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+
+/**
+ * A {@link CallHandler} that sets client identification on outgoing calls.
+ *
+ * @author Fabio Simeoni
+ *
+ */
+public class ClientInfoHandler extends AbstractHandler {
+
+
+ /** 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);
+
+ @Override
+ public void handleRequest(GCoreService> target, SOAPHeader header, SOAPMessageContext context) throws Exception {
+ addHeader(header,CALLER_QNAME, target.clientId());
+ }
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/GCoreJAXWSHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/GCoreJAXWSHandler.java
new file mode 100644
index 0000000..20c8b6a
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/GCoreJAXWSHandler.java
@@ -0,0 +1,69 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPHandler;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+
+/**
+ * A {@link SOAPHandler} that adds gCube headers to outgoing calls.
+ *
+ * @author Fabio Simeoni
+ *
+ */
+public class GCoreJAXWSHandler implements SOAPHandler {
+
+ private final GCoreService> target;
+
+ public 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();
+
+ for (CallHandler handler : HandlerRegistry.handlers())
+ handler.handleRequest(target, header, context);
+
+ } catch (Exception e) {
+ throw new RuntimeException("cannot configure outgoing message", e);
+ }
+ else
+ try {
+
+ for (CallHandler handler : HandlerRegistry.handlers())
+ handler.handleResponse(target, context);
+
+ } catch (Exception e) {
+ throw new RuntimeException("cannot configure outgoing message", e);
+ }
+
+ return true;
+ };
+
+ public Set getHeaders() {
+ return null;
+ }
+
+ public boolean handleFault(SOAPMessageContext context) {
+ return true;
+ }
+
+ public void close(MessageContext context) {
+ }
+
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/HandlerRegistry.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/HandlerRegistry.java
new file mode 100644
index 0000000..b581600
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/HandlerRegistry.java
@@ -0,0 +1,45 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Discovers available {@link CallHandler}s.
+ *
+ * @author Fabio Simeoni
+ *
+ */
+public class HandlerRegistry {
+
+ private final static Logger log = LoggerFactory.getLogger(HandlerRegistry.class);
+
+ private final static List handlers = new ArrayList();
+
+ static {
+
+ ServiceLoader loader = ServiceLoader.load(CallHandler.class);
+ Iterator it = loader.iterator();
+ while (it.hasNext())
+ try {
+ CallHandler handler = it.next();
+ log.info("loaded call handler {}",handler);
+ handlers.add(handler);
+ }
+ catch(Error e) {
+ log.error("could not load call handler",e);
+ }
+ }
+
+ /**
+ * Returns the discovered {@link CallHandler}s.
+ * @return the handlers
+ */
+ public static List handlers() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/LegacyWSAddressingHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/LegacyWSAddressingHandler.java
new file mode 100644
index 0000000..a31bc4d
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/LegacyWSAddressingHandler.java
@@ -0,0 +1,33 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import java.util.Iterator;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPHeaderElement;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+
+/**
+ * A {@link CallHandler} that transforms WS-Addressing information in outgoing calls into MemberSubmission form.
+ * @author Fabio Simeoni
+ *
+ */
+public class LegacyWSAddressingHandler extends AbstractHandler {
+
+ //helper: adapts ws-addressing headers to member submission's. brutal but there is no support for member submission in
+ //jdk 1.6
+ @Override
+ public void handleRequest(GCoreService> target, SOAPHeader header, SOAPMessageContext context) 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());
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/ScopeHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/ScopeHandler.java
new file mode 100644
index 0000000..eb510a0
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/ScopeHandler.java
@@ -0,0 +1,31 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+import org.gcube.common.scope.api.ScopeProvider;
+
+/**
+ * A {@link CallHandler} that sets the current scope on outgoing calls.
+ * @author Fabio Simeoni
+ *
+ */
+public class ScopeHandler extends AbstractHandler {
+
+ /** 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);
+
+ @Override
+ public void handleRequest(GCoreService> target, SOAPHeader header, SOAPMessageContext context) 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);
+ }
+}
diff --git a/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/TargetServiceHandler.java b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/TargetServiceHandler.java
new file mode 100644
index 0000000..167b37d
--- /dev/null
+++ b/src/main/java/org/gcube/common/clients/stubs/jaxws/handlers/TargetServiceHandler.java
@@ -0,0 +1,33 @@
+package org.gcube.common.clients.stubs.jaxws.handlers;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+
+/**
+ * A {@link CallHandler} that sets the coordinates of the target service on outgoing calls.
+ *
+ * @author Fabio Simeoni
+ *
+ */
+public class TargetServiceHandler extends AbstractHandler {
+
+ /** Namespace of scope-related headers */
+ private static final String SCOPE_NS = "http://gcube-system.org/namespaces/scope";
+
+ /** Name of the service class call header. */
+ private static final String SERVICECLASS_HEADER_NAME = "serviceClass";
+ private static final QName SERVICECLASS_QNAME = new QName(SCOPE_NS,SERVICECLASS_HEADER_NAME);
+
+ /** Name of the service name call header. */
+ private static final String SERVICENAME_HEADER_NAME = "serviceName";
+ private static final QName SERVICENAME_QNAME = new QName(SCOPE_NS,SERVICENAME_HEADER_NAME);
+
+ @Override
+ public void handleRequest(GCoreService> target, SOAPHeader header, SOAPMessageContext context) throws Exception {
+ addHeader(header,SERVICECLASS_QNAME, target.gcubeClass());
+ addHeader(header,SERVICENAME_QNAME, target.gcubeName());
+ }
+}
diff --git a/src/main/resources/META-INF/services/org.gcube.common.clients.stubs.jaxws.handlers.CallHandler b/src/main/resources/META-INF/services/org.gcube.common.clients.stubs.jaxws.handlers.CallHandler
new file mode 100644
index 0000000..34f8b70
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.gcube.common.clients.stubs.jaxws.handlers.CallHandler
@@ -0,0 +1,4 @@
+org.gcube.common.clients.stubs.jaxws.handlers.ScopeHandler
+org.gcube.common.clients.stubs.jaxws.handlers.TargetServiceHandler
+org.gcube.common.clients.stubs.jaxws.handlers.ClientInfoHandler
+org.gcube.common.clients.stubs.jaxws.handlers.LegacyWSAddressingHandler
\ No newline at end of file
diff --git a/src/test/java/org/acme/ConfigTest.java b/src/test/java/org/acme/ConfigTest.java
new file mode 100644
index 0000000..9c5d366
--- /dev/null
+++ b/src/test/java/org/acme/ConfigTest.java
@@ -0,0 +1,55 @@
+package org.acme;
+
+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 org.acme.jaxws.stubs.StatelessStub;
+import org.gcube.common.clients.stubs.jaxws.handlers.HandlerRegistry;
+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;
+
+@RunWith(MyContainerTestRunner.class)
+public class ConfigTest {
+
+ @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() {
+
+ ScopeProvider.instance.set("/gcube/devsec");
+
+ stub = stubFor(stateless).at(URI.create("http://localhost:9999/wsrf/services/acme/service/stateless"));
+
+ }
+
+ @Test
+ public void handlerTest() {
+
+ TestHandler handler = new TestHandler();
+
+ assertTrue(HandlerRegistry.handlers().contains(handler));
+
+ String input = "input";
+ String output = stub.foo(input);
+
+ assertEquals(input, output);
+
+ handler.called=true;
+
+ assertTrue(HandlerRegistry.handlers().contains(handler));
+
+ }
+
+
+}
diff --git a/src/test/java/org/acme/TestHandler.java b/src/test/java/org/acme/TestHandler.java
new file mode 100644
index 0000000..f6f8aa0
--- /dev/null
+++ b/src/test/java/org/acme/TestHandler.java
@@ -0,0 +1,41 @@
+package org.acme;
+
+import javax.xml.soap.SOAPHeader;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.gcube.common.clients.stubs.jaxws.GCoreService;
+import org.gcube.common.clients.stubs.jaxws.handlers.AbstractHandler;
+
+public class TestHandler extends AbstractHandler {
+
+ public boolean called=false;
+
+ @Override
+ public void handleRequest(GCoreService> target, SOAPHeader header, SOAPMessageContext context) throws Exception {
+ called=true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (called ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TestHandler other = (TestHandler) obj;
+ if (called != other.called)
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/src/test/resources/META-INF/services/org.gcube.common.clients.stubs.jaxws.handlers.CallHandler b/src/test/resources/META-INF/services/org.gcube.common.clients.stubs.jaxws.handlers.CallHandler
new file mode 100644
index 0000000..0b229d5
--- /dev/null
+++ b/src/test/resources/META-INF/services/org.gcube.common.clients.stubs.jaxws.handlers.CallHandler
@@ -0,0 +1 @@
+org.acme.TestHandler
\ No newline at end of file