Does anyone know how to configure it so that a SOAP service and REST service can share the same port using Jersey (Grizzly) outside of an application server?
- My soap service is at www.someurl.com:port/soap/crm
- My rest service is at www.someurl.com:port/crm
These services share the same port but not the same base url and therefor should be able to run side by side on that port. However, there is a port bind error ..
All of this is in a custom service application and there is no web.xml or such.
The REST service is using Jersey and the Soap service is a class 'ReceptionService' published on an endpoint.
URI soapUri = URI.create("192.168.0.0:1234\soap\Crm")
URI restUri = URI.create("192.168.0.0:1234\crm")
// START SOAP SERVICE
Object reception = getObjectResource(ReceptionService.class);
Endpoint e = Endpoint.publish(soapUri, reception);
// START REST SERVICE
ResourceConfig rc = new ResourceConfig().packages("company.rest");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(restUri, rc);
When I try this, Grizzly spits out 'java.net.BindException: Address already in use: bind'
My soap service reception is setup like this:
@WebService(targetNamespace = "company.crm")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class Reception implements ReceptionService {
... methods
}
My rest service classes are annotated as usual like ...
@Path("hello/{username}")
public class Hello { ... }
I am a bit of a newbie at this and any pointers would be appreciated. And please, don't bother suggesting I run an application server. That is not the problem here -- the problem is how do I get around the port-bind issue without moving to some other webservice framework?
NOTE RE BOUNTY: I CANNOT ITERATE THIS ENOUGH
"The bounty winner will demonstrate how to use Jersey for REST and a Java SOAP service (annotated JAX-WS) together on the same endpoint. The answer will not require changes to the Rest and Soap annotated classes. However, and HTTP server code changes or configuration changes to make it work are acceptable. Switching to Jetty or some other application server are not acceptable The solution must be 100% embedded and run using Java SE and Java web service libraries."
Jetty's overlay feature allows you to deploy two different webapps with different paths on the same Jetty instance/port.
You would have one web.xml with your Jersey servlet (for REST) and the other web.xml with the SOAP servlet.
http://www.eclipse.org/jetty/documentation/current/overlay-deployer.html
What you are saying is nothing but two different interfaces for exposing services and yes you can host them on a single port just deploy it in the same container and you will be having both the interfaces up and running.
Just make sure you don't have a context path conflict, which does not seem to happen in the urls mentioned in the question above.
e.g. Let the rest interface be deployed as:
www.someurl.com:port2/crm , so soap should not be deployed in the same url, www.someurl.com:port1/soap/crm , which is alright.
You should also explain a bit how you are deploying the interfaces, as separate war files or in a single war file.
If you are using a common container such as tomcat for your webservices, then you can get requests for both of the services arriving on the same port. You can deploy both the REST and SOAP based services as part of your application. The container will accept the incoming request and will forward them to the application depending on the application context. In your application web.xml, you can configure the where to send the request depending on the request URL mapping.
It´s not possible to start more than one service on the same port.
When you want that your App is accessible over the same port, you have to use an Application
Server.
You must take care that both Apps on the Server are accessible with different URL´s (web.xml).
All Applications on the same Application Server are now accessible over the same port.
This is most of the code I use to host both rest and soap services on a single port (2 different context paths), completely embedded in my app (using Grizzly obviously), and spring configured...
package com.mycompany.structure.web.grizzly;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.BindException;
import java.util.EnumSet;
import java.util.LinkedList;
import javax.servlet.DispatcherType;
import javax.servlet.Servlet;
import com.mycompany.structure.web.jersey.jackson.JsonResourceConfig;
import com.mycompany.structure.web.jersey.spring.ExposedApplicationContext;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import org.glassfish.grizzly.jaxws.JaxwsHandler;
import org.glassfish.grizzly.servlet.WebappContext;
import org.glassfish.jersey.servlet.ServletContainer;
import org.smallmind.nutsnbolts.lang.web.PerApplicationContextFilter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class GrizzlyInitializingBean implements DisposableBean, ApplicationContextAware, ApplicationListener, BeanPostProcessor {
private static final Class[] NO_ARG_SIGNATURE = new Class[0];
private HttpServer httpServer;
private LinkedList<WebService> serviceList = new LinkedList<>();
private ServletInstaller[] servletInstallers;
private String host;
private String contextPath;
private String restPath;
private String soapPath;
private int port;
private boolean debug = false;
public void setHost (String host) {
this.host = host;
}
public void setPort (int port) {
this.port = port;
}
public void setContextPath (String contextPath) {
this.contextPath = contextPath;
}
public void setRestPath (String restPath) {
this.restPath = restPath;
}
public void setSoapPath (String soapPath) {
this.soapPath = soapPath;
}
public void setServletInstallers (ServletInstaller[] servletInstallers) {
this.servletInstallers = servletInstallers;
}
public void setDebug (boolean debug) {
this.debug = debug;
}
@Override
public synchronized void onApplicationEvent (ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
if (debug) {
System.setProperty("com.sun.xml.ws.transport.http.HttpAdapter.dump", "true");
}
httpServer = new HttpServer();
httpServer.addListener(new NetworkListener("grizzly2", host, port));
WebappContext webappContext = new WebappContext("Grizzly Application Context");
webappContext.addServlet("JAX-RS Application", new ServletContainer(new JsonResourceConfig(ExposedApplicationContext.getApplicationContext()))).addMapping(restPath + "/*");
webappContext.addFilter("per-application-data", new PerApplicationContextFilter()).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), restPath + "/*");
webappContext.addListener("org.springframework.web.context.request.RequestContextListener");
for (ServletInstaller servletInstaller : servletInstallers) {
try {
Constructor<? extends Servlet> servletConstructor;
Servlet servlet;
String urlPattern;
servletConstructor = servletInstaller.getServletClass().getConstructor(NO_ARG_SIGNATURE);
servlet = servletConstructor.newInstance();
webappContext.addServlet(servletInstaller.getDisplayName(), servlet).addMapping((urlPattern = servletInstaller.getUrlPattern()) == null ? "/" : urlPattern);
}
catch (Exception exception) {
throw new GrizzlyInitializationException(exception);
}
}
webappContext.deploy(httpServer);
for (WebService webService : serviceList) {
HttpHandler httpHandler = new JaxwsHandler(webService.getService(), false);
httpServer.getServerConfiguration().addHttpHandler(httpHandler, soapPath + webService.getPath());
}
try {
httpServer.start();
}
catch (IOException ioException) {
if (!(ioException instanceof BindException)) {
throw new GrizzlyInitializationException(ioException);
}
}
}
}
@Override
public void setApplicationContext (ApplicationContext applicationContext) {
ExposedApplicationContext.register(applicationContext);
}
@Override
public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException {
ServicePath servicePath;
if ((servicePath = bean.getClass().getAnnotation(ServicePath.class)) != null) {
serviceList.add(new WebService(servicePath.value(), bean));
}
return bean;
}
@Override
public synchronized void destroy () {
if (httpServer != null) {
httpServer.shutdown();
}
}
}