SOAP annotation for path - java

I need to manage different versions that come in the URL of the Webservice. I'm using a common method in the Webservice for SOAP and REST, and when I tried to get the path in the endPoint class I got the correct path for REST, but not for SOAP(I got a null in this case), does anybody how to get the path in soap?
The url looks like: http://localhost:8083/webService/v1/test and the code is:
#Stateless
#WebService(endpointInterface = "ItestgEndpoint", serviceName="testService")
#Component("testEndpoint")
#Path("/webService")
#Consumes({MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_XML})
public class TestEndpoint implements ItestgEndpoint{
#PUT
#Path("/{version}/test")
#Consumes({MediaType.APPLICATION_XML })
#Produces({MediaType.APPLICATION_XML })
#WebResult(name="testResponse")
public testResponse testEvent(#WebParam(targetNamespace="http://test/web", name="message")
#RequestParam MessageClass message,
#WebParam(name="version") #PathParam("version") String version
) throws TimeoutException, EMSException, ValidationException, AuthenticationException {
logger.info(version);
}
I saw this post SOAP and REST Webservice with one implementation in Java EE, but it didn't solve my problem.
Thanks

SOAP has no "path" like REST has. Depending on the service toolkit you use (CXF, axis, ...) you may need to collect the information in the request that you can extract from the transport mechanism of the soap message. This may or may not be available to you.
Usually, you wire the SOAP service to a path in a configuration. For example in axis, you set the soap servlet dispatcher in the web.xml, same is for cxf. The actual service is then wired in the beans.xml or services.wsdd.
The SOAP handler finds the service by the name of the endpoint and will then send the call to that endpoint which will dispatch it to the right method. The method is in the transmitted SOAP header, not in the URI.
In REST, the identification of the target service/method is in the URI, not in the XML.
So, in my opinion, for SOAP, this is by declaration and the wiring is static, while in REST, you can have the version as a path parameter.
UPDATE: Since everything is possible if you just try hard enough :-) you could rewrite the dispatcher code to allow an extra path parameter on SOAP, maybe the available packages allow some kind of interceptor class, that allows you to rewrite the SOAP header to point to another endpoint, depending on a header attribute that you invent.

Related

Jax-RS consume ANY Content-Type

I have a REST channel with POST method for uploading a binary content. This can be anything.
The method body is as follows:
#POST
#Path("/")
public Response upload(#Context HttpServletRequest httpRequest) {
It has worked when the client has not set Content-Type header, however if he set it, for example, to application/xml, an error occured:
Unsupported Media Type</pre></p><hr>Powered by Jetty:// 9.3.15.v20161220
I've tried adding wildcard:
#Consumes(MediaType.WILDCARD)
however, it still produces the same error.
How can I make jax-rs to accept ANY content type? Or I'm simply using the wrong tool for my job? I've taken Jax-RS because it can consume beans instantiated by IoC frameworks like blueprint...

Get HTTP response code from JAX-WS asynchronous web service

I have an asynchronous JAX-WS web service (#WebService and #WebMethod annotations). I am invoking it in Java. and I would like to know how to get HTTP response code from that service in Java code.
I couldn't find anything on that subject, but I deduced solution based on how my request context is built, because I needed response context so I thought they may be similar. Request context:
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint)
So I thought that this may work:
int responseCode = (int)((BindingProvider) port).getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE);
And it works. ; )

Authenticating with an API key in JAX-RS

We'd like to secure our rest api using an api key. Here are the requirements:
Public-facing services require an api key.
"Private" services can only accept a call from within the cluster,
not the outside world.
Each api identifies a user, and the User object must be available to
the rest service.
Is there some standard way to do this in a JAX-RS app? (We're using Resteasy.)
I've read all about filters, interceptors and basic auth, but it isn't clear to me what's the best approach.
In an earlier version of the app we had a roll-your-own solution in which public services ran on a public port and private ones on a private port. There was a custom api key lookup that set the User object as a variable into the rest service object.
I can't figure out how to do either of these things using standard JAX-RS.
Using a filter to intercept the request
This kind of authentication could be achieved with a ContainerRequestFilter, intercepting the requests to your resource methods.
The filter will be used to extract the API key from the request and validate it. If the API key is not valid, the request will be refused. Otherwise, the request will proceed to the resource methods.
Have a look at the following piece of code. The ContainerRequestContext API can be used to extract information from the HTTP request:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Extract and validate the API key from the request
String apiKey = requestContext.getHeaderString("API-Key");
...
}
}
Also have a look at this answer I wrote a while ago about authentication with tokens in JAX-RS. There you will find plenty of details that can be useful to address the situation you described in your question.
Identifying the user
During the authentication process, you must be able to identify the user who is performing the request. To propagate this information to your resource classes/methods you could:
Override the SecurityContext and inject it into your resource classes/methods.
Use a CDI Event and a producer method to create an object that contains the user identifier that can be injected in your resource classes/methods.
For more details on the these approaches, refer to the answer I mentioned above.
Binding the filter to some resource classes/methods
By default, the filters are global (it means they are executed for all the resource methods of your application). To bind the filter to a subset of resource methods or classes, you could use name binding annotations.
Not giving a detailed answer, but just a suggestion. Check for CustomInvokers and register the invoker for the services. Validate the api-key and throw an error if it's not valid. If there is an error then your client gets an error. The Service code won't be called.
For the actual security framework, please check netflix zuul.

