You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Tom Davies <to...@atlassian.com> on 2007/11/08 02:03:02 UTC

Programmatically publishing a REST endpoint

Hi,

I have a SOAP services working fine, using the servlet transport. The  
servlet is configured in web.xml, and the end point publishing happens  
in the init method of the servlet (which is a subclass of CXFServlet:

public void init(ServletConfig servletConfig) throws ServletException {
         super.init(servletConfig);
         Bus bus = this.getBus();
         BusFactory.setDefaultBus(bus);
         Endpoint.publish("/review",  
SpringContext.getComponent("rpcReviewService"));
	Endpoint e = Endpoint.create(HTTPBinding.HTTP_BINDING,  
SpringContext.getComponent("restReviewService"));
         e.publish("/rest");
         Endpoint.publish("/auth",  
SpringContext.getComponent("rpcAuthService"));
     }

My RestReviewService class (based on the CustomerService example)  
looks like:

@Component("restReviewService")
@WebService
@UriTemplate("/review/")
public class RestReviewService {
         @Autowired
         private ReviewService reviewService;

         @HttpContext
         UriInfo uriInfo;

         @HttpMethod("GET")
         @UriTemplate("/all/")
         public List<ReviewData> getAllReviews() {
             return reviewService.getAllReviews();
         }
}

When I start my server the log says:
...
[java] Nov 8, 2007 11:34:53 AM  
org.apache.cxf.service.factory.ReflectionServiceFactoryBean  
buildServiceFromClass
      [java] INFO: Creating Service {http://rpc.spi.crucible.atlassian.com/ 
}RestReviewServiceService from class  
com.atlassian.crucible.spi.rpc.RestReviewService
      [java] Nov 8, 2007 11:34:53 AM  
org.apache.cxf.endpoint.ServerImpl initDestination
      [java] INFO: Setting the server's publish address to be /rest
      [java] Nov 8, 2007 11:34:53 AM  
org.apache.cxf.service.factory.ReflectionServiceFactoryBean  
buildServiceFromClass
...

But the service endpoint seems to be another SOAP service, as when I  
go to http://localhost:6060/foo/services/rest/review/all I get:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/ 
envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</ 
faultcode><faultstring>No such operation: review</faultstring></ 
soap:Fault></soap:Body></soap:Envelope>

Thanks for any tips or pointers to documentation other than http://cwiki.apache.org/CXF20DOC/rest-with-jax-ws-provider-and-dispatch.html

I suspect I need to set the JAXRS binding for the endpoint, but I  
don't know how to do it...

Tom

--
ATLASSIAN - http://www.atlassian.com
Our products help over 8,500 customers in more than 95 countries to  
collaborate






RE: Programmatically publishing a REST endpoint

Posted by "Liu, Jervis" <jl...@iona.com>.

> -----Original Message-----
> From: Tom Davies [mailto:tom@atlassian.com]
> Sent: 2007?11?12? 6:23
> To: cxf-user@incubator.apache.org
> Subject: Re: Programmatically publishing a REST endpoint
> 
> 
> 
> On 08/11/2007, at 7:37 PM, Liu, Jervis wrote:
> 
> > Here you go, a brief document on how to build RESTful services in  
> > CXF using JAX-RS (JSR-311): 
> http://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+%28
JSR-311%29
> >
> 
> Hi Jervis,
> 
> Thanks for the information.
> 
> One clarification: as I'm using the servlet transport, I 
> don't want to  
> set an explicit address, just a path component, so that the REST API  
> is under the URL my CXFServlet maps to.
> 
> So given that I have this code to publish my SOAP services:
> 
> public void init(ServletConfig servletConfig) throws 
> ServletException {
>         super.init(servletConfig);
>         Bus bus = this.getBus();
>         BusFactory.setDefaultBus(bus);
>         Endpoint.publish("/review",  
> SpringContext.getComponent("rpcReviewService"));
>         Endpoint.publish("/auth",  
> SpringContext.getComponent("rpcAuthService"));
> 	... REST publishing goes here ...
>     }
> 
> Can I use something like:
> JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
>         sf.setResourceClasses(RestReviewService.class);
>         //default lifecycle is per-request, change it to singleton
>         sf.setResourceProvider(RestReviewService.class, new  
> SingletonResourceProvider());
>         sf.setBus(bus);
> 	sf.setAddress("/rest"); // will this work?
> 
>         sf.create();
> 
This should work. Willem Jiang had done some work on this part recently to make it possible to publish an endpoint using servlet transport both from spring configuration and API. 

> A more general question: What are the pros and cons of using 
> CXF HTTP  
> binding vs. JSR-311 for REST?
> 

If you take a closer look into JSR-311 and CXF HTTP binding, you may find that they have a lot of things in common, such as the URITemplate, HTTP Method annotation etc. Maybe the annotation names are different, but the basic ideas are same. So I would say you can view JSR-311 as an evolved and more standard version of CXF HTTP binding. 


> Thanks again,
>    Tom
> 
> --
> ATLASSIAN - http://www.atlassian.com
> Our products help over 8,500 customers in more than 95 countries to  
> collaborate
> 
> 
> 
> 
> 

----------------------------
IONA Technologies PLC (registered in Ireland)
Registered Number: 171387
Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland

Re: Programmatically publishing a REST endpoint

Posted by Tom Davies <to...@atlassian.com>.
On 08/11/2007, at 7:37 PM, Liu, Jervis wrote:

> Here you go, a brief document on how to build RESTful services in  
> CXF using JAX-RS (JSR-311): http://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+%28JSR-311%29
>

Hi Jervis,

Thanks for the information.

One clarification: as I'm using the servlet transport, I don't want to  
set an explicit address, just a path component, so that the REST API  
is under the URL my CXFServlet maps to.

So given that I have this code to publish my SOAP services:

public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
        Bus bus = this.getBus();
        BusFactory.setDefaultBus(bus);
        Endpoint.publish("/review",  
SpringContext.getComponent("rpcReviewService"));
        Endpoint.publish("/auth",  
SpringContext.getComponent("rpcAuthService"));
	... REST publishing goes here ...
    }

