Jax-WS and annotations - java

We currently have this
#WebServiceRef(wsdlLocation = "META-INF/wsdl/localhost_8080/SwitchWSService/SwitchWebService.wsdl")
private SwitchWSService switchWS;
Can't we point to the real web service and it still work.
#WebServiceRef(wsdlLocation = "www.web.com/SwitchWSService/SwitchWebService.wsdl")
private SwitchWSService switchWS;

Chapter 7.9 of the JAX-WS 2.0 spec says:
wsdlLocation:
A URL pointing to the
location of the WSDL document for the
service being referred to.
...
The wsdlLocation element, if
present, overrides theWSDL location
information specified in the
WebService annotation of the
referenced generated service class.
So your approach is basically OK. But strictly speaking
www.web.com/SwitchWSService/SwitchWebService.wsdl
is not an URL since an URL or URI in general must start with a scheme (see RFC 3986).

Let me see, you want your WSDL to be published onto some external URL and then give clients that URL to retrieve WSDL from. That means your service won't be the source of WSDL download, and thus you don't need to provide ANY wsdlLocation for it.

Related

wsdl file location path setup in java

I'm using wsdl files to generate client & is working fine on my local server since the generated files have path like "C:\path\to\wsdl\Air.wsdl"
I'm trying to replace all the paths as above to the one that work on live server I've found some hints but I'm not so sure how to implement it (I'm new to web services).
Below is how my files currently look like
#WebServiceClient(name = "AirService",
wsdlLocation = "file:/C:/Eclipse WorkSpace/TravelPortCXF/WebContent/wsdl/air_v33_0/Air.wsdl",
targetNamespace = "http://www.travelport.com/service/air_v33_0")
static {
URL url = null;
try {
url = new URL("file:/C:/Eclipse WorkSpace/TravelPortCXF/WebContent/wsdl/air_v33_0/Air.wsdl");
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger(AirService.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "file:/C:/Eclipse WorkSpace/TravelPortCXF/WebContent/wsdl/air_v33_0/Air.wsdl");
}
WSDL_LOCATION = url;
}
This seems to be like it should be changed (I'm not sure about that, found it on googling)
#WebServiceClient(name = "AirService",
wsdlLocation = "classpath:wsdl/air_v33_0/Air.wsdl",
targetNamespace = "http://www.travelport.com/service/air_v33_0")
static {
URL url = AirService.class.getClassLoader().getResource("wsdl/air_v33_0/Air.wsdl");
if (url == null) {
java.util.logging.Logger.getLogger(AirService.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "classpath:wsdl/air_v33_0/Air.wsdl");
}
WSDL_LOCATION = url;
}
But I actually don't understand how that method works.. Can someone please make me understand how can I change the path and where to place the wsdl files in the project so that it works properly on the live server and also the difference between both the codes.
Also I don't want to generate every-time when build is created, I want to generate the files (that are already been generated), place the wsdl somewhere in the project folder from where it can be accessed and then change the path in the Java files (by replacing all the paths at once) as in the above codes.
Few intro points for you:
Wsdl file contains description webmethods callable on the server (in general method names, their input parameters and its types and types of results of this methods). Therefore wsdl file is like contract between client and server - client knows what methods to call on the server, what parameters it will need to send with method name, and what type of result it can expect.
You can download and store wsdl file from server, and then use it for generation of special client class(es) (called stubs). This classes have java methods 1 to 1 corresponding to web service methods described in wsdl file. Source code of these classes is generated automatically by special tool (wsimport) which reads content of wsdl file and generate corresponding methods. From your perspective as developer of client, it is then very simple - you need only in some way create instance of this class (giving it url of wsdl file on the server) and call it's method like you call any other Java class method. (Generated implementation code of this methods cares for serialization of inputs and sending of webservice request to server, and then deserialization of response back to you, so you will obtain normal Java object as a result of call).
Maybe you now ask, why you need to set url to server's wsdl file before call of webservice method. Answer is that client code before calling your webservice automatically download's wsdl from the server and check's if it does not change meantime (if yes it does not call webservice and throws error). It sometimes happen that developer of server changed e.g. parameters of webservice method and you as client developer have still old version of wsdl, therefore validation aspect of this technology saves you a lot of time.
Now real examples:
Look at JAX-WS deployment best practice: WSDL location and client generation question to see client code how webservice method (hello) is called using HelloWorldPOCImpl stub class.
For server side implementation you need only two annotation #Webservice and #WebMethod, please look at chapter 3.1 to see example: https://metro.java.net/getting-started/building-a-simple-metro-application.html
For server, you dont need to create wsdl file manually, server generates wsdl file automatically - based on your code and mentioned annotations.

