JAX-WS WebService via CXF provides inaccurate wsdl - java

I've deployed a simple JAX-WS service, built contract-first. In the JAX-WS Endpoint configuration, I specify the location of the original wsdl. However, this is not the wsdl that is returned by cxf. The original wsdl contains policy statements that are an important part of the contract, and should be visible in the wsdl to the service consumers.
I know that the wsdl location i'm setting on the endpoint is correct. When it's not correct, deployment of the war fails. I've also logged the value to double-check.
When deployed locally, the service is available at http://localhost:8080/store-web-0.1.0/services/store.
Problem: The wsdl available at http://localhost:8080/store-web-0.1.0/services/store?wsdl does not contain the policy statements that can be seen in the original wsdl. Leaving out this important part of the contract is not acceptable.
Question: Why is the wsdl available at http://localhost:8080/store-web-0.1.0/services/store?wsdl missing the policy statements and not simply the original wsdl that is configured on the jax-ws endpoint?
Additional details are below. Please let me know if there's any other information you'd like to see.
Thanks in advance!
Details
We're using: JBoss EAP 6.2, CXF 2.7.16 (moving to CXF 3.x is not an option), Spring 4.1.6
We exclude the 'webservices' subsystem in our jboss-deployment-descriptor.xml file
JAX-WS Configuration Class
#Bean StoreImpl storeImpl() {
return new StoreImpl();
}
#Bean
public Endpoint storeServiceEndpoint() {
EndpointImpl endpoint = new EndpointImpl(storeImpl());
endpoint.publish("/store");
// This configuration is located in the WAR, but WSDL is in separate JAR
String wsdlLocation = this.getClass().getResource("/store.wsdl").toString();
endpoint.setWsdlLocation(wsdlLocation);
return endpoint;
}
Web Service Implementation Class
#WebService(endpointInterface = "my.service.Store", serviceName = "store")
public class StoreImpl implements Store {
public StoreImpl() {
}
#Override
public BuySomethingResponse buySomething(BuySomethingRequest buySomethingRequest) {
// operation implementation code here
return response;
}
}
Web Application Initialization
#Order(value=1)
public class StoreWebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(JAXWSEndpointConfig.class);
container.addListener(new ContextLoaderListener(context));
}
}
#Order(value=2)
public class CXFWebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
ServletRegistration.Dynamic dispatcher = container.addServlet("CXFServlet", CXFServlet.class);
dispatcher.addMapping("/services/*");
}
}

I was able to find the issues, of which there were 3.
Issue #1
As seen in the JAX-WS configuration class code included in the question, I was setting the wsdl location after publishing the endpoint.
Issues #2 and #3
The #WebService annotation on the StoreImpl class needed two additional attributes set: targetNamespace and portName. Their values needed to, obviously, match what was defined in the original WSDL.

Related

JAX RS and WebSockets with Stomp in Spring Boot conflict

I am using Spring-Boot. I would like to use JAX RS as my basic REST-API in combination with WebSockets (using Stomp). However, these two libraries seem to end up in a conflict.
I have the following WebSocketConfig:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").setAllowedOrigins("http://localhost:8000").withSockJS();
}
and the following AppConfig:
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(...);
}
}
The problem occurs, if both classes are commented in. If I comment out AppConfig, my socket-connection will connect without any problems. In the other cases, my REST-Api works but the WebSocket-Connection cannot be established (404 exception). I assume the problem lies in the Jax RS component which probably tries to 'consume' the /hello call and does not find a resource mapped to it.
My question is: How can I tell Jax RS to either ignore the /hello call, so that it gets passed through to the WebSocketMessageBroker or to get it working next to each other?
It's related to Spring-Boot Jersey: allow Jersey to serve static content. The default mapping for the Jersey servlet is /*, which hogs up all the requests. By default it will not forward any routes for which it can't find.
You have couple options:
Change the default mapping for the Jersey servlet. You can do that by either
Adding an #ApplicationPath("/new-root") annotation on top of the ResourceConfig subclass.
Or setting the mapping in the application.properties file, using the following property: spring.jersey.applicationPath
Make Jersey run as a servlet filter instead of a servlet. Doing this allows you to set a property with Jersey that will will allow it forward requested routes to the servlet container, that are not mapped in the Jersey application.
You can see how to work this solution, in this post

Apache CXF wsdl2java: make service return original WSDL file