Can I use something like:
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
        sf.setResourceClasses(RestReviewService.class);
        //default lifecycle is per-request, change it to singleton
        sf.setResourceProvider(RestReviewService.class, new  
SingletonResourceProvider());
        sf.setBus(bus);
	sf.setAddress("/rest"); // will this work?

        sf.create();

A more general question: What are the pros and cons of using CXF HTTP  
binding vs. JSR-311 for REST?

Thanks again,
   Tom

--
ATLASSIAN - http://www.atlassian.com
Our products help over 8,500 customers in more than 95 countries to  
collaborate






RE: Programmatically publishing a REST endpoint

Posted by "Liu, Jervis" <jl...@iona.com>.
Here you go, a brief document on how to build RESTful services in CXF using JAX-RS (JSR-311): http://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+%28JSR-311%29

BTW,  at the moment we do not support the return of a List in JAX-RS (e.g., List<ReviewData> getAllReviews() ), I am even not sure whether or not this should be supported. The main problem is a direct mapping from List to XML would result in an invalid XML as it has multiple root elements, thus can not be displayed on browsers. You will need a wrapper object, i.e., ReviewDataList getAllReviews(), where ReviewDataList is defined as:

@XmlRootElement(name = "ReviewDataList")
public class ReviewDataList {
    private Collection<ReviewData> rds;

    public Collection<ReviewData> getReviewData() {
        return rds;
    }

    public void setReviewData(Collection<ReviewData> r) {
        this.rds= r;
    }
}


Jervis

