I have a bunch of generated SOAP client stubs that differ between WSDL versions. This happens because SOAP servers have different version of their web services.
Stubs for the web service version 1 are packed in soap.stubs.version1 and stubs for version 2 under soap.stubs.version2.
This means that MyStub in version 1 of the WSDL can be different from MyStub in version 2. As such if I call a SOAP method that returns version 2 of MyStub and hold the value in version 1 of MyStub It will "break", as the xml response can't be properly mapped to the stub's attributes.
Because of this I need to associate class types with SOAP Servers.
Replicating logic for each version would be simply impossible:
if(SoapServer.version==1)
{
soap.subts.version1.MyStub result = SoapServer.getFoo();
/* rest of the logic using result of type soap.subts.version1.MyStub */
}
else if(SoapServer.version==2)
{
soap.subts.version2.MyStub result = SoapServer.getFoo();
/* rest of the logic using result of type soap.subts.version2.MyStub */
}
Every time I'd generate stubs for a newer version I would need to replicate all the logic to use the new stubs. Sometimes the only thing that changes is an attribute.
As such how can I use the proper stubs depending on the SOAP Server without having to re-implement all the logic for that "class"?
I thought about using Object but that would require allot of if instanceof and casts.
I've managed to resolve this issue with a misck of Java reflection and URLClassLoader. What I basicly did was:
Depending on the Server version I define the package name from where to fetch the subts
Using URLClassLoader I load the correct .class files
Using reflection I invoke the correct methods
This has the great advantage of Plug And Play SOAP Servers even with different stub versions. The only thing that must be constant between versions are the methods names so it's possible to fetch them through Class.getMethod.
Related
Okay. So i'm taking over a very very old system that uses Groovy, and this application is connecting to a third party web service via its configuration file with the entry like this: (this is for prd)
webService.wsdlUrl = "jar:file:/lib/MyWebService.jar!/META-INF/wsdl/MyServices_live.wsdl"
It has its own set of groovy configuration files for qa and prd. Qa looks like this:
webService.wsdlUrl = "jar:file:/lib/MyWebService.jar!/META-INF/wsdl/MyServices_qa.wsdl"
These MyServices_live.wsdl and MyServices_qa.wsdl files contain the path to the actual web service url (for prd and qa respectively) which is the one that needs to be replaced for both instances.
I already have the new url. So what did I do? I don't have enough experience doing this so I had to do some research. Apparently, I can use "wsimport" to connect to the new web service url and append ?wsdl to the end of this url so I can generate a jax-rs web service client. I was able to produce a set of java codes that I eventually learned that theyI thought problem solved. I just need to compile these java codes and jar the classes, so I'll have an updated MyWebService.jar.
Now, I realized with what I have done, the wsdl parameter is embedded in the code
#WebServiceClient(name = "Services", targetNamespace = "http://blahblah/", wsdlLocation = "https://newhostname.com/Service?wsdl")
With this approach, I would create 2 jars, 1 for prd and 1 for qa which won't be the most ideal thing to do. We would like to retain the previous capability of controlling where the web service client (inside the jar) will point to by using a parameter (e.g. just like here... the wsdl was specified jar:file:/lib/MyWebService.jar!/META-INF/wsdl/MyServices_live.wsdl ).
Again, to highlight the architecture, the application is running in Groovy and it is using a jar file to access some third party services.
I haven't really done any Groovy development, so I would like to as much as possible not touch any Groovy code.
Would you have any idea of how i can go about this problem?
So there is a SOAP webservice. The targetNamespace in the WSDL dynamically changes based on customer's configurable string. Think of it like
targetNamespace="http://myservice."+ [CouldBeAnyString] + "domain.com"
I have two questions:
My basic research tells me that this is a pretty weird(bad?) practice for developing webservices. Thoughts ?
How does one write a client for such a webservice ? I have tested using jax-ws stub and it isn't compatible when targetNamespace changes. Any other suggestions ? I have been trying to understand dynamic client generation based on wsdl. Would prefer a nicer path though if one exists
Update:
I am only the client. Service is provided by someone else.
Same customer has multiple environments (eg test,production) where the service is hosted under different targetNamespaces
If the SOAPUI call works even if the targetNamespace has change, you could use a lightweight HTTP library called HTTPCLIENT.
With this library you don't need to generate client, since you are sending the SOAP envelope as a string, the way you would do via SOAPUI.
The downside is to work with Strings.
In theory, it is feasible to create such a Web Service client.
Steps:
Create Java artifacts based on the WSDL using wsimport.exe of JDK (see: http://www.mkyong.com/webservices/jax-ws/jax-ws-wsimport-tool-example as a reference)
For the purposes of the code displayed below, I have used the Calculator WSDL provided by Microsoft
Create a "Dynamic Web Project" via Eclipse J2EE
Copy the Java artifacts created in step #1, under src folder of the project created in step #2.
Create a new Class containing you main method. Normally you would have something similar to:
String wsdlLocation = "127.0.0.1:8088";//Normally you should retrieve that value dynamically
Url url = new URL(wsdlLocation + "?wsdl");// ?wsdl is actually needed
String namespaceURI = "http://Example.org";//Normally you should retrieve that value dynamically
String localPart = "CalculatorService";// as specified in WSDL file (see name attribute of service tag)
QName qname = new QName(namespaceURI, localPart);
CalculatorService service = new CalculatorService(url,qname);
ICalculator iCalculator = service.getICalculator();
int response = iCalculator.add(1, 2);
System.out.println(response);
Now for the tricky part:
If you have followed the example with the aforementioned WSDL, you should now have several Annotated Classes having hard-coded namespace (e.g. ICalculator is annotated with:
#WebResult(name = "result", targetNamespace = "..."))//where ... is similar to http ://example .org
Using Java reflection modify all the hard-coded values at runtime (see an example here: https://stackoverflow.com/a/14276270/2625635 on how to modify Annotations)
The aforementioned solution should do the trick.
Most client frameworks allow you to create an interface for calling your client (i.e. they create a contract interface). They also provide an implementation for that interface and it is the implementation that has specific annotations or extends "SOAP aware" classes, while the interface is clean of such details.
From what you posted I assume the clients have the same interface, it's just the implementation namespace that's different? If yes, then write your application to use the interface then build a jar for each environment's implementation. When you deploy on test servers deploy with the test jar, while on production deploy with the production jar (i.e. pick a different implementation for the same contract depending on the environment).
Even if the framework you use doesn't create an interface for you, you can create one yourself and hide the various implementations behind an adapter of some sort.
You can also do something like edubriguenti suggested but I wouldn't go as far as working with strings. Work with SAAJ instead.
This basically has me at a loss, and has for almost a week. I'm working on a part of company architecture, trying to get REST all set up. There are two methods that are not in the javax.ws.rs package - SEARCH and PATCH. I've created the following interface in our project to implement SEARCH: (mostly a copy/paste from examples)
/** imports and such as appropriate **/
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#HttpMethod("SEARCH")
public #interface SEARCH {
}
The code using this works flawlessly if called against it directly. However, the web service that talks to the main service fails every time with 500 Invalid HTTP method: SEARCH. So, to be clear, there are two web-enabled services. The first that uses the above code works fine. The second, which is supposed to be nothing but a proxy to the first service fails.
The second service that is having the problem runs on jetty. The servlet that is doing the proxying is an extension of org.mortbay.servlet.ProxyServlet - the only overrides are on init and proxyHttpUrl to do a little bit of URL tweaking. I know that the second service doesn't pass the response into the first because I can shut down the first and the second still gives me that error back.
My question is, am I missing configuration pieces to enable "custom" (i.e. not in the javax.ws.rs package) http methods?
First off, that proxy servlet code is very old, from jetty-6 unless I am mistaken. We have released jetty-9 now, and the last three versions of jetty have come from eclipse so the ProxyServlet you ought to be using is the org.eclipse.jetty.servlets.ProxyServlet class.
Now, from jetty-7 on we added some customization to that proxy servlet so you could modify much more of the client exchange...and you might need to make use of that to get additional http methods working. It could be that the http-client only excepts standard http methods in which case we would have to fix that up for your use case (open a bug at bugs.eclipse.org under RT/Jetty if that is the case).
When I create a new Web service using RSA 7.5 IDE and Web Sphere 7.0 server from a Web Application, then I can see a few auto-generated files created by this process, namely:
1) For the service, a SEI file is created
2) For the models, ser, deser and helper files are created.
But I cant understand what are the use of all these SEI, ser, deser and helper files.
Any valid explanation on this will be much appreciated.
BOUNTY EDIT:
Bounty-Edit:
Since I did not get any response I would like to ask this question again - offering a bounty to encourage an in-depth answer. I would love to know how and when are these files used internally?
Regards,
Service Endpoint Interface (SEI):
SEI is the Java interface corresponding to the Web service port type
being implemented. It is defined by the JAX-RPC, which specifies the
language mapping from WSDL 1.1 to Java. Ref
Or
A service endpoint interface (SEI) is a Java interface that
declares the methods that a client can invoke on the service. Ref
These ser,dser,helper are helpers to convert an XML document into a java object and vice versa (WebServices). Ref
Files generated in the server project: (WebSphere Application Server 6.1 Ref)
According to the settings made during the run of the wizard, the following files in the WeatherJavaBeanWeb project have been created:
Service endpoint interface (SEI): itso.bean.WeatherJavaBean_SEI.java is the interface defining the methods exposed in the Web service.
WSDL file: /WebContent/WEB-INF/wsdl/WeatherJavaBean.wsdl describes the Web service.
Deployment descriptor: webservices.xml, ibm-webservices-ext.xml and ibm-webservices-bnd.xml. These files describe the Web service according to the Web services for J2EE style (JSR 109). The JAX-RPC mapping is described in the WeatherJavaBean_mapping.xml file.
Data mapping files: The helper beans in the itso.objects package perform the data conversion from XML to Java objects and back.
A servlet is defined in the Web deployment descriptor to invoke the JavaBean.
Hope this information help you.
Those files are related to the WebSphere mapping between Java, WSDL, and XML. They are automatically generated, and should not need to be edited. You should pretend they are not there (except if they are not there you may have trouble deploying...).
SEI - Service Endpoint Interface
ser - Serialize
deser - Deserialize
helper - ?
Here are some psuedo-helpful links, that may provide some more insight into your question:
IBM Technotes
WebSphere v6.1 Handbook (check Chapter 15 -> Creating a Web Service --> Generated Files)
All these files are basically generated for webservice.
A web service ia basically a port between 2 running applications independant of the framework or language.
Leta say if you are using java from one side of web service then for complete compilation the java end would need some class files that have those methids which you wish to call on the service.
For this a stub is generated. This stub is basically an interface(SEI).
Also websphere needs additional files for implementing the webservices functionality, thus tge helper files.
This is basically the summary of it.
I'm working on a web-service-proxy with auditing (later on with caching = creating own responses) and I need to generate #Endpoints (such that will just forward i.e. call a remote web service or dummy atleast). Marshaling/unmarshaling seems neccessary for the proxy will add "something" to the request...
We are to use spring-ws and JAXB. Got all XSDs and static WSDLs of the proxied web service.
Any hints around? Anyone doing something similar? How are you doing it?
Is there a simple way how to achieve this using spring or spring-integration?
Thanks in advance..
This should be possible using both Spring WS and Spring Integration:
With Spring WS, you can create a proxy class for your remote WS, wrapping around a org.springframework.ws.client.core.WebServiceTemplate to talk to the WS - which has API's to take care of marshalling the request to xml and unmarshalling the response.
With Spring Integration, you can use an outbound Webservices gateway , but you will need to front it with a messaging gateway, which will act as your proxy, along these lines:
<int:gateway id="wsproxy" service-interface="..ProxyInterface" default-request-channel="requestChannel" default-reply-channel="replyChannel"/>
<int-ws:outbound-gateway id="wsGateway" request-channel="requestChannel" uri="http://serviceURL" marshaller="someMarshaller" unmarshaller="someUnmarshaller"/>
However, I would recommend the first approach of using the WebserviceTemplate, as you do not have a very complex integration need here.
Today I can tell how we proceeded without spring-integration. We found two different ways how to generate #Endpoint class.
1) Using XSLT and Freemarker we generated the endpoint class source in pre-compile phase. XSLT transformation walked thru all WSDL files to create one summary file which was then used to generate the source.
2) Using Javassist we copied the template class, then generated methods regarding content of JAXB2Marshaller instance and finally instantiated object using FactoryBean, all at server start-up.
Problem here we met was set of XSD files written in form that caused the root objects were generated without #XmlRootAnnotation. Javassist version we had internally works with Java 1.4 (no generics) so we used global customization file for XJC and forced #XmlRootAnnotation on root objects.
Both solutions have their pros and cons but both are simpler then using ESB.