Both REST and SOAP Web Services for a single application

We've build an application using Spring and deployed it with Tomcat. We have a working REST interface, however one of our clients only has a SOAP client.
My understanding is that a SOAP web service and a REST web service cannot coexist on the same port or application.
What are my options for accepting a SOAP request with as little development as possible. Should I accept a soap packet via the rest interface and parse the XML? Or can I setup a SOAP interface communicate with my REST interface and respond back?
I'm using Gradle as my build tool. It would be nice to have the solution as part of a single WAR file
In my experience, you can mix SOAP and REST in the same application if you're very careful about XML namespaces for JAXB. However, I wouldn't recommend it since updating one means risking the other's stability. Here is what I recommend...
Setup a multi-project build in gradle
Create three projects, one for the business logic, one for the REST interface, and one for the SOAP interface
Modify the REST/SOAP interface to use common business logic project
Deploy as two separate WARs
Should I accept a soap packet via the rest interface and parse the XML?
SOAP is a protocol and not just a format so this probably won't work with most (any?) frameworks.
Or can I setup a SOAP interface communicate with my REST interface and respond back?
You probably could at the expense of performance and/or maintainability.
We have a project that has similar requirements. We still have to support SOAP and we're going forward with ReST.
There is no reason that the two will conflict. Since you're using spring, you can even have the same domain objects as a response that gets marshalled to XML and JSON as your preference.
What you have to do is create different URI for the two. e.g someService/** for the SOAP and some-rest for the ReST implementations. You can have a service layer to handle shared logic (mostly the code needed on the end point and the rest controller is to fetch the required data from the service layer and sending it to be marshalled)
Just add some entry to your web.xml file to indicate the rest path and the endpoint paths...
It sounds like your web service is primarily REST (it's 2013) but you have to support soap for a limited case. I'd design your web service with rest primarily in mind, but perhaps use a separate mechanism to indicate to the server that the client requires soap support. If possible, have the soap client send an http request header or use modified URL that perhaps ends in .soap. In any case there's no reason why you can't support both protocols on the same app.
You can do that by following this Steps:
-Add annotation of both Rest and Soap on class implementation.
-Creating interface to hold the method annotation for Soap.
-Put Rest annotation on method in class implementation.
-Configure "web.xml" file to add "servlet" for Rest implementation you use.
-Don't forget to create class extend Application like [ApplicationConfiguration.class].
1- Class Implementation
#javax.jws.WebService(endpointInterface = "com.test.ebpp.autopayment.tess.ejb.GService", targetNamespace = "http://ejb.test.autopayment.ebpp.tess.com/", serviceName = "ApplicationBusinessFacadeService", portName = "ApplicationBusinessFacadePort")
#Path(value = "/ApplicationBusinessFacadeService")
public class ApplicationBusinessFacadePortBindingImpl implements
ApplicationBusinessFacade {
#Override
#POST
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public ProcessResponse process(Process request) {
//type your code
}
}
2- Service Interface
#WebService(name = "ApplicationBusinessFacade", targetNamespace = "http://ejb.gateway.ebpp.com/")
#XmlSeeAlso({
com.ebpp.gateway.ejb.ObjectFactory.class,
com.ebpp.ifxmessages.ObjectFactory.class
})
public interface ApplicationBusinessFacade {
#WebMethod
#WebResult(targetNamespace = "")
#RequestWrapper(localName = "process", targetNamespace = "http://ejb.gateway.ebpp.com/", className = "com.ebpp.gateway.ejb.Process")
#ResponseWrapper(localName = "processResponse", targetNamespace = "http://ejb.gateway.ebpp.com/", className = "com.ebpp.gateway.ejb.ProcessResponse")
public ProcessResponse process(
#WebParam(name = "arg0", targetNamespace = "")
Process arg0);
}
3- web.xml
<servlet>
<servlet-name>com.ebpp.core.rs.config.ApplicationConfiguration</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>com.ebpp.core.rs.config.ApplicationConfiguration</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</servlet>

Apache CXF: how to return failure response from an interceptor

I have written a custom interceptor that does some parameter validation. I want to be able to return an error code and serialize a JAXB-annotated class as the response body.
If I throw a WebApplicationException, it doesn't have any special processing done to serialize the Response object inside (which makes sense; I assume that is done by another interceptor).
How should I go about stopping the interceptor chain but still have JAXB serialize the response entity?
Well, at least in the CXF JAX-RS interceptor flow, if you set:
message.getExchange().put(Response.class, response);
...then the actual service does not get invoked, while the other phases do get invoked. Haven't dug in to the CXF code to see where that logic kicks in.
So I built a response like this:
Response response = Response
.status(Response.Status.FORBIDDEN)
.entity(new ErrorEntity("This is a JAXB object with an error string"))
.build();
I also have some custom authentication running in a CXF JAX-RS filter and I only want to check the parameters when the authentication is alright, so I set my parameter interceptor class to run during the PRE_INVOKE phase.

Categories