Jersey resource that matches any path

I am using Jersey v1.x and a Guice Servlet.
What I'm trying to do is bind a Jersey Resource that matches any #Path, such that I can use Jersey to respond with a 404.
I'm looking to do this, since my servlet consists of different components (e.g. a rest API that lives under /api, and a web UI that lives under /.
In Guice terms, that means I have several ServletModules that each set up one part of the servlet:
In my ApiServletModule: serve("/api").with(GuiceContainer.class, conf)
In my WebUiServletModule: serve("/").with(GuiceContainer.class, conf)
In this setup, I want to define what the 404 response body looks like for each part of the webapp (/api or /) from the codebase of each subproject responsible, without having to reimplement Jersey
So far I have tried to bind a resource that match #Path("/"), #Path("*") and #Path("/*"), but none of these seem to be picked up when I request /some/path/that/doesnt/exist
You need to use the regex format of the path expression, i.e.
#Path("{any: .*}")
You could inject List<PathSegment> to look at all the segments if you need them.
public Response getSomething(#PathParam("any") List<PathSegment> segments)
#peeskillet's answer is indeed correct, in the sense that it describes how you can create a Jersey resource that matches any path.
However, my goal of creating a resource that delivers 404 responses for whenever any other unmatched path is requested is not quite met by this answer:
At least in combination with Guice, will such a "match all"-resource intercept all requests, regardless of whether any more specific resources are available. Additionally, you cannot modify the HTTP response status code from within a resource.
For this purpose, Jersey has ExceptionMappers that can be implemented and loaded by adding the #Provider annotation. One particular type would be a ExceptionMapper<NotFoundException>, which is invoked when a Resource throws a NotFoundException. The ExceptionMapper can then decide what response to generate, including the status code.

Do "pure Spring" based servlets have Endpoint URL like CXF based WSDL have?

I have a perfectly working demo server/client apps pair using Spring (only!) -- no CXF or WSDL involved. It runs with the help of Apache Tomcat 7.0.34.
I was curious to see whether I can see any trace to its presence on a browser (http://localhost:8080/) but I couldn't find any hint to a URL in the source code (copied verbatim from a tutorial).
I then found this thread which provided a way to get the endpoint's URL:
TransportContext tc = TransportContextHolder.getTransportContext();
WebServiceConnection wc = tc.getConnection();
URI uri = wc.getUri();
I added this to my demo/tutorial client's code and while the first statement (getTransportContext()) doesn't throw any exception, it returns null and so the second one (getConnection()) throws a NullPointerException .
Why?
Do "pure" Spring based servlets lack endpoint URLs?
If not, what am I missing? What is the way to retrieve the service's URL?
I know that the client knows about the server by means of the context path and the bean id (as defined in the shared beans.xml):
ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext( new String[] {"/sample/spring/beans.xml" } );
But isn't there a URL equivalent to this? Like WSDLs do?
I agree with #GreyBeardedGeek's comment, there's no concept of endpoint URL on Spring web-app (java servlet web-app in general).
If you do need to runtime lookup what URL the user used to reach your app, you can use ServletRequest / HttpServletRequest methods such as getRemoteAddr(), getRemoteHost(), getURL(), getContextPath() etc. Eg:
#RequestMapping("/home")
public String home(HttpServletRequest req) {
String host = req.getRemoteHost();
// ...
}
However keep in mind multiple URL can point to the same tomcat server, eg if a reverse proxy / DNS CName is setup. And that might (or not) yield different URL for you.

dynamic proxy soap web service client in java?

Is there any way to use soap-rpc web services such that the client is generated via a shared interface? Restful web services do it this way, but what about soap based? Do you always have to use a tool like Axis or CXF to generate your stubs and proxies, or is there something out there that will set it up dynamically?
Thanks.
EDIT #1:
To clarify, I'm looking to do something like this:
Common interface:
#WebService
public interface MyWebService {
#WebMethod
String helloWorld();
}
This common interface can already be used to create the server side component. My question is: can this type of common interface be used on the client side to generate dynamic proxies? Restful web services do it this way (Restlets & CXF) and it seems the .Net world has this type of functionality too.
I would see this tutorial of JAX-WS useful for your purposes:
In the example code the Web Services Client is configured by adding an annotation #WebServiceRef with a property pointing to the WSDL location to the client implementation class and no tools are needed to access the stuff from the Web Service that is referenced.
Was this the way you would like to have it, or did this even answer to right question?
Not exactly sure what you're looking for, but if you don't want to rely on JAX-WS/JAXB-generated artifacts (service interfaces and binding objects), you can make use of the Service and Dispatch APIs. For example:
QName serviceName = new QName(...);
Service service = Service.create(serviceName);
QName portName = new QName(...);
String endpointAddress = "...";
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
SOAPMessage request = ...;
SOAPMessage response = dispatch.invoke(request);
Check Apache CXF. Configuring a Spring Client (Option 1).
When you want to call a webservice, you must have knowledge of methods implemented on it. For that, We need to make stubs OR we can read it from WSDL.
I have created a WS client, using AXIS2 libraries, which is without stubs. The thing is, for each diff. WS we need to create response handles.
You can call any WS method using SOAP envelops and handle the response.
//common interface for response handlers...
//implement this for diff. web service/methods
public interface WSRespHandler{
public Object getMeResp(Object respData);
}
//pass particular handler to client when you call some WS
public class WebServiceClient {
public Object getResp(WSRespHandler respHandler) {
...
return repHandler.getMeResp(xmlData);
}
}
Please check the link below, which shows the example interface for WS client.
http://javalibs.blogspot.com/2010/05/axis2-web-service-client-without.html
For every diff. WS method we can have diff. implementation for WSRespHandler interface, which will help parsing the response.
Not knowing java so well, but being forced to learn some to accomplish a task that I was given, I needed to consume a .Net service that I have already written, I had to do a little research.
I found that 99% of the examples/samples/problems with invoking a method call against a .Net service, or any service for that matter involved using J2EE (ServiceManager) or build classes and a proxy that reflect the service being invoked. Unfortunately for me, none of this would work. I was working "in a box". I could not add new classes, could not WSDL references, did not have J2EE, but DID have access to the standard java libs.
I am used to doing this sort of thing in pretty much every other language but java, but now there was no choice, and java it was.
A lot of digging and figuring out all new terminology, methods, classes, etc, I knew I was getting close, but was having issues with some small items to complete the task.
Then I came across this post: http://www.ibm.com/developerworks/xml/library/x-jaxmsoap/
As long as you have some sort of idea of what you need to send the soap service in term of the soap envelope, the above link will give you the information you need to be able to invoke a service without the classes, wsdl class generators and J2EE, apache or other dependencies.
In an hour from the time I read the mentioned article, I had a class working and about 10 minutes later, converted the code to the "in the box" solution.
Hope this helps
Apache Tuscany might help you, although it may be heavier than you want
http://tuscany.apache.org/

Creating a web-service client with a known but inaccessible wsdl

We have been provided with a wsdl and xsd schema by a company we are working with via email. The web-services we are interfacing with are accessed through a IPsec tunnel. There are local references(on their end) in the published WSDL which means we cannot consume it.
1st question: Is this a common setup? I thought the point of having a WSDL was not only to define the contract but to also expose the service to consumers.
I can easily generate client/server code off of the provided WSDL using wsimport, wsconsume, etc.. I know when my generated client makes a call to my generated service it produces the correct message I need.
2nd Question: Is there an easy way to route this to a different soap address?
I just want to be able to do something like:
SalesTaxService svc = new SalesTaxService();
SalesTax tax = svc.getSalesTaxPort()
tax.getRate("NY");
But not use the soap address defined in the WSDL. I would like to avoid writing a bunch of dispatch clients for each method.
Am I missing something?
*In response to skaffman:
This is what was generated. It defaulted to wsdlLocation as a name shrug
#WebServiceClient(name = "SomeService")
public class SomeService_Service extends Service {
public SomeService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SomeService_Service(URL wsdlLocation) {
super(wsdlLocation, new QName("urn:some_service", "SomeService"));
}
}
I thought the point of having a WSDL
was not only to define the contract
but to also expose the service to
consumers.
No, WSDL is purely a descriptive tool, it has no real runtime role. The web service operates completely independently of the WSDL. It's not uncommon for the WSDL to not be exposed.
Is there an easy way to route this to
a different soap address?
That depends entirely on what web service implementation you're using, and you don't say, although I'm guessing JAX-WS. If that's the case, the artifacts that JAX-WS's tools generate allow you to pass in the URL to the client stub constructors, I think.
So I figured out why I was having a problem. I was assuming that the wsdlLocation had to be the WSDL that the actual service was publishing. This of course is not the case. The solution is to package a local WSDL with the correct SOAP:Address for the actual service into the client.
edit
I found out that you can alter the endpoint address programmatically without having to alter the actual WSDL:
HelloService service = new HelloService (
this.getClass().getResource("originalHello.wsdl"),
new QName("http://example.org/hello", "HelloService "));
HelloPort proxy = service.getHelloPort();
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpointaddress");
proxy.sayHello("Hello World!");
Credit goes to : Jianming Li

Categories

Resources