I'm trying to use Opentext Content Web Services(CWS) from my axis2-based web-service.
This is a piece of code that creates a proxy client to CWS and passes an authentication token in a header.
DocumentManagement_Service docManService = new DocumentManagement_Service();
DocumentManagement docManClient = docManService.getBasicHttpBindingDocumentManagement();
try
{
// The namespace of the OTAuthentication object
final String ECM_API_NAMESPACE = "urn:api.ecm.opentext.com";
// Create a SOAP header
SOAPHeader header = MessageFactory.newInstance().createMessage().getSOAPPart().getEnvelope().getHeader();
// Add the OTAuthentication SOAP header element
SOAPHeaderElement otAuthElement = header.addHeaderElement(new QName(ECM_API_NAMESPACE, "OTAuthentication"));
// Add the AuthenticationToken SOAP element
SOAPElement authTokenElement = otAuthElement.addChildElement(new QName(ECM_API_NAMESPACE, "AuthenticationToken"));
authTokenElement.addTextNode(authToken);
// Set the SOAP header on the docManClient
String ENDPOINT_ADDRESS_PROPERTY = WSBindingProvider.ENDPOINT_ADDRESS_PROPERTY;
((WSBindingProvider) docManClient).setOutboundHeaders(Headers.create(otAuthElement));
}
catch (SOAPException e)
{
System.out.println("Failed to set authentication SOAP header!\n");
System.out.println(e.getMessage());
System.out.println(e.getStackTrace());
return;
}
This code works fine when executed from simple java application. In that case docManClient is a SEIStub object and setOutboundHeaders method works after casting to WSBindingProvider.
But when this code is executed inside my axis2 webservice, docManClient is JAXWSProxyHandler object and it can not be casted into WSBindingProvider nor execute setOutboundHeaders method.
So my question is - How do I pass my header with AuthElement using JAXWSProxyHandler (do the same as setOutBoundHeaders method do) OR Can I somehow convert JAXWSProxyHandler object to SEIStub object?
The problem occurs because you are using an API that is specific to the JAX-WS implementation in the JRE. However, when running on Axis2, the JAX-WS implementation provided by Axis2 will be used instead. That implementation supports a different set of API extensions.
What this means is that your code is not portable across different JAX-WS implementations. You have two options:
Make it portable by only using standard APIs. In your case this would require implementing a JAX-WS handler that adds the header. To pass the authToken to the handler, you would cast the client to BindingProvider and add the data to the request context.
Remove the axis2-jaxws JAR from your Axis2 deployment so that your code will use the JAX-WS implementation from the JRE. Of course this won't work if the service itself is deployed as a JAX-WS service. Unfortunately the code snippet doesn't show whether that's the case or not.
Related
I'm trying to access an old SOAP based system written in C# from a Java backend service. This C# application is looking for an AddressHeader to be populated with a specific value on every request. I'm using Apache CXF to create the requests to this service. Unfortunately, for the life of me, I cannot find out how to add this address header to each of the requests. Does anyone know what the equivalent in Java is and how to add it using Apache CXF?
The address header is the same as the SOAP header, hence we only need to add a particular SOAP header to every request so that be capable of making a successful call.
Here is an example I found on the internet.
ClientProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(singz.ws.cxf.sample.SampleServiceInterface.class);
factory.setAddress("http://xxx.xxx.com/services/SampleService/v1");
SampleServiceInterface serviceClient = (SampleServiceInterface) factory.create();
Client proxy = ClientProxy.getClient(serviceClient);
List<Header> headersList = new ArrayList<Header>();
Header testSoapHeader1 = new Header(new QName("uri:singz.ws.sample", "soapheader1"), "SOAP Header Message 1", new JAXBDataBinding(String.class));
Header testSoapHeader2 = new Header(new QName("uri:singz.ws.sample", "soapheader2"), "SOAP Header Message 2", new JAXBDataBinding(String.class));
headersList.add(testSoapHeader1);
headersList.add(testSoapHeader2);
proxy.getRequestContext().put(Header.HEADER_LIST, headersList);
Please refer to the below links, wish it is useful to you.
https://dzone.com/articles/apache-cxf-how-add-custom-soap-0
How do you add a Soap Header defined in a wsdl to a web service client in CXF?
https://dzone.com/articles/apache-cxf-how-add-custom-soap
Feel free to let me know if there is anything I can help with.
I'm a beginner and I'm a little bit lost with Resteasy
I'd like to send a post request with an URL similar to this : http://myurl.com/options?value=3name=picture
String myValue = "3";
String myName = "picture";
String key = "topsecret";
I'm not too sure about what's coming. I've seen several tutorial classes (not very clear to me) and another way similar to this
final MultivaluedMap<String, Object> queryParams = new MultivaluedMapImpl<>();
queryParams.add("value", myValue);
queryParams.add("name", myPicture);
final ResteasyClient client = new ResteasyClientBuilder().build();
final ResteasyWebTarget target = client.target(url).queryParams(queryParams);;
final Builder builder = target.request();
When I write I have loads of warning. Is it the right way do it ? What about the API key ?
First of all, you must check the documentation of the API you want to consume regarding how the API key must be sent to the server. Not all APIs follow the same approach.
For example purposes, let's assume that the API key must be sent in the X-Api-Key header. It's a non standard and I've made it up just to demonstrate how to use the client API.
So you can have the following:
// Create a client
Client client = ClientBuilder.newClient();
// Define a target
WebTarget target = client.target("http://myurl.com/options")
.queryParam("value", "3")
.queryParam("name", "picture");
// Perform a request to the target
Response response = target.request().header("X-Api-Key", "topsecret")
.post(Entity.text(""));
// Process the response
// This part is up to you
// Close the response
response.close();
// Close the client
client.close();
The above code uses the JAX-RS API, which is implemented by RESTEasy. You'd better use Client instead of ResteasyClient whenever possible to ensure portability with other implementations.
The above code also assumes that you want to send an empty text in the request payload. Modify it accordingly.
Response instances that contain an un-consumed entity input stream should be closed. This is typical for scenarios where only the response headers and the status code are processed, ignoring the response entity.
Going beyond the scope of the question, bear in mind that Client instances are heavy-weight objects that manage the underlying client-side communication infrastructure. Hence initialization as well as disposal of a Client instance may be a rather expensive operation.
The documentation advises to create only a small number of Client instances and reuse them when possible. It also states that Client instances must be properly closed before being disposed to avoid leaking resources.
One of my system need to invoke SOAP based webservices. As of now, for every new webservices, I generate Java stubs from the provided WSDL file and redeploy the web application with new webservice consumer code. Is there a good approach to dynamically create a webservice client that can invoke the methods from the provided WSDL files? All I am expecting is
put the WSDL file in the location that can be accessed by the web application
invoke the Servlet with a keyword having the wsdl file name, and other params required for the webservice method.
Can the Apache CXF help in this? I read in a post, generating wsdl2java in the runtime and loading the classes, over a time, can exhaust the pemgen memory space.
You should look here : http://cxf.apache.org/docs/dynamic-clients.html
This is exactly that.
here an example:
ClientImpl client = (ClientImpl)doc.getClientFromWsdl("http://myurl:8080/DataCentersWS?wsdl");
String operationName = "getVirtualisationManagerUuid";
BindingOperationInfo op = doc.getOperation(client, operationName);
List<MessagePartInfo> messagesParts = op.getInput().getMessageParts();
Object[] params = new Object[messagesParts.size()];
/* feed yours params here (this feeding was heavy in my code */
Object[] res = client.invoke(op, params);
There is many other examples in the source distribution of cxf.
I can call NetDocuments SOAP API by C# as following:
// Authenticate to the NetDocuments directory service
ndDir.Directory ndDirectory = new ndDir.Directory();
ndDirectory.CookieContainer = new System.Net.CookieContainer(); // enable cookie handling
ndDirectory.Login( username, password );
// Connect to the NetDocuments storage service
ndStor.storage ndStorage = new ndStor.storage();
ndStorage.CookieContainer = ndDirectory.CookieContainer; // share cookies with the directory service
XmlNode searchRes = ndStorage.Search( criteria, attrList );
However, when I call NetDocuments SOAP API by java with Axis 1.4, I receive error: "No authentication session. The authentication session has timed out or was not established prior to this call."
DirectorySoapStub stubDir = new DirectorySoapStub(new URL("https://vault.netvoyage.com/ndApi/directory.asmx"), new DirectoryLocator());
StorageSoapStub stubSto = new StorageSoapStub(new URL("https://vault.netvoyage.com/ndApi/storage.asmx"), new StorageLocator());
stubSto.setMaintainSession(true);
stubDir.login(username, password);
javax.xml.soap.MimeHeaders mhds = stubDir._getCall().getMessageContext().getCurrentMessage().getMimeHeaders();
java.util.Iterator iterator = mhds.getAllHeaders();
while (iterator.hasNext()) {
javax.xml.soap.MimeHeader mhd = (javax.xml.soap.MimeHeader)iterator.next();
if ("set-cookie".indexOf(mhd.getName()) >= 0) {
stubSto._setProperty(mhd.getName(), mhd.getValue());
}
}
stubSto.search(criteria, attrList);
Is there similar thing of CookieContainer in Java? How can I call NetDocuments SOAP API by java with Axis 1.4?
I realise this question was posted a while ago, but I've been able to get this working in the past by using the JAX-RPC plugin that comes with NetBeans. The version of NetBeans I used was v6.8 (I think that the JAX-RPC plugin is not included in newer versions of NetBeans as JAX-RPC isn't widely used anymore). I remember struggling to get anything working when I tried to use Axis, though that was more than likely due to me not being familiar enough with it.
I can't remember all the steps necessary, but you can point the JAX-RPC plugin at the WSDL for NetDocuments and all the classes needed for calling the API are then set up for you.
To handle authentication correctly, it was necessary to set the SESSION_MAINTAIN_PROPERTY on the DirectorySoap_Stub and StorageSoap_Stub classes to true - this instructs them to maintain a session once you have logged in. See e.g. http://docs.oracle.com/cd/E19575-01/821-0177/fxybb/index.html for info on SESSION_MAINTAIN_PROPERTY
Additionally, when you login via the DirectorySoap object, if you then want to use the methods of StorageSoap you need to let the StorageSoap object know the cookie that you are using in the DirectorySoap session.
To do this I implemented a javax.xml.rpc.handler.Handler that stores the CookieJar from the DirectorySoap session (property "com.sun.xml.rpc.client.http.CookieJar" on the request MessageContext) and sets that CookieJar on the same property of requests of the StorageSoap session.
Hopefully that's useful to anyone with similar SOAP issues...
Cheers
I use Netbeans to generate web service client code, client-style JAX-WS, so i can invoke a web service API.
However, when I invoke the web service API, I get the exception:
com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 307: Temporary Redirect
Why do I get this? What is the workaround? I know the problem isn't with the web service itself, because I can get responses fine via soapUI and .Net.
Faced the same problem about a month ago.
Web service client classes were generated using Apache CXF and web service returned HTTP
status 307, which led to the same exception.
Invocation of the same web service method using soapUI with property Follow Redirects set to true was successful and returned needed data.
After googling awhile, it looked like there is no property to enable following redirects in the JAX-WS for this.
So, below is the code which is currently working, though I'm not sure it is compliant with any standards:
Supposing generated client classes looks like:
// generated service class
public class MyWebServiceClient extends javax.xml.ws.Service {
// ...
private final QName portName = "...";
// ...
public RetrieveMyObjects getRetrieveMyObjects() {
return super.getPort(portName, RetrieveMyObject.class);
}
// ...
}
// generated port interface
// annotations here
public interface RetrieveMyObjects {
// annotations here
List<MyObject> getAll();
}
Now, upon executing following code:
MyWebServiceClient wsClient = new MyWebServiceClient("wsdl/location/url/here.wsdl");
RetrieveMyObjectsPort retrieveMyObjectsPort = wsClient.getRetrieveMyObjects();
wsClient should return instance which is both instance of RetrieveMyObjects & javax.xml.ws.BindingProvider interfaces. It is not stated anywhere on the surface of JAX-WS, but it seems that a lot of code is based on that fact. One can re-assure him\herself by executing something like:
if(!(retrieveMyObjectsPort instanceof javax.xml.ws.BindingProvider)) {
throw new RuntimeException("retrieveMyObjectsPort is not instance of " + BindingProvider.class + ". Redirect following as well as authentication is not possible");
}
Now, when we are sure that retrieveMyObjectsPort is instance of javax.xml.ws.BindingProvider we can send plain HTTP POST request to it, simulating SOAP request (though it looks incredibly incorrect & ugly, but this works in my case and I didn't find anything better while googling) and check whether web service will send redirect status as a response:
// defined somewhere before
private static void checkRedirect(final Logger logger, final BindingProvider bindingProvider) {
try {
final URL url = new URL((String) bindingProvider.getRequestContext().get(ENDPOINT_ADDRESS_PROPERTY));
logger.trace("Checking WS redirect: sending plain POST request to {}", url);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/html; charset='UTF-8'");
connection.setDoOutput(true);
if(connection.getResponseCode() == 307) {
final String redirectToUrl = connection.getHeaderField("location");
logger.trace("Checking WS redirect: setting new endpoint url, plain POST request was redirected with status {} to {}", connection.getResponseCode(), redirectToUrl);
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, redirectToUrl);
}
} catch(final Exception e) {
logger.warn("Checking WS redirect: failed", e);
}
}
// somewhere at the application start
checkRedirect(logger, (BindingProvider) retrieveMyObjectsPort);
Now, what this method does is: it takes BindingProvider.ENDPOINT_ACCESS_PROPERTY of retrieveMyObjectsPort i.e. the url to which this port method will be sending SOAP requests and sends plain HTTP POST request as described above. Then it checks whether response status is 307 - Temporary Redirect (other statuses like 302 or 301 may also be included) and if it is, gets the URL to which web service is redirecting and sets new endpoint for the specified port.
In my case this checkRedirect method is called once for each web service port interface and then everything seems to work fine:
Redirect is checked on url like http://example.com:50678/restOfUrl
Web service redirects to url like https://example.com:43578/restOfUrl (please note that web service client authentication is present) - endpoint of a port is set to that url
Next web service requests executed via that port are successful
Disclaimer: I'm quite new to webservices and this is what I managed to achieve due to the lack of solutions for this questions, so please correct me if something is wrong here.
Hope this helps
Yes I know this post is old, but I've had similar errors, and thought maybe somebody would benefit from my solution.
the one that plagued me the most was:
com.sun.xml.ws.client.ClientTransportException: The server sent HTTP status code 200: OK
Which turns out to mean an incomplete response header. Apparently jax-ws does some kind of validation that includes validating the HTTP headers as well. And the server I was using was just sending an empty header.
It worked like a charm after adding 'application/soap+xml' to the Content-Type header.