> -----Original Message-----
> From: Liu, Jervis [mailto:jliu@iona.com]
> Sent: 2007?11?8? 15:06
> To: cxf-user@incubator.apache.org
> Subject: RE: Programmatically publishing a REST endpoint
> 
> 
> Currently there are three ways to build a RESTful service in 
> CXF. [1] and [2] should give you enough information on how to 
> use CXF HTTP binding and JAX-WS Dispatch/Provider to build a 
> RESTful service. Now we have a third option - using JSR-311. 
> You are very welcome to try this new feature out, any 
> feedbacks would be hightly appreciated. This has not been 
> documented yet, but I will do this soon. At the same time, 
> there are couple of examples under system test directory [3], 
> which hopefully will help you out. 
> 
> To answer your specific question, if you want to use CXF HTTP 
> binding, you need to write your server mainline as below: 
> 
> JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
> sf.setServiceClass(PeopleService.class);
> sf.getServiceFactory().setWrapped(true);
> sf.setBindingId(HttpBindingFactory.HTTP_BINDING_ID);
> sf.setAddress("http://localhost:9001/");
> 
> PeopleService peopleService = new PeopleServiceImpl();
> sf.getServiceFactory().setInvoker(new BeanInvoker(peopleService));
> 
> Server svr = sf.create();
> 
> Your RestReviewService.class suggests that you are actually 
> using JSR-311, in this case, your server main line is as below:
> 
>         JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
>         sf.setResourceClasses(RestReviewService.class);
>         //default lifecycle is per-request, change it to singleton
>         sf.setResourceProvider(RestReviewService.class, new 
> SingletonResourceProvider());
>         sf.setAddress("http://localhost:9001/");
> 
>         sf.create();  
> 
> 
> [1]. http://cwiki.apache.org/CXF20DOC/http-binding.html
> [2]. 
> http://cwiki.apache.org/CXF20DOC/rest-with-jax-ws-provider-and
> -dispatch.html
> [3]. 
> https://svn.apache.org/repos/asf/incubator/cxf/trunk/systests/
> src/test/java/org/apache/cxf/systest/jaxrs
> 
> Hope this helps,
> Jervis
> 
> 
> 
> > -----Original Message-----
> > From: Tom Davies [mailto:tom@atlassian.com]
> > Sent: 2007?11?8? 9:03
> > To: cxf-user@incubator.apache.org
> > Subject: Programmatically publishing a REST endpoint
> > 
> > 
> > Hi,
> > 
> > I have a SOAP services working fine, using the servlet 
> > transport. The  
> > servlet is configured in web.xml, and the end point 
> > publishing happens  
> > in the init method of the servlet (which is a subclass of 
> CXFServlet:
> > 
> > public void init(ServletConfig servletConfig) throws 
> > ServletException {
> >          super.init(servletConfig);
> >          Bus bus = this.getBus();
> >          BusFactory.setDefaultBus(bus);
> >          Endpoint.publish("/review",  
> > SpringContext.getComponent("rpcReviewService"));
> > 	Endpoint e = Endpoint.create(HTTPBinding.HTTP_BINDING,  
> > SpringContext.getComponent("restReviewService"));
> >          e.publish("/rest");
> >          Endpoint.publish("/auth",  
> > SpringContext.getComponent("rpcAuthService"));
> >      }
> > 
> > My RestReviewService class (based on the CustomerService example)  
> > looks like:
> > 
> > @Component("restReviewService")
> > @WebService
> > @UriTemplate("/review/")
> > public class RestReviewService {
> >          @Autowired
> >          private ReviewService reviewService;
> > 
> >          @HttpContext
> >          UriInfo uriInfo;
> > 
> >          @HttpMethod("GET")
> >          @UriTemplate("/all/")
> >          public List<ReviewData> getAllReviews() {
> >              return reviewService.getAllReviews();
> >          }
> > }
> > 
> > When I start my server the log says:
> > ...
> > [java] Nov 8, 2007 11:34:53 AM  
> > org.apache.cxf.service.factory.ReflectionServiceFactoryBean  
> > buildServiceFromClass
> >       [java] INFO: Creating Service 
> > {http://rpc.spi.crucible.atlassian.com/ 
> > }RestReviewServiceService from class  
> > com.atlassian.crucible.spi.rpc.RestReviewService
> >       [java] Nov 8, 2007 11:34:53 AM  
> > org.apache.cxf.endpoint.ServerImpl initDestination
> >       [java] INFO: Setting the server's publish address to be /rest
> >       [java] Nov 8, 2007 11:34:53 AM  
> > org.apache.cxf.service.factory.ReflectionServiceFactoryBean  
> > buildServiceFromClass
> > ...
> > 
> > But the service endpoint seems to be another SOAP service, 
> as when I  
> > go to http://localhost:6060/foo/services/rest/review/all I get:
> > 
> > <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/ 
> > envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</ 
> > faultcode><faultstring>No such operation: review</faultstring></ 
> > soap:Fault></soap:Body></soap:Envelope>
> > 
> > Thanks for any tips or pointers to documentation other than 
> > http://cwiki.apache.org/CXF20DOC/rest-with-jax-ws-provider-and
> > -dispatch.html
> > 
> > I suspect I need to set the JAXRS binding for the endpoint, but I  
> > don't know how to do it...
> > 
> > Tom
> > 
> > --
> > ATLASSIAN - http://www.atlassian.com
> > Our products help over 8,500 customers in more than 95 
> countries to  
> > collaborate
> > 
> > 
> > 
> > 
> > 
> 
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, 
> Dublin 4, Ireland
> 

----------------------------
IONA Technologies PLC (registered in Ireland)
Registered Number: 171387
Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland

RE: Programmatically publishing a REST endpoint

Posted by "Liu, Jervis" <jl...@iona.com>.
Currently there are three ways to build a RESTful service in CXF. [1] and [2] should give you enough information on how to use CXF HTTP binding and JAX-WS Dispatch/Provider to build a RESTful service. Now we have a third option - using JSR-311. You are very welcome to try this new feature out, any feedbacks would be hightly appreciated. This has not been documented yet, but I will do this soon. At the same time, there are couple of examples under system test directory [3], which hopefully will help you out. 

To answer your specific question, if you want to use CXF HTTP binding, you need to write your server mainline as below: 

JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setServiceClass(PeopleService.class);
sf.getServiceFactory().setWrapped(true);
sf.setBindingId(HttpBindingFactory.HTTP_BINDING_ID);
sf.setAddress("http://localhost:9001/");

PeopleService peopleService = new PeopleServiceImpl();
sf.getServiceFactory().setInvoker(new BeanInvoker(peopleService));

Server svr = sf.create();

Your RestReviewService.class suggests that you are actually using JSR-311, in this case, your server main line is as below:

        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
        sf.setResourceClasses(RestReviewService.class);
        //default lifecycle is per-request, change it to singleton
        sf.setResourceProvider(RestReviewService.class, new SingletonResourceProvider());
        sf.setAddress("http://localhost:9001/");

        sf.create();  


[1]. http://cwiki.apache.org/CXF20DOC/http-binding.html
[2]. http://cwiki.apache.org/CXF20DOC/rest-with-jax-ws-provider-and-dispatch.html
[3]. https://svn.apache.org/repos/asf/incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs

Hope this helps,
Jervis



> -----Original Message-----
> From: Tom Davies [mailto:tom@atlassian.com]
> Sent: 2007?11?8? 9:03
> To: cxf-user@incubator.apache.org
> Subject: Programmatically publishing a REST endpoint
> 
> 
> Hi,
> 
> I have a SOAP services working fine, using the servlet 
> transport. The  
> servlet is configured in web.xml, and the end point 
> publishing happens  
> in the init method of the servlet (which is a subclass of CXFServlet:
> 
> public void init(ServletConfig servletConfig) throws 
> ServletException {
>          super.init(servletConfig);
>          Bus bus = this.getBus();
>          BusFactory.setDefaultBus(bus);
>          Endpoint.publish("/review",  
> SpringContext.getComponent("rpcReviewService"));
> 	Endpoint e = Endpoint.create(HTTPBinding.HTTP_BINDING,  
> SpringContext.getComponent("restReviewService"));
>          e.publish("/rest");
>          Endpoint.publish("/auth",  
> SpringContext.getComponent("rpcAuthService"));
>      }
> 
> My RestReviewService class (based on the CustomerService example)  
> looks like:
> 
> @Component("restReviewService")
> @WebService
> @UriTemplate("/review/")
> public class RestReviewService {
>          @Autowired
>          private ReviewService reviewService;
> 
>          @HttpContext
>          UriInfo uriInfo;
> 
>          @HttpMethod("GET")
>          @UriTemplate("/all/")
>          public List<ReviewData> getAllReviews() {
>              return reviewService.getAllReviews();
>          }
> }
> 
> When I start my server the log says:
> ...
> [java] Nov 8, 2007 11:34:53 AM  
> org.apache.cxf.service.factory.ReflectionServiceFactoryBean  
> buildServiceFromClass
>       [java] INFO: Creating Service 
> {http://rpc.spi.crucible.atlassian.com/ 
> }RestReviewServiceService from class  
> com.atlassian.crucible.spi.rpc.RestReviewService
>       [java] Nov 8, 2007 11:34:53 AM  
> org.apache.cxf.endpoint.ServerImpl initDestination
>       [java] INFO: Setting the server's publish address to be /rest
>       [java] Nov 8, 2007 11:34:53 AM  
> org.apache.cxf.service.factory.ReflectionServiceFactoryBean  
> buildServiceFromClass
> ...
> 
> But the service endpoint seems to be another SOAP service, as when I  
> go to http://localhost:6060/foo/services/rest/review/all I get:
> 
> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/ 
> envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</ 
> faultcode><faultstring>No such operation: review</faultstring></ 
> soap:Fault></soap:Body></soap:Envelope>
> 
> Thanks for any tips or pointers to documentation other than 
> http://cwiki.apache.org/CXF20DOC/rest-with-jax-ws-provider-and
> -dispatch.html
> 
> I suspect I need to set the JAXRS binding for the endpoint, but I  
> don't know how to do it...
> 
> Tom
> 
> --
> ATLASSIAN - http://www.atlassian.com
> Our products help over 8,500 customers in more than 95 countries to  
> collaborate
> 
> 
> 
> 
> 

----------------------------
IONA Technologies PLC (registered in Ireland)
Registered Number: 171387
Registered Address: The IONA Building, Shelbourne Road, Dublin 4, Ireland