I am struggling big time offering a web service based on some WSDL file received from a customer. As described in details here, the WSDL file returned when appending a ?wsdl to the service URL like
http://never.mind/SomeService?wsdl
seems to be misinterpreted by SoapUI and this again prevents the customer from using the service!
I was now hoping that someone could help me understand if it is possible to make the get WSDL endpoint return the original WSDL file instead of some Apache CXF digested version?
Update: I just read somewhere that there is a WSDLGetInterceptor taking care of the get WSDL requests - can I maybe override that one?
I chose to override the getDocument method of the WSDLGetUtils class being used by the WSDLGetInterceptor. My version of the utils class MyWSDLGetUtilsis put into action via this interceptor:
public class WsdlGetSoapInterceptor extends AbstractSoapInterceptor {
public WsdlGetSoapInterceptor() {
super(Phase.READ);
addBefore(WSDLGetInterceptor.class.getName());
}
/** {#inheritDoc} */
#Override
public void handleMessage(final SoapMessage message) throws Fault {
message.setContextualProperty(WSDLGetUtils.class.getName(), MyWSDLGetUtils.Instance);
}
}

What is URL of WSDL of EJB WebService (JAX-WS)?

As far as I understood, you can introduce:
#Stateless
#WebService
public class MyWebServiceEndpoint {
#Inject SomeBean aBean;
#WebMethod
public String getSomething() {
return "something";
}
}
and when application deployed, the WebService is exposed in the Application Server (such as WebSphere). Then what is the URL of WSDL, where other applications can find my service?
The URL of your WSDL on the server should be in the following format:
http://hostname:port/contextRoot/MyWebServiceEndpoint?WSDL
But this is running under the assumption that the url-pattern attribute of the endpoint entity in your sun-jaxws.xml file uses the same name as your web service class.
Just a hint to the first answer/URL,
In some cases the "context Root" get excluded from the webservice url after deployment.
I can't say for other application servers but for WebLogic and EJB web service URL follow the following default pattern:
http://host:port/'className'/'className'+Service
where 'className' is the simple name of the Java class implementing the web service.
You can easily override the end of the URL by setting the serviceName attribute in the #WebService annotation. If you need to change the root context you must package your web service as an EJB jar embedded in an EAR and use the WebLogic specific deployement descriptor (which I would avoid at all costs).
Hope it helps :)
you need to publish it, You can have a Publisher class like this:
import javax.xml.ws.Endpoint;
//Endpoint publisher
public class Publisher {
public static void main(String[] args) {
Endpoint.publish("http://localhost:9999/webserv/Test", new FilenetWebService());
}
}

JBoss / Resteasy how to prepopulate objects using a filter before the exposed API?

Environment: JBoss AS 7, RestEasy 3.0.5.
I would like to use a preprocess filter in my application to authenticate a particular user and add this authenticated user to the request scope. I tried the following:
#Provider
public class SecurityFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) {
// authenticate, lookup user code etc...
requestContext.setProperty("User", new User("test"));
}
}
And then access it at the bean level using:
#Stateless
public class TestBean {
#Context HttpServletRequest servletRequest;
#GET
#Path("/hello")
public String hello() {
return "Hello " + servletRequest.getAttribute("User");
}
}
However the Context elements are not injected when the bean is annotated as stateless (stateless is required for EJB logic) due to a 2 year old RestEasy bug.
Can anyone think of a solution to this issue?
Alternatively, is there a more typical solution that prepopulating these objects using a filter?
Kind thanks for reading.
What I have done before is that I have a web application, "facade" if you want, to the EJBs. The JAX-RS layer is implemented in this application. A servlet filter intercepts the request to the JAX-RS resources and calls a CDI service that implements the "authenticate, lookup user code etc" logic. On success, the CDI service exports the current user object to CDI. This user object is #Inject'ed in the EJBs.
If CDI is an option for you (and I don't see why not in this setup), you could do the same (i.e. export the User to CDI) from your SecurityFilter, without having to create a web-app.
Additionally the dependency of the service layer (EJBs) to web-specific APIs (HttpServletRequest) is a bit creepy; I really think dependency injection of the actual User object is the way to go.

Integrate Jersey with RMI

I have a Java Jersey project, where I am running an application. On the other hand I have a project were there is a RMI application how can I put this two to work together. In other words how can I intergrate RMI/IIOP into a Jersey application.
I was thinking of something like this:
#Path("/items")
public class ItemsResource {
#Context
UriInfo uriInfo;
#Context
Request request;
Stuber s = new Stuber();
#GET
public Response get() throws RemoteException {
}
Were I have an external class in the Jersey Project that will work as a client to connect with the RMI/IIOP
public class Stuber {
Context ic;
iRemoteLogic logic;
public Stuber() {
super();
Object objref;
try {
ic = new InitialContext();
objref = ic.lookup("LogicService");
System.out.println("Client: Obtained a ref. to Hello server.");
logic = (iRemoteLogic) PortableRemoteObject.narrow(
objref, iRemoteLogic.class);
What should I add to the Stuber class to be able to work as an RMI/IIOP client?
Thanks :)
NOTE: I followed this tutorial for the RMI/IIOP
You would need to provide somewhere an implementation of iRemoteService that is exported via RMI/IIOP (i.e. PortableRemoteObject), and register it via JNDI as LogicService. I doubt the latter is going to work: surely you will need to provide a protocol and host to JNDI.

Categories

Resources