Java – how to programmatically publish web services to Tomcat

I want to publish web services programmatically to Tomcat

//how to tell this tomcat?
Endpoint.publish("http://0.0.0.0:8080/SimpleService",serviceImpl);
//or better something like this:
Endpoint.publish("/SimpleService",serviceImpl);

No need to use web XML and / or sun jaxws XML (for each service)

Question: is there any known way to implement it (using jax-ws or Apache CXF or...)?

(I know that similar questions have been posted. But none of them answered my questions.)

Solution

This is my own problem

This is a simplified working example:

I subclass a cxfnonspringservlet and put it on the web Register in XML:

<servlet>
 <servlet-name>MyCXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>de.test.MyCXFServlet</servlet-class>
 <load-on-startup>2</load-on-startup>
 <async-supported>true</async-supported>
</servlet>

<servlet-mapping>
 <servlet-name>MyCXFServlet</servlet-name>
 <url-pattern>/soap/*</url-pattern>
</servlet-mapping>

This is my subclass cxfnonspringservlet:

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;
import javax.jws.WebMethod;
import javax.servlet.ServletConfig;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.frontend.Serverfactorybean;
import org.apache.cxf.service.factory.ReflectionServicefactorybean;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;

public class MyCXFServlet extends CXFNonSpringServlet
{
    @Override
    protected void loadBus(ServletConfig sc) 
    {
        super.loadBus(sc);
        publishServices();
    }

    private void publishServices()
    {
        Set<Class> serviceInterfaces = new HashSet<>();
        serviceInterfaces.add(de.test.IUserService.class);
        serviceInterfaces.add(de.test.ILoginService.class);

        for (Class aSVCInterface : serviceInterfaces)
        {
            final String serviceName = aSVCInterface.getSimpleName();

            try
            {
                ReflectionServicefactorybean reflectionFactory = new ReflectionServicefactorybean(){
                    @Override
                    protected boolean isValidMethod(Method method)
                    {
                        boolean ret = super.isValidMethod(method);
                        WebMethod wm = method.getAnnotation(WebMethod.class);
                        if (wm != null && wm.exclude())
                            ret = false;
                        return ret;
                    }

                    @Override
                    protected String getServiceName() //Override for custom service name
                    {
                        return serviceName;
                    }

                };
                reflectionFactory.setServiceClass(aSVCInterface);

                Object proxiedServiceObject = Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{aSVCInterface},new de.test.MyWebServiceInvocationHandler(aSVCInterface));

                Serverfactorybean factory = new Serverfactorybean(reflectionFactory);
                factory.setBus(getBus());
                factory.setServiceClass(aSVCInterface);
                factory.setServiceBean(proxiedServiceObject);
                factory.setAddress("/" + serviceName);
                Server svr = factory.create();    
                svr.getEndpoint().getInInterceptors().add(new de.test.MyServiceInterceptor());
            }
            catch (Exception exception)
            {
                exception.printStackTrace();
            }
        }
    }
}

The above servlet will publish two simple interfaces as soap web service Implementation is dynamic (proxy)

This is my myserviceinterceptor:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import org.apache.cxf.binding.soap.soapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.invoker.BeanInvoker;
import org.apache.cxf.service.invoker.Invoker;

public class MyServiceInterceptor extends AbstractSoapInterceptor
{
    public MyServiceInterceptor() 
    {
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage p_message) throws Fault 
    {
        final Exchange exchange = p_message.getExchange();
        final Endpoint endpoint = exchange.get(Endpoint.class);
        final Service service = endpoint.getService();
        final Invoker invoker = service.getInvoker();

        if (invoker instanceof BeanInvoker)
        {
            BeanInvoker bi = (BeanInvoker)invoker;
            Object serviceObj = bi.getServiceObject(null);
            if (Proxy.isProxyClass(serviceObj.getClass()))
            {
                InvocationHandler ih = Proxy.getInvocationHandler(serviceObj);
                if (ih instanceof MyWebServiceInvocationHandler)
                {
                    MyWebServiceInvocationHandler h = (MyWebServiceInvocationHandler)ih;
                    h.setSoapMessage(p_message);
                }
            }
        }
    }
}

Myserviceinterceptor class is mainly used to inject the current soapmessage into mywebserviceinvocationhandler

My mywebserviceinvocationhandler (I don't think code is needed here) is responsible for calling the real service method It just implements invocationhandler and has a SOAP message field (see myserviceinterceptor) This is required to get soapmessage details (such as header)

I hope this will help Cheers!

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>