So, I've created a client stub application with Apache CXF from a WSDL. The process was relatively straight-forward. I did it within SoapUI interface. I supplied the WSDL location, told CXF to generate the client stub and hit okay.
Then, I imported the project into Eclipse, added the Apache CXF libraries, configured some security options, certs and whatnot.
I wrote a main with a few test calls to my webservice, and... it worked.
Now my problem is that I don't know WHY it worked. To be more specific, when I hit run in Eclipse, the debug output clearly shows that there are CXF classes being invoked.
INFO: Loaded configuration file cxf.xml.
and
org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
In my main() I'm invoking the
MyServices ss = new MyServices(wsdlURL, SERVICE_NAME);
port = ss.getWSHttpBindingMyService();
But the MyServices class extends javax.xml.ws.Service and there's nothing that hints to CXF.
wsdl2java also generated a MyService interface and a MyServiceImpl class that sits in the same package. It looks like a good candidate. In my main() I can write stuff like port.someMethod(someRequest). If I ctrl-click on someMethod and follow the implementation, it actually brings me to MyServiceImpl class but there's only dummy code there!
public Boolean someMethod(SomeRequest request) {
LOG.info("Executing operation");
System.out.println(request);
try {
Boolean _return = null;
return _return;
} catch (java.lang.Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
So there must be some configuration somewhere that is telling the runtime which implementation to use. But I cannot figure out where or which one it is.
Thanks
Whether you use cxf or wsdl2java to generate the client code .
The client code will be generated as per the J2EE specification.
The code generated is just the declaration of service , the implementation of service will be on server.
The client code make uses of the webservice wsdl location to find the service and the operation exposed by it.
Check in your MyServices , You will see your service URL.
Ex
wsdlLocation = `"http://127.0.0.1/bookstore/services/search?wsdl"`
Thanks
Related
I'm trying to develop a client for onvif which has wsdl as in:
http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl
The wsdl2java runs fine and code is generated. However, because there is no element in the wsdl, it doesn't generate a service class for me to use. It only generate an interface for the element.
The webservice's endpoint URI will be different for each device where the service is provided. My question is, given that URI, how am I supposed to get an instance of the portType interface, so that I could use the interface to interact with the webservice?
Thanks
You don't really need it to create a service class to utilize the generated stub. It is possible to use something similar to the following:
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
...
protected <T> T getService(final Class<T> serviceClass, final boolean useSoap12) {
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(serviceClass);
factory.setAddress(endpoint);
if (useSoap12) {
factory.setBindingId("http://schemas.xmlsoap.org/wsdl/soap12/");
}
return serviceClass.cast(factory.create());
}
Where serviceClass is the annotated interface CXF created.
Am pretty new to web services and have been trying to implement Soap Faults. I used Apache Axis2 to generate webservice in the following manner.
public interface XYZ{
public String myMethod(User[] user)
}
Here I have created a User class with some variables so that I can generate User object at .Net environment to pass User[] of objects.
Public class Webservice implements XYZ
{
Public String myMethod(User[] user){
//My implementation
}
}
Now, I created a dynamic project using Eclipse and with the help of Axis2 plugin I created webservice for my "Webservice" class which generates wsdl file. I deployed the webcontent in the Tomcat folder and able to access the WSDL file in the .Net environment. I am able to pass array of objects (User[]) from .Net to Java and able to do my task. Now, I need to implement Soap Faults in Java which I am not sure how to implement.
Can anyone help me with an example or tutorial ?
Your best bet is to Google for something like "jax-ws faults". For example:
http://www.ibm.com/developerworks/webservices/library/ws-jaxws-faults/index.html
You can also implement an error handler, as discussed under "Using handlers in JAX-WS Web services" here:
http://axis.apache.org/axis2/java/core/docs/jaxws-guide.html#BottomUpService
Most frameworks will trigger a SOAP fault when you throw an Exception in the method implementing your operation. That will not give you much control on the SOAP fault content though.
See here for some details on Axis
Generally, You don't need any specific coding for implementing SOAP fault.. Whenever there is any exception thrown by the method (here myMethod in your example.), axis will automatically generate SOAPFault element in the resulting response. The exception is actually wrapped into AxisFault exception and sent to the client.
See here a i.
I get this exception when I try to call a .NET web service:
javax.xml.bind.JAXBException: class com.pixelware.mdv.tramites.TramiteXML nor any of its super class is known to this context.
The client is a Java library created with the CFX JAX-WS frontend (Classes precreated with WSDL)
The method I'm trying to call accepts (nested in another object) an Object (anyType in the WSDL)
Looks like the JAXB engine inside CXF is unable to marshall (serialize to XML) my class. That's because JAXB is unable to serialize a class if it is not registered in it's context and the class being passed it's part of the main program, not the client library.
The CXF documentation shows a lot of configuration options, and it looks like it can be done adding the property additionalContextClasses to the service properties.
I can't add this property by configuration because my client is a separated library with the CFX generated classes.
I tried to add the property programmatically with this code:
Map<String, Object> ctx = (BindingProvider)ws.getWSSoap()).getRequestContext();
ctx.put("jaxb.additionalContextClasses", new Class[] {TramiteXML.class});
But it doesn't work. Looks like maybe this configuration has to be done before creating the client.
I've also found this post, whit the same (or very similar) problem, and the proposed solutions are far from easy.
Shouldn't it be much more simple? Maybe I'm missing something.
Any suggestions?
Well, I found it.
I got it to work using the "raw" DIspatcher API that CXF provides.
I created a method like this:
public ReturnType registrar(RequestType request)
{
// That's the call that didn't worked. Registrar is the name of the method
// return serviceCLient.registrar(user, password, request);
try {
JAXBContext context = JAXBContext.newInstance(RequestType.class, ReturnType.class,
request.geGenericContent().getClass());
Dispatch<Object> registrarDispatch = service.createDispatch(
RegistroElectronico.RegistroElectronicoSoap, context, Mode.PAYLOAD);
registrarDispatch.getRequestContext().put(Dispatch.SOAPACTION_USE_PROPERTY, Boolean.TRUE );
registrarDispatch.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, "http://pixelware.com/RegistroTelematico/Registrar" );
Registrar registrar = new Registrar();
registrar.setLogin(this.user);
registrar.setPassword(this.password);
registrar.setSolicitud(request);
RegistrarResponse response = (RegistrarResponse) registrarDispatch.invoke(registrar);
return response.getRegistrarResult();
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
Finally, the Dispatcher API was easier to use than I thought (Fortunately, there is a class for every web service method call).
The trick was to add my dynamic object type to the JAXBContext.
Anyway, I wonder why something like this couldn't be already done automatically by the CXF framework
Can someone fill in the missing link in the code below?
First way:
The web service interface file is HappyService.
JaxWSProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInterceptors().add(new LoggingInInterceptor());
factory.getInterceptors().add(new LoggingOutInterceptor());
//MISSING LINK. Where does HappyService.class come from? I don't have it
factory.setServiceClass(HappyService.class);
factory.setAddress("http://......../happyService");
//Again how do I get HappyService?
HappyService client = (HappyService) factory.create();
Second way:
String UrlString = "Your WSDL URL";
String nameSpaceUri = "urn:Foo";
String serviceName = "MyHelloService";
String portName = "HelloIFPort";
URL helloWsdlUrl = new URL(UrlString);
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service helloService =
serviceFactory.createService(helloWsdlUrl,
new QName(nameSpaceUri, serviceName));
//Where did dynamicproxy.HelloIF come from? This code won't compile as that file does not exist anywhere
dynamicproxy.HelloIF myProxy =
(dynamicproxy.HelloIF)
helloService.getPort(
new QName(nameSpaceUri, portName),
dynamicproxy.HelloIF.class);
System.out.println(myProxy.sayHello("Buzz"));
Anyone that has a clue as to where these interface classes come from and how they are generated please let me know. It looks like the only way I can do an web service invocation is by writing the SOAP request by hand and I really don't want to do that as it can get very large and error prone.
There are many tools that generate webservices Java classes from WSDL definition files.
You could try JAXB, which is the standard Java tool for this task.
An other possibility is Axis, which a level higher.
You need a SOAP library such as Apache Axis2. The library will include tools for generating Java classes from WSDLs. You would use that generated code to make the web service calls.
Based on your first sample I think you use the CXF framework.
This framework provides a task named wsdl2java that allows to generate classes from a WSDL file.
Once your classes are generated you can use them in your code to call the Web Service in an easy way without having to build the SOAP message by hand. It's CXF's job to do this.
I think it helps if you refer few basics of web-services in java
http://www.oracle.com/technetwork/java/index-jsp-137004.html
http://metro.java.net/
I am using Apache Axis to connect my Java app to a web server. I used wsdl2java to create the stubs for me, but when I try to use the stubs, I get the following exception:
org.apache.axis.ConfigurationException: No service named <web service name> is available
any idea?
According to the documentation linked to by #arnonym, this exception is somewhat misleading. In the first attempt to find the service a ConfigurationException is thrown and caught. It is logged at DEBUG level by the ConfigurationException class. Then another attempt is made using a different method to find the service that may then succeed. The workaround for this is to just change the log level on the ConfigurationException class to INFO in your log4j.properties:
log4j.logger.org.apache.axis.ConfigurationException = INFO
Just a guess, but it looks like that error message is reporting that you've left the service name blank. I imagine the code that generates that error message looks like this:
throw new ConfigurationException("No service named" + serviceName + " is available");
It is an exception used by Axis' control flow.
http://wiki.apache.org/ws/FrontPage/Axis/DealingWithCommonExceptions
--> org.apache.axis.ConfigurationException: No service named XXX is available
This is what my code looks like. It seems to work fine.
Are you using a service locator or just creating your service?
SomeServiceLocator locator = new SomeServiceLocator();
SomeService service = null;
try
{
service = locator.getSomeServiceImplPort();
}
catch (ServiceException e)
{
e.printStackTrace();
}
I don't know what version of Axis you're using but I'm using Axis2 for both server and client and the Java2WSDL create a default endpoint for the service on localhost. If you create the client stub with WSDL2Java, the default constructor of the stub will then point to localhost. If the service is on other endpoint you must use the constructor with the endpoint as parameter...
Maybe the problem is not that at all but as said on other answers, without the WSDL you're using as WSDL2Java input it's hard to say.