[seam-commits] Seam SVN: r10628 - in branches/community/Seam_2_1: doc/Seam_Reference_Guide/en-US and 5 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Fri Apr 24 09:29:32 EDT 2009
Author: christian.bauer at jboss.com
Date: 2009-04-24 09:29:32 -0400 (Fri, 24 Apr 2009)
New Revision: 10628
Added:
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/EventComponentTestResource.java
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/PlainTestResource.java
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResource.java
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResourceBean.java
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestComponent.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyProviderFactory.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyResourceFactory.java
Modified:
branches/community/Seam_2_1/build/root.pom.xml
branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Webservices.xml
branches/community/Seam_2_1/examples/restbay/resources/WEB-INF/components.xml
branches/community/Seam_2_1/examples/restbay/resources/jboss-rest-bay-ds.xml
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestResource.java
branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/Application.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceHome.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceQuery.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyBootstrap.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyDispatcher.java
branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyResourceAdapter.java
Log:
JBSEAM-3449, JBSEAM-4150, upgrade to RESTEasy 1.1RC2, support for plain EJB resources, bootstrap improvements, more tests in example
Modified: branches/community/Seam_2_1/build/root.pom.xml
===================================================================
--- branches/community/Seam_2_1/build/root.pom.xml 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/build/root.pom.xml 2009-04-24 13:29:32 UTC (rev 10628)
@@ -300,7 +300,7 @@
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
- <version>1.1-RC1</version>
+ <version>1.1-RC2</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
Modified: branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Webservices.xml
===================================================================
--- branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Webservices.xml 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/Webservices.xml 2009-04-24 13:29:32 UTC (rev 10628)
@@ -340,6 +340,7 @@
<resteasy:resource-class-names>
<value>org.foo.MyCustomerResource</value>
<value>org.foo.MyOrderResource</value>
+ <value>org.foo.MyStatelessEJBImplementation</value>
</resteasy:resource-class-names>
<resteasy:provider-class-names>
@@ -349,6 +350,18 @@
</resteasy:application>]]></programlisting>
<para>
+ RESTEasy supports plain EJBs (EJBs that are not Seam components) as resources. Instead of configuring the
+ JNDI names in a non-portable fashion in <literal>web.xml</literal> (see RESTEasy documentation), you can
+ simply list the EJB implementation classes, not the business interfaces, in <literal>components.xml</literal>
+ as shown above. Note that you have to annotate the <literal>@Local</literal> interface of the EJB with
+ <literal>@Path</literal>, <literal>@GET</literal>, and so on - not the bean implementation class. This allows
+ you to keep your application deployment-portable with the global Seam <literal>jndi-pattern</literal> switch
+ on <literal><core:init/></literal>. Note that EJB resources will not be found even if scanning of
+ resources is enabled, you always have to list them manually. Again, this is only relevant for EJB resources
+ that are not also Seam components and that do not have a <literal>@Name</literal> annotation.
+ </para>
+
+ <para>
The <literal>use-built-in-providers</literal> switch enables (default) or disables the RESTEasy built-in
providers. We recommend you leave them enabled, as they provide plaintext, JSON, and JAXB marshalling
out of the box.
Modified: branches/community/Seam_2_1/examples/restbay/resources/WEB-INF/components.xml
===================================================================
--- branches/community/Seam_2_1/examples/restbay/resources/WEB-INF/components.xml 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/examples/restbay/resources/WEB-INF/components.xml 2009-04-24 13:29:32 UTC (rev 10628)
@@ -35,7 +35,11 @@
entity-class="org.jboss.seam.example.restbay.Category"
auto-create="true"/>
- <resteasy:application resource-path-prefix="/restv1"/>
+ <resteasy:application resource-path-prefix="/restv1">
+ <resteasy:resource-class-names>
+ <value>org.jboss.seam.example.restbay.resteasy.StatelessEjbTestResourceBean</value>
+ </resteasy:resource-class-names>
+ </resteasy:application>
<resteasy:resource-home path="/configuredCategory" name="configuredCategoryResourceHome"
entity-home="#{categoryHome}" entity-id-class="java.lang.Integer"
Modified: branches/community/Seam_2_1/examples/restbay/resources/jboss-rest-bay-ds.xml
===================================================================
--- branches/community/Seam_2_1/examples/restbay/resources/jboss-rest-bay-ds.xml 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/examples/restbay/resources/jboss-rest-bay-ds.xml 2009-04-24 13:29:32 UTC (rev 10628)
@@ -1,9 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE datasources
- PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
- "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
-
<datasources>
<local-tx-datasource>
<jndi-name>restbayDatasource</jndi-name>
Added: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/EventComponentTestResource.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/EventComponentTestResource.java (rev 0)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/EventComponentTestResource.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,138 @@
+package org.jboss.seam.example.restbay.resteasy;
+
+import org.jboss.resteasy.annotations.Form;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.In;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+/**
+ * @author Christian Bauer
+ */
+ at Name("eventComponentTestResource")
+ at Path("/eventComponentTest")
+public class EventComponentTestResource extends TestResource
+{
+
+ @In
+ TestComponent testComponent;
+
+ @GET
+ @Path("/echouri")
+ @Override
+ public String echoUri()
+ {
+ return super.echoUri();
+ }
+
+ @GET
+ @Path("/echoquery")
+ @Override
+ public String echoQueryParam(@QueryParam("bar") String bar)
+ {
+ return super.echoQueryParam(bar);
+ }
+
+ @GET
+ @Path("/echoheader")
+ @Override
+ public String echoHeaderParam(@HeaderParam("bar") String bar)
+ {
+ return super.echoHeaderParam(bar);
+ }
+
+ @GET
+ @Path("/echocookie")
+ @Override
+ public String echoCookieParam(@CookieParam("bar") String bar)
+ {
+ return super.echoCookieParam(bar);
+ }
+
+ @GET
+ @Path("/echotwoparams/{1}/{2}")
+ @Override
+ public String echoTwoParams(@PathParam("1") String one, @PathParam("2") String two)
+ {
+ return super.echoTwoParams(one, two);
+ }
+
+ @GET
+ @Path("/echoencoded/{val}")
+ @Override
+ public String echoEncoded(@PathParam("val") @Encoded String val)
+ {
+ return super.echoEncoded(val);
+ }
+
+ @POST
+ @Path("/echoformparams")
+ @Consumes("application/x-www-form-urlencoded")
+ @Override
+ public String echoFormParams(MultivaluedMap<String, String> formMap)
+ {
+ return super.echoFormParams(formMap);
+ }
+
+ @POST
+ @Path("/echoformparams2")
+ @Override
+ public String echoFormParams2(@FormParam("foo") String[] foo)
+ {
+ return super.echoFormParams2(foo);
+ }
+
+ @POST
+ @Path("/echoformparams3")
+ @Override
+ public String echoFormParams3(@Form TestForm form)
+ {
+ return super.echoFormParams3(form);
+ }
+
+ @Path("/foo/bar/{baz}")
+ @Override
+ public SubResource getBar(@PathParam("baz") String baz)
+ {
+ return super.getBar(baz);
+ }
+
+ @GET
+ @Path("/convertDate/{isoDate}")
+ @Override
+ public long convertPathParam(@PathParam("isoDate") GregorianCalendar isoDate)
+ {
+ return super.convertPathParam(isoDate);
+ }
+
+ @GET
+ @Path("/trigger/unsupported")
+ @Override
+ public String throwException()
+ {
+ return super.throwException();
+ }
+
+ @GET
+ @Path("/commaSeparated")
+ @Produces("text/csv")
+ @Override
+ public List<String[]> getCommaSeparated()
+ {
+ return testComponent.getCommaSeparated();
+ }
+
+}
Added: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/PlainTestResource.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/PlainTestResource.java (rev 0)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/PlainTestResource.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,121 @@
+package org.jboss.seam.example.restbay.resteasy;
+
+import org.jboss.resteasy.annotations.Form;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+/**
+ * @author Christian Bauer
+ */
+ at Path("/plainTest")
+public class PlainTestResource extends TestResource
+{
+
+ @GET
+ @Path("/echouri")
+ @Override
+ public String echoUri()
+ {
+ return super.echoUri();
+ }
+
+ @GET
+ @Path("/echoquery")
+ @Override
+ public String echoQueryParam(@QueryParam("bar") String bar)
+ {
+ return super.echoQueryParam(bar);
+ }
+
+ @GET
+ @Path("/echoheader")
+ @Override
+ public String echoHeaderParam(@HeaderParam("bar") String bar)
+ {
+ return super.echoHeaderParam(bar);
+ }
+
+ @GET
+ @Path("/echocookie")
+ @Override
+ public String echoCookieParam(@CookieParam("bar") String bar)
+ {
+ return super.echoCookieParam(bar);
+ }
+
+ @GET
+ @Path("/echotwoparams/{1}/{2}")
+ @Override
+ public String echoTwoParams(@PathParam("1") String one, @PathParam("2") String two)
+ {
+ return super.echoTwoParams(one, two);
+ }
+
+ @GET
+ @Path("/echoencoded/{val}")
+ @Override
+ public String echoEncoded(@PathParam("val") @Encoded String val)
+ {
+ return super.echoEncoded(val);
+ }
+
+ @POST
+ @Path("/echoformparams")
+ @Consumes("application/x-www-form-urlencoded")
+ @Override
+ public String echoFormParams(MultivaluedMap<String, String> formMap)
+ {
+ return super.echoFormParams(formMap);
+ }
+
+ @POST
+ @Path("/echoformparams2")
+ @Override
+ public String echoFormParams2(@FormParam("foo") String[] foo)
+ {
+ return super.echoFormParams2(foo);
+ }
+
+ @POST
+ @Path("/echoformparams3")
+ @Override
+ public String echoFormParams3(@Form TestForm form)
+ {
+ return super.echoFormParams3(form);
+ }
+
+ @Path("/foo/bar/{baz}")
+ @Override
+ public SubResource getBar(@PathParam("baz") String baz)
+ {
+ return super.getBar(baz);
+ }
+
+ @GET
+ @Path("/convertDate/{isoDate}")
+ @Override
+ public long convertPathParam(@PathParam("isoDate") GregorianCalendar isoDate)
+ {
+ return super.convertPathParam(isoDate);
+ }
+
+ @GET
+ @Path("/trigger/unsupported")
+ @Override
+ public String throwException()
+ {
+ return super.throwException();
+ }
+
+ @GET
+ @Path("/commaSeparated")
+ @Produces("text/csv")
+ @Override
+ public List<String[]> getCommaSeparated()
+ {
+ return super.getCommaSeparated();
+ }
+}
Added: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResource.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResource.java (rev 0)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResource.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,93 @@
+package org.jboss.seam.example.restbay.resteasy;
+
+import org.jboss.resteasy.annotations.Form;
+
+import javax.ejb.Local;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.Path;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.POST;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.Produces;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+/**
+ * @author Christian Bauer
+ */
+ at Local
+ at Path("/statelessEjbTest")
+public interface StatelessEjbTestResource
+{
+
+ // TODO: RESTEasy can not inject setter/fields on plain EJBs, see https://jira.jboss.org/jira/browse/RESTEASY-151
+ // That's why we have to do it through parameter injection below
+ @Context
+ public void setUriInfo(UriInfo uriInfo);
+
+ @Context
+ public void setHeaders(HttpHeaders headers);
+
+
+ @GET
+ @Path("/echouri")
+ String echoUri(@Context UriInfo uriInfo); // TODO
+
+ @GET
+ @Path("/echoquery")
+ String echoQueryParam(@QueryParam("bar") String bar);
+
+ @GET
+ @Path("/echoheader")
+ String echoHeaderParam(@HeaderParam("bar") String bar);
+
+ @GET
+ @Path("/echocookie")
+ String echoCookieParam(@CookieParam("bar") String bar);
+
+ @GET
+ @Path("/echotwoparams/{1}/{2}")
+ String echoTwoParams(@PathParam("1") String one, @PathParam("2") String two);
+
+ @GET
+ @Path("/echoencoded/{val}")
+ String echoEncoded(@PathParam("val") @Encoded String val);
+
+ @POST
+ @Path("/echoformparams")
+ @Consumes("application/x-www-form-urlencoded")
+ String echoFormParams(MultivaluedMap<String, String> formMap);
+
+ @POST
+ @Path("/echoformparams2")
+ String echoFormParams2(@FormParam("foo") String[] foo);
+
+ @POST
+ @Path("/echoformparams3")
+ String echoFormParams3(@Form TestForm form);
+
+ @Path("/foo/bar/{baz}")
+ SubResource getBar(@PathParam("baz") String baz);
+
+ @GET
+ @Path("/convertDate/{isoDate}")
+ long convertPathParam(@PathParam("isoDate") GregorianCalendar isoDate);
+
+ @GET
+ @Path("/trigger/unsupported")
+ String throwException();
+
+ @GET
+ @Path("/commaSeparated")
+ @Produces("text/csv")
+ List<String[]> getCommaSeparated(@Context HttpHeaders headers); // TODO
+}
Added: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResourceBean.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResourceBean.java (rev 0)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/StatelessEjbTestResourceBean.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,101 @@
+package org.jboss.seam.example.restbay.resteasy;
+
+import javax.ejb.Stateless;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+/**
+ * @author Christian Bauer
+ */
+ at Stateless
+public class StatelessEjbTestResourceBean extends TestResource implements StatelessEjbTestResource
+{
+
+ @javax.annotation.Resource // EJB injection!
+ javax.ejb.SessionContext ejbSessionContext;
+
+
+ public String echoUri(@Context UriInfo uriInfo)
+ {
+ assert ejbSessionContext != null; // Ensure this is executed in the EJB container
+ setUriInfo(uriInfo);
+ return super.echoUri();
+ }
+
+ @Override
+ public String echoQueryParam(String bar)
+ {
+ return super.echoQueryParam(bar);
+ }
+
+ @Override
+ public String echoHeaderParam(String bar)
+ {
+ return super.echoHeaderParam(bar);
+ }
+
+ @Override
+ public String echoCookieParam(String bar)
+ {
+ return super.echoCookieParam(bar);
+ }
+
+ @Override
+ public String echoTwoParams(String one, String two)
+ {
+ return super.echoTwoParams(one, two);
+ }
+
+ @Override
+ public String echoEncoded(String val)
+ {
+ return super.echoEncoded(val);
+ }
+
+ @Override
+ public String echoFormParams(MultivaluedMap<String, String> formMap)
+ {
+ return super.echoFormParams(formMap);
+ }
+
+ @Override
+ public String echoFormParams2(String[] foo)
+ {
+ return super.echoFormParams2(foo);
+ }
+
+ @Override
+ public String echoFormParams3(TestForm form)
+ {
+ return super.echoFormParams3(form);
+ }
+
+ @Override
+ public SubResource getBar(String baz)
+ {
+ return super.getBar(baz);
+ }
+
+ @Override
+ public long convertPathParam(GregorianCalendar isoDate)
+ {
+ return super.convertPathParam(isoDate);
+ }
+
+ @Override
+ public String throwException()
+ {
+ return super.throwException();
+ }
+
+ public List<String[]> getCommaSeparated(@Context HttpHeaders headers)
+ {
+ setHeaders(headers);
+ return super.getCommaSeparated();
+ }
+
+}
\ No newline at end of file
Added: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestComponent.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestComponent.java (rev 0)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestComponent.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,23 @@
+package org.jboss.seam.example.restbay.resteasy;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.AutoCreate;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Christian Bauer
+ */
+ at Name("testComponent")
+ at AutoCreate
+public class TestComponent
+{
+
+ public List<String[]> getCommaSeparated() {
+ List<String[]> csv = new ArrayList();
+ csv.add(new String[]{"foo", "bar"});
+ csv.add(new String[]{"asdf", "123"});
+ return csv;
+ }
+}
Modified: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestResource.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestResource.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/TestResource.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -1,66 +1,67 @@
package org.jboss.seam.example.restbay.resteasy;
-import org.jboss.resteasy.annotations.Form;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
-import java.util.ArrayList;
/**
* Plain JAX RS root resource, no Seam components/lifecycle.
*
* @author Christian Bauer
*/
- at Path("/test")
public class TestResource
{
@Context
- UriInfo uriInfo;
+ protected UriInfo uriInfo;
@Context
- HttpHeaders headers;
+ protected HttpHeaders headers;
- @GET
- @Path("/echouri")
+ public void setUriInfo(UriInfo uriInfo)
+ {
+ this.uriInfo = uriInfo;
+ }
+
+ public void setHeaders(HttpHeaders headers)
+ {
+ this.headers = headers;
+ }
+
public String echoUri()
{
return uriInfo.getPath();
}
- @GET
- @Path("/echoquery")
- public String echoQueryParam(@QueryParam("bar") String bar)
+ public String echoQueryParam(String bar)
{
return bar;
}
- @GET
- @Path("/echoheader")
- public String echoHeaderParam(@HeaderParam("bar") String bar)
+ public String echoHeaderParam(String bar)
{
return bar;
}
- @GET
- @Path("/echocookie")
- public String echoCookieParam(@CookieParam("bar") String bar)
+ public String echoCookieParam(String bar)
{
return bar;
}
- @GET
- @Path("/echoencoded/{val}")
- public String echoEncoded(@PathParam("val") @Encoded String val)
+ public String echoTwoParams(String one, String two)
{
+ return one+two;
+ }
+
+ public String echoEncoded(String val)
+ {
return val;
}
- @POST
- @Path("/echoformparams")
- @Consumes("application/x-www-form-urlencoded")
public String echoFormParams(MultivaluedMap<String, String> formMap)
{
String result = "";
@@ -71,9 +72,7 @@
return result;
}
- @POST
- @Path("/echoformparams2")
- public String echoFormParams2(@FormParam("foo") String[] foo)
+ public String echoFormParams2(String[] foo)
{
String result = "";
for (String s : foo)
@@ -83,44 +82,31 @@
return result;
}
- @POST
- @Path("/echoformparams3")
- public String echoFormParams3(@Form TestForm form)
+ public String echoFormParams3(TestForm form)
{
return form.toString();
}
- @Path("/foo/bar/{baz}")
- public SubResource getBar(@PathParam("baz") String baz)
+ public SubResource getBar(String baz)
{
return new SubResource(baz);
}
- @GET
- @Path("/foo/{isoDate}")
- public long convertPathParam(@PathParam("isoDate") GregorianCalendar isoDate)
+ public long convertPathParam(GregorianCalendar isoDate)
{
return isoDate.getTime().getTime();
}
- @GET
- @Path("/foo/unsupported")
public String throwException()
{
throw new UnsupportedOperationException("foo");
}
- @GET
- @Path("/foo/commaseparated")
- @Produces("text/csv")
public List<String[]> getCommaSeparated() {
assert headers.getAcceptableMediaTypes().size() == 2;
assert headers.getAcceptableMediaTypes().get(0).toString().equals("text/plain");
assert headers.getAcceptableMediaTypes().get(1).toString().equals("text/csv");
- List<String[]> csv = new ArrayList();
- csv.add(new String[]{"foo", "bar"});
- csv.add(new String[]{"asdf", "123"});
- return csv;
+ return new TestComponent().getCommaSeparated();
}
Modified: branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java
===================================================================
--- branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -4,6 +4,7 @@
import org.jboss.seam.example.restbay.test.fwk.MockHttpServletResponse;
import org.jboss.seam.example.restbay.test.fwk.MockHttpServletRequest;
import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
import static org.testng.Assert.assertEquals;
import javax.servlet.http.Cookie;
@@ -23,10 +24,20 @@
}};
}
- @Test
- public void testExeptionMapping() throws Exception
+ @DataProvider(name = "queryPaths")
+ public Object[][] getData()
{
- new ResourceRequest(Method.GET, "/restv1/test/foo/unsupported")
+ return new String[][] {
+ { "/restv1/plainTest" },
+ { "/restv1/eventComponentTest" },
+ { "/restv1/statelessEjbTest" }
+ };
+ }
+
+ @Test(dataProvider = "queryPaths")
+ public void testExeptionMapping(final String resourcePath) throws Exception
+ {
+ new ResourceRequest(Method.GET, resourcePath + "/trigger/unsupported")
{
@Override
@@ -40,22 +51,22 @@
}
- @Test
- public void testPlainResources() throws Exception
+ @Test(dataProvider = "queryPaths")
+ public void testEchos(final String resourcePath) throws Exception
{
- new ResourceRequest(Method.GET, "/restv1/test/echouri")
+ new ResourceRequest(Method.GET, resourcePath + "/echouri")
{
@Override
protected void onResponse(MockHttpServletResponse response)
{
assert response.getStatus() == 200;
- assert response.getContentAsString().equals("/test/echouri");
+ assert response.getContentAsString().endsWith("/echouri");
}
}.run();
- new ResourceRequest(Method.GET, "/restv1/test/echoquery")
+ new ResourceRequest(Method.GET, resourcePath + "/echoquery")
{
@Override
@@ -75,7 +86,7 @@
}.run();
- new ResourceRequest(Method.GET, "/restv1/test/echoheader")
+ new ResourceRequest(Method.GET, resourcePath + "/echoheader")
{
@Override
@@ -93,7 +104,7 @@
}.run();
- new ResourceRequest(Method.GET, "/restv1/test/echocookie")
+ new ResourceRequest(Method.GET, resourcePath + "/echocookie")
{
@Override
@@ -111,7 +122,7 @@
}.run();
- new ResourceRequest(Method.GET, "/restv1/test/foo/bar/asdf")
+ new ResourceRequest(Method.GET, resourcePath + "/foo/bar/asdf")
{
@Override
@@ -124,12 +135,24 @@
}.run();
+ new ResourceRequest(Method.GET, resourcePath + "/echotwoparams/foo/bar")
+ {
+
+ @Override
+ protected void onResponse(MockHttpServletResponse response)
+ {
+ assert response.getStatus() == 200;
+ assert response.getContentAsString().equals("foobar");
+ }
+
+ }.run();
+
}
- @Test
- public void testEncoding() throws Exception
+ @Test(dataProvider = "queryPaths")
+ public void testEncoding(final String resourcePath) throws Exception
{
- new ResourceRequest(Method.GET, "/restv1/test/echoencoded/foo bar")
+ new ResourceRequest(Method.GET, resourcePath + "/echoencoded/foo bar")
{
@Override
@@ -142,10 +165,10 @@
}.run();
}
- @Test
- public void testFormHandling() throws Exception
+ @Test(dataProvider = "queryPaths")
+ public void testFormHandling(final String resourcePath) throws Exception
{
- new ResourceRequest(Method.POST, "/restv1/test/echoformparams")
+ new ResourceRequest(Method.POST, resourcePath + "/echoformparams")
{
@Override
@@ -164,7 +187,7 @@
}.run();
- new ResourceRequest(Method.POST, "/restv1/test/echoformparams2")
+ new ResourceRequest(Method.POST, resourcePath + "/echoformparams2")
{
@Override
@@ -183,7 +206,7 @@
}.run();
- new ResourceRequest(Method.POST, "/restv1/test/echoformparams3")
+ new ResourceRequest(Method.POST, resourcePath + "/echoformparams3")
{
@Override
@@ -205,13 +228,13 @@
}
- @Test
- public void testStringConverter() throws Exception
+ @Test(dataProvider = "queryPaths")
+ public void testStringConverter(final String resourcePath) throws Exception
{
final String ISO_DATE = "2007-07-10T14:54:56-0500";
final String ISO_DATE_MILLIS = "1184097296000";
- new ResourceRequest(Method.GET, "/restv1/test/foo/" + ISO_DATE)
+ new ResourceRequest(Method.GET, resourcePath + "/convertDate/" + ISO_DATE)
{
@Override
@@ -225,11 +248,11 @@
}
- @Test
- public void testProvider() throws Exception
+ @Test(dataProvider = "queryPaths")
+ public void testProvider(final String resourcePath) throws Exception
{
- new ResourceRequest(Method.GET, "/restv1/test/foo/commaseparated")
+ new ResourceRequest(Method.GET, resourcePath + "/commaSeparated")
{
@Override
Modified: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/Application.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/Application.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/Application.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -23,8 +23,8 @@
public class Application extends javax.ws.rs.core.Application
{
- private Map<Class<?>, Set<Component>> providerClasses = new HashMap<Class<?>, Set<Component>>();
- private Map<Class<?>, Set<Component>> resourceClasses = new HashMap<Class<?>, Set<Component>>();
+ final private Map<Class<?>, Set<Component>> providerClasses = new HashMap<Class<?>, Set<Component>>();
+ final private Map<Class<?>, Set<Component>> resourceClasses = new HashMap<Class<?>, Set<Component>>();
private List<String> providerClassNames = new ArrayList<String>();
private List<String> resourceClassNames = new ArrayList<String>();
Modified: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceHome.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceHome.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceHome.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -42,7 +42,6 @@
import org.jboss.resteasy.core.Headers;
import org.jboss.resteasy.core.StringParameterInjector;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.seam.Entity;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.framework.Home;
@@ -59,7 +58,9 @@
* @param <T> Entity class
* @param <T2> Entity id class
*/
- at Path("")
+// Empty @Path because it's ignored by second-stage bootstrap if not subclassed or in components.xml
+// but we need it as a marker so we'll find components.xml declarations during first stage of bootstrap.
+ at Path("")
public class ResourceHome<T, T2> extends AbstractResource<T>
{
private EntityHomeWrapper<T> entityHome = null;
@@ -263,7 +264,7 @@
private T unmarshallEntity(InputStream is)
{
Class<T> entityClass = getEntityClass();
- MessageBodyReader<T> reader = ResteasyProviderFactory.getInstance().getMessageBodyReader(entityClass, entityClass, entityClass.getAnnotations(), requestContentType);
+ MessageBodyReader<T> reader = SeamResteasyProviderFactory.getInstance().getMessageBodyReader(entityClass, entityClass, entityClass.getAnnotations(), requestContentType);
if (reader == null)
{
throw new RuntimeException("Unable to find MessageBodyReader for content type " + requestContentType);
@@ -288,7 +289,7 @@
*/
private T2 unmarshallId(String id)
{
- StringParameterInjector injector = new StringParameterInjector(getEntityIdClass(), getEntityIdClass(), "id", PathParam.class, null, null, ResteasyProviderFactory.getInstance());
+ StringParameterInjector injector = new StringParameterInjector(getEntityIdClass(), getEntityIdClass(), "id", PathParam.class, null, null, SeamResteasyProviderFactory.getInstance());
return (T2) injector.extractValue(id);
}
Modified: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceQuery.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceQuery.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResourceQuery.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -48,6 +48,8 @@
*
* @param <T> entity type
*/
+// Empty @Path because it's ignored by second-stage bootstrap if not subclassed or in components.xml
+// but we need it as a marker so we'll find components.xml declarations during first stage of bootstrap.
@Path("")
public class ResourceQuery<T> extends AbstractResource<T>
{
@@ -109,8 +111,7 @@
public Type[] getActualTypeArguments()
{
- Type[] types = { getEntityClass() };
- return types;
+ return new Type[] { getEntityClass() };
}
};
return Response.ok(new GenericEntity(result, responseType)
Modified: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyBootstrap.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyBootstrap.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyBootstrap.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -2,12 +2,21 @@
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Startup;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Logger;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Create;
import org.jboss.seam.deployment.AnnotationDeploymentHandler;
import org.jboss.seam.deployment.DeploymentStrategy;
-import org.jboss.seam.annotations.*;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.log.Log;
import org.jboss.seam.util.Reflections;
+import org.jboss.seam.util.EJB;
+import org.jboss.resteasy.core.ThreadLocalResteasyProviderFactory;
import java.util.Collection;
import java.util.HashSet;
@@ -17,6 +26,8 @@
/**
* Scans annoated JAX-RS resources and providers, optionally registers them as Seam components.
+ * It does so by populating the <tt>Application</tt> instance, which is then processed further
+ * by the <tt>ResteasyDispatcher</tt> during startup.
*
* @author Christian Bauer
*/
@@ -24,7 +35,7 @@
@Scope(ScopeType.APPLICATION)
@Startup
@AutoCreate
- at Install(classDependencies = "org.jboss.resteasy.core.Dispatcher")
+ at Install(classDependencies = "org.jboss.resteasy.spi.ResteasyProviderFactory")
public class ResteasyBootstrap
{
@@ -34,11 +45,23 @@
@In
protected Application application;
+ private SeamResteasyProviderFactory providerFactory;
+ public SeamResteasyProviderFactory getProviderFactory()
+ {
+ return providerFactory;
+ }
+
@Create
- public void onStartup()
+ public void init()
{
- log.info("deploying RESTEasy providers and resources");
+ log.info("starting RESTEasy with custom SeamResteasyProviderFactory");
+ providerFactory = new SeamResteasyProviderFactory();
+ // Always use the "deployment sensitive" factory - that means it is handled through ThreadLocal, not static
+ SeamResteasyProviderFactory.setInstance(new ThreadLocalResteasyProviderFactory(getProviderFactory()));
+
+ log.info("deploying JAX-RS application");
+
Collection<Class<?>> annotatedProviderClasses = null;
Collection<Class<?>> annotatedResourceClasses = null;
if (application.isScanProviders() || application.isScanResources())
@@ -162,9 +185,16 @@
log.debug("adding resource Seam components {0} for class {1}", components, resourceClass);
application.addResourceClass(resourceClass, components);
}
+ // Check if it is a @Path annotated EJB interface
+ else if (resourceClass.isAnnotationPresent(EJB.LOCAL) ||
+ resourceClass.isAnnotationPresent(EJB.REMOTE))
+ {
+ log.debug("ignoring @Path annotated EJB interface, add the bean " +
+ "implementation to <resteasy:resource-class-names/>: " + resourceClass.getName());
+ }
else
{
- log.debug("adding resource class with JAX-RS default lifecycle: " + resourceClass.getName());
+ log.debug("adding resource class: " + resourceClass.getName());
application.addResourceClass(resourceClass);
}
}
Modified: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyDispatcher.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyDispatcher.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyDispatcher.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -1,30 +1,35 @@
package org.jboss.seam.resteasy;
-import java.util.Set;
-
+import org.jboss.resteasy.core.SynchronousDispatcher;
+import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
+import org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory;
+import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher;
+import org.jboss.resteasy.spi.ResourceFactory;
+import org.jboss.resteasy.spi.StringConverter;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
-import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.Seam;
+import org.jboss.seam.core.Init;
+import org.jboss.seam.util.EJB;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.In;
-import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
+import org.jboss.seam.annotations.JndiName;
import org.jboss.seam.log.Log;
-import org.jboss.resteasy.core.AsynchronousDispatcher;
-import org.jboss.resteasy.core.PropertyInjectorImpl;
-import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
-import org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory;
-import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher;
-import org.jboss.resteasy.spi.*;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import java.util.Set;
+
/**
* An extended version of the RESTEasy dispatcher, configured on Seam application
* startup with a custom JAX RS <tt>Application</tt> instance. Registers custom resource
- * and provider lifecycle handlers.
+ * and provider lifecycle handlers with RESTEasy, depending on configured/detected resources
+ * from <tt>ResteasyBootstrap</tt>.
*
* @author Christian Bauer
*/
@@ -32,25 +37,41 @@
@Scope(ScopeType.APPLICATION)
@Startup(depends = "org.jboss.seam.resteasy.bootstrap")
@AutoCreate
- at Install(classDependencies = "org.jboss.resteasy.core.Dispatcher")
public class ResteasyDispatcher extends HttpServletDispatcher
{
@In
- Application application;
+ protected Application application;
+ @In
+ protected ResteasyBootstrap bootstrap;
+
@Logger
- Log log;
+ private Log log;
@Create
- public void onStartup()
+ public void init()
{
+ try
+ {
+ init(null);
+ }
+ catch (ServletException ex)
+ {
+ // Can never happen
+ }
+ }
+
+ @Override
+ public void init(ServletConfig servletConfig) throws ServletException
+ {
+ // We can skip the init, it only sets up the provider factory (did that already in bootstrap) and
+ // the other stuff we do in onStartup(). We also do NOT put the ResteasyProviderFactory, the Dispatcher,
+ // nor the Registry into the servlet context. Let's hope RESTEasy code is sane enough not to access the
+ // servlet context at runtime...
log.debug("registering RESTEasy and JAX RS resources and providers");
+ setDispatcher(new SynchronousDispatcher(bootstrap.getProviderFactory()));
- ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
- ResteasyProviderFactory.setInstance(providerFactory); // This is really necessary
- setDispatcher(new AsynchronousDispatcher(providerFactory));
-
getDispatcher().setLanguageMappings(application.getLanguageMappings());
getDispatcher().setMediaTypeMappings(application.getMediaTypeMappings());
@@ -58,145 +79,160 @@
if (application.isUseBuiltinProviders())
{
log.info("registering built-in RESTEasy providers");
- RegisterBuiltin.register(providerFactory);
+ RegisterBuiltin.register(getDispatcher().getProviderFactory());
}
+
for (Class providerClass : application.getProviderClasses())
{
- Set<Component> seamComponents = application.getProviderClassComponent(providerClass);
- if (seamComponents != null)
+ Set<Component> components = application.getProviderClassComponent(providerClass);
+ if (components != null)
{
- for (Component seamComponent : seamComponents)
- {
- if (ScopeType.STATELESS.equals(seamComponent.getScope()))
- {
- throw new RuntimeException(
- "Registration of STATELESS Seam components as RESTEasy providers not implemented!"
- );
- }
- else if (ScopeType.APPLICATION.equals(seamComponent.getScope()))
- {
- Object providerInstance = Component.getInstance(seamComponent.getName());
- boolean isStringConverter = false;
- for (Class componentIface : seamComponent.getBusinessInterfaces())
- {
- if (StringConverter.class.isAssignableFrom(componentIface))
- {
- isStringConverter = true;
- break;
- }
- }
- if (isStringConverter)
- {
- log.error("can't register Seam component as RESTEasy StringConverter, see: https://jira.jboss.org/jira/browse/JBSEAM-4020");
- //log.debug("registering Seam component as custom RESTEasy string converter provider: " + seamComponent.getName());
- //providerFactory.addStringConverter((StringConverter)providerInstance);
- }
- else
- {
- providerFactory.registerProviderInstance(providerInstance);
- }
- }
- }
+ registerSeamComponentProviders(components, providerClass);
}
else
{
- // Just plain RESTEasy, no Seam component lookup or lifecycle
- if (StringConverter.class.isAssignableFrom(providerClass))
- {
- log.debug("registering as custom RESTEasy string converter provider class: " + providerClass);
- providerFactory.addStringConverter(providerClass);
- }
- else
- {
- providerFactory.registerProvider(providerClass);
- }
+ registerProvider(providerClass);
}
}
// Resource registration
- Registry registry = getDispatcher().getRegistry();
for (final Class resourceClass : application.getClasses())
{
- log.debug("registering JAX RS resource class: " + resourceClass);
+ // First check if it's a class that is a Seam component
Set<Component> components = application.getResourceClassComponent(resourceClass);
if (components != null)
{
- log.debug("registering all {0} components of {1}", components.size(), resourceClass);
- // Register every component
- for (final Component seamComponent : components)
- {
- // Seam component lookup when call is dispatched to resource
- ResourceFactory factory = new ResourceFactory()
- {
+ registerSeamComponentResources(components, resourceClass);
+ }
+ else
+ {
+ registerResource(resourceClass);
+ }
+ }
- public Class<?> getScannableClass()
- {
- return resourceClass;
- }
+ }
- public void registered(InjectorFactory factory)
- {
- // Wrap the Resteasy PropertyInjectorImpl in a Seam interceptor (for @Context injection)
- seamComponent.addInterceptor(
- new ResteasyContextInjectionInterceptor(
- new PropertyInjectorImpl(getScannableClass(), dispatcher.getProviderFactory())
- )
- );
- // NOTE: Adding an interceptor to Component at this stage means that the interceptor is
- // always executed last in the chain. The sorting of interceptors of a Component occurs
- // only when the Component metadata is instantiated. This is OK in this case, as the
- // JAX RS @Context injection can occur last after all other interceptors executed.
+ protected void registerSeamComponentProviders(Set<Component> components, Class providerClass) {
+ for (Component seamComponent : components)
+ {
+ if (ScopeType.STATELESS.equals(seamComponent.getScope()))
+ {
+ throw new RuntimeException(
+ "Registration of STATELESS Seam components as RESTEasy providers not implemented!"
+ );
+ }
+ else if (ScopeType.APPLICATION.equals(seamComponent.getScope()))
+ {
+ Object providerInstance = Component.getInstance(seamComponent.getName());
+ boolean isStringConverter = false;
+ for (Class componentIface : seamComponent.getBusinessInterfaces())
+ {
+ if (StringConverter.class.isAssignableFrom(componentIface))
+ {
+ isStringConverter = true;
+ break;
+ }
+ }
+ if (isStringConverter)
+ {
+ log.error("can't register Seam component as RESTEasy StringConverter, see: https://jira.jboss.org/jira/browse/JBSEAM-4020");
+ //log.debug("registering Seam component as custom RESTEasy string converter provider: " + seamComponent.getName());
+ //getDispatcher().getProviderFactory().addStringConverter((StringConverter)providerInstance);
+ }
+ else
+ {
+ getDispatcher().getProviderFactory().registerProviderInstance(providerInstance);
+ }
+ }
+ }
+ }
- }
+ protected void registerSeamComponentResources(Set<Component> components, Class resourceClass) {
+ for (final Component seamComponent : components)
+ {
+ // Seam component lookup when call is dispatched to resource
+ ResourceFactory factory =
+ new SeamResteasyResourceFactory(resourceClass, seamComponent, getDispatcher().getProviderFactory());
- public Object createResource(HttpRequest request, HttpResponse response, InjectorFactory factory)
- {
- // Push this onto event context so we have it available in ResteasyContextInjectionInterceptor
- Contexts.getEventContext().set(ResteasyContextInjectionInterceptor.RE_HTTP_REQUEST_VAR, request);
- Contexts.getEventContext().set(ResteasyContextInjectionInterceptor.RE_HTTP_RESPONSE_VAR, response);
- return Component.getInstance(seamComponent.getName());
- }
+ // Register component on specific path if the component is a ResourceHome or ResourceQuery component configured in components.xml
+ if (seamComponent.getBeanClass().equals(ResourceHome.class) || seamComponent.getBeanClass().equals(ResourceQuery.class))
+ {
- public void requestFinished(HttpRequest request, HttpResponse response, Object resource)
- {
- }
-
- public void unregistered()
- {
- }
- };
- // Register component on specific path if the component is a ResourceHome or ResourceQuery component configured in components.xml
- if (seamComponent.getBeanClass().equals(ResourceHome.class) || seamComponent.getBeanClass().equals(ResourceQuery.class))
- {
- AbstractResource instance = (AbstractResource) seamComponent.newInstance();
- String path = instance.getPath();
- if (instance.getPath() != null)
- {
- log.debug("registering resource {0} on path {1}", seamComponent.getName(), path);
- registry.addResourceFactory(factory, path);
- } else {
- log.warn("Unable to register {0} resource on null path.", seamComponent.getName());
- }
- }
- else
- {
- log.debug("registering resource {0}", seamComponent.getName());
- registry.addResourceFactory(factory);
- }
+ // We can always instantiate this safely here because it can't have dependencies!
+ AbstractResource instance = (AbstractResource) seamComponent.newInstance();
+ String path = instance.getPath();
+ if (instance.getPath() != null)
+ {
+ log.debug("registering resource {0} on path {1} with Seam component lifecycle", seamComponent.getName(), path);
+ getDispatcher().getRegistry().addResourceFactory(factory, path);
}
+ else
+ {
+ log.warn("Unable to register {0} resource on null path, check components.xml", seamComponent.getName());
+ }
}
else
{
- // ResourceHome and ResourceQuery won't be registered if not declared as a component
- if (ResourceHome.class.equals(resourceClass) || ResourceQuery.class.equals(resourceClass))
- continue;
-
- // JAX-RS default lifecycle
- log.info("registering resource {0} with default JAX-RS lifecycle", resourceClass);
- registry.addResourceFactory(new POJOResourceFactory(resourceClass));
+ log.debug("registering resource {0} with Seam component lifecycle", seamComponent.getName());
+ getDispatcher().getRegistry().addResourceFactory(factory);
}
}
}
+
+ protected void registerProvider(Class providerClass) {
+ // Just plain RESTEasy, no Seam component lookup or lifecycle
+ if (StringConverter.class.isAssignableFrom(providerClass))
+ {
+ log.debug("registering as custom RESTEasy string converter provider class: " + providerClass);
+ getDispatcher().getProviderFactory().addStringConverter(providerClass);
+ }
+ else
+ {
+ getDispatcher().getProviderFactory().registerProvider(providerClass);
+ }
+ }
+
+ protected void registerResource(Class resourceClass) {
+ // ResourceHome and ResourceQuery have an empty @Path("") and are supposed to be subclassed before use
+ // (or through components.xml) - they should be ignored if they are not proper Seam components
+ if (ResourceHome.class.equals(resourceClass) || ResourceQuery.class.equals(resourceClass))
+ return;
+
+ // Plain EJBs (not a Seam component) can be registered in RESTEasy by JNDI name
+ if (resourceClass.isAnnotationPresent(EJB.STATELESS) || resourceClass.isAnnotationPresent(EJB.STATEFUL))
+ {
+ String jndiName = getJndiName(resourceClass);
+ log.debug("registering plain EJB resource as RESTEasy JNDI resource name: " + jndiName);
+ getDispatcher().getRegistry().addJndiResource(jndiName);
+
+ }
+ else
+ {
+ // JAX-RS default lifecycle
+ log.debug("registering resource {0} with default JAX-RS lifecycle", resourceClass.getName());
+ getDispatcher().getRegistry().addResourceFactory(new POJOResourceFactory(resourceClass));
+ }
+ }
+
+ protected String getJndiName(Class<?> beanClass)
+ {
+ if (beanClass.isAnnotationPresent(JndiName.class))
+ {
+ return beanClass.getAnnotation(JndiName.class).value();
+ }
+ else
+ {
+ String jndiPattern = Init.instance().getJndiPattern();
+ if (jndiPattern == null)
+ {
+ throw new IllegalArgumentException(
+ "You must specify org.jboss.seam.core.init.jndiPattern or use @JndiName: " + beanClass.getName()
+ );
+ }
+ return jndiPattern.replace("#{ejbName}", Seam.getEjbName(beanClass));
+ }
+ }
+
}
Modified: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyResourceAdapter.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyResourceAdapter.java 2009-04-24 13:13:27 UTC (rev 10627)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/ResteasyResourceAdapter.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -5,11 +5,13 @@
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.log.Log;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
import org.jboss.seam.web.AbstractResource;
import org.jboss.resteasy.core.SynchronousDispatcher;
+import org.jboss.resteasy.core.ThreadLocalResteasyProviderFactory;
import org.jboss.resteasy.plugins.server.servlet.HttpServletInputMessage;
import org.jboss.resteasy.plugins.server.servlet.HttpServletResponseWrapper;
import org.jboss.resteasy.plugins.server.servlet.ServletSecurityContext;
@@ -19,7 +21,6 @@
import org.jboss.resteasy.specimpl.UriInfoImpl;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.util.PathHelper;
import javax.servlet.ServletException;
@@ -28,6 +29,7 @@
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
@@ -49,10 +51,21 @@
@Logger
Log log;
+ protected ResteasyDispatcher dispatcher;
+ protected Application application;
+
+ @Create
+ public void init()
+ {
+ // No injection, so lookup on first request
+ dispatcher = (ResteasyDispatcher) Component.getInstance(ResteasyDispatcher.class);
+ application = (Application) Component.getInstance(Application.class);
+ }
+
@Override
public String getResourcePath()
{
- Application appConfig = (Application)Component.getInstance(Application.class);
+ Application appConfig = (Application) Component.getInstance(Application.class);
return appConfig.getResourcePathPrefix();
}
@@ -61,13 +74,18 @@
throws ServletException, IOException
{
- // Wrap in RESTEasy contexts
- try {
+ try
+ {
log.debug("processing REST request");
- ResteasyProviderFactory.pushContext(HttpServletRequest.class, request);
- ResteasyProviderFactory.pushContext(HttpServletResponse.class, response);
- ResteasyProviderFactory.pushContext(SecurityContext.class, new ServletSecurityContext(request));
+ // Wrap in RESTEasy thread-local factory handling
+ ThreadLocalResteasyProviderFactory.push(dispatcher.getDispatcher().getProviderFactory());
+
+ // Wrap in RESTEasy contexts (this also puts stuff in a thread-local)
+ SeamResteasyProviderFactory.pushContext(HttpServletRequest.class, request);
+ SeamResteasyProviderFactory.pushContext(HttpServletResponse.class, response);
+ SeamResteasyProviderFactory.pushContext(SecurityContext.class, new ServletSecurityContext(request));
+
// Wrap in Seam contexts
new ContextualHttpServletRequest(request)
{
@@ -76,51 +94,80 @@
{
HttpHeaders headers = ServletUtil.extractHttpHeaders(request);
- URI absolutePath;
- try
- {
- URL absolute = new URL(request.getRequestURL().toString());
+ UriInfoImpl uriInfo = extractUriInfo(request);
- UriBuilderImpl builder = new UriBuilderImpl();
- builder.scheme(absolute.getProtocol());
- builder.host(absolute.getHost());
- builder.port(absolute.getPort());
- builder.path(absolute.getPath());
- builder.replaceQuery(absolute.getQuery());
- absolutePath = builder.build();
- }
- catch (MalformedURLException e)
- {
- throw new RuntimeException(e);
- }
+ HttpResponse theResponse = new HttpServletResponseWrapper(
+ response,
+ dispatcher.getDispatcher().getProviderFactory()
+ );
- String path = PathHelper.getEncodedPathInfo(absolutePath.getRawPath(), request.getContextPath());
+ HttpRequest in = new HttpServletInputMessage(
+ request,
+ theResponse,
+ headers,
+ uriInfo,
+ request.getMethod().toUpperCase(),
+ (SynchronousDispatcher) dispatcher.getDispatcher()
+ );
- Application appConfig = (Application)Component.getInstance(Application.class);
- if (appConfig.isStripSeamResourcePath()) {
- log.trace("removing SeamResourceServlet url-pattern and dispatcher prefix from request path");
- path = path.substring(path.indexOf(getResourcePath())+getResourcePath().length());
- }
-
- log.debug("final request path: " + path);
- List<PathSegment> pathSegments = PathSegmentImpl.parseSegments(path);
- UriInfoImpl uriInfo = new UriInfoImpl(absolutePath, path, request.getQueryString(), pathSegments);
-
- HttpRequest in;
- ResteasyDispatcher dispatcher =
- (ResteasyDispatcher) Component.getInstance(ResteasyDispatcher.class);
- HttpResponse theResponse =
- new HttpServletResponseWrapper(response, dispatcher.getDispatcher().getProviderFactory());
- in = new HttpServletInputMessage(
- request, theResponse, headers, uriInfo, request.getMethod().toUpperCase(), (SynchronousDispatcher)dispatcher.getDispatcher());
-
dispatcher.getDispatcher().invoke(in, theResponse);
}
}.run();
- } finally {
- ResteasyProviderFactory.clearContextData();
+ }
+ finally
+ {
+ // Clean up the thread-locals
+ SeamResteasyProviderFactory.clearContextData();
+ ThreadLocalResteasyProviderFactory.pop();
log.debug("completed processing of REST request");
}
}
+
+ // Replaces the static ServletUtil.extractUriInfo(), removes the Seam-related sub-path
+ protected UriInfoImpl extractUriInfo(HttpServletRequest request)
+ {
+ String contextPath = request.getContextPath();
+ URI absolutePath;
+ try
+ {
+ URL absolute = new URL(request.getRequestURL().toString());
+
+ UriBuilderImpl builder = new UriBuilderImpl();
+ builder.scheme(absolute.getProtocol());
+ builder.host(absolute.getHost());
+ builder.port(absolute.getPort());
+ builder.path(absolute.getPath());
+ builder.replaceQuery(absolute.getQuery());
+ absolutePath = builder.build();
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ String path = PathHelper.getEncodedPathInfo(absolutePath.getRawPath(), contextPath);
+
+ if (application.isStripSeamResourcePath())
+ {
+ log.debug("removing SeamResourceServlet url-pattern and dispatcher prefix from request path");
+ path = path.substring(path.indexOf(getResourcePath()) + getResourcePath().length());
+ }
+
+ List<PathSegment> pathSegments = PathSegmentImpl.parseSegments(path);
+ URI baseURI = absolutePath;
+ if (!path.trim().equals(""))
+ {
+ String tmpContextPath = contextPath;
+ if (!tmpContextPath.endsWith("/")) tmpContextPath += "/";
+ baseURI = UriBuilder.fromUri(absolutePath).replacePath(tmpContextPath).build();
+ }
+
+ log.debug("UriInfo, absolute URI : " + absolutePath);
+ log.debug("UriInfo, base URI : " + baseURI);
+ log.debug("UriInfo, relative path/@Path: " + path);
+ log.debug("UriInfo, query string : " + request.getQueryString());
+
+ return new UriInfoImpl(absolutePath, baseURI, path, request.getQueryString(), pathSegments);
+ }
}
Added: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyProviderFactory.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyProviderFactory.java (rev 0)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyProviderFactory.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,25 @@
+package org.jboss.seam.resteasy;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+/**
+ * TODO: We need to significantly extend and change that class so we can lookup provider instances
+ * through Seam at runtime. The original class has only been designed for registration of "singleton"
+ * providers during startup.
+ *
+ * @author Christian Bauer
+ */
+public class SeamResteasyProviderFactory extends ResteasyProviderFactory
+{
+
+ public static void setInstance(ResteasyProviderFactory factory)
+ {
+ ResteasyProviderFactory.setInstance(factory);
+ }
+
+ public static ResteasyProviderFactory getInstance()
+ {
+ return ResteasyProviderFactory.getInstance();
+ }
+
+}
Added: branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyResourceFactory.java
===================================================================
--- branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyResourceFactory.java (rev 0)
+++ branches/community/Seam_2_1/src/resteasy/org/jboss/seam/resteasy/SeamResteasyResourceFactory.java 2009-04-24 13:29:32 UTC (rev 10628)
@@ -0,0 +1,73 @@
+package org.jboss.seam.resteasy;
+
+import org.jboss.resteasy.spi.ResourceFactory;
+import org.jboss.resteasy.spi.InjectorFactory;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.jboss.resteasy.spi.HttpResponse;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.jboss.resteasy.core.PropertyInjectorImpl;
+
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.Component;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.log.Logging;
+
+/**
+ * Looks up Seam component in Seam contexts when a JAX RS resource is requested.
+ *
+ * @author Christian Bauer
+ */
+public class SeamResteasyResourceFactory implements ResourceFactory
+{
+ Log log = Logging.getLog(SeamResteasyResourceFactory.class);
+
+ private final Class<?> resourceClass;
+ private final Component seamComponent;
+ private final ResteasyProviderFactory providerFactory;
+
+ public SeamResteasyResourceFactory(Class<?> resourceClass, Component seamComponent, ResteasyProviderFactory providerFactory)
+ {
+ this.resourceClass = resourceClass;
+ this.seamComponent = seamComponent;
+ this.providerFactory = providerFactory;
+ }
+
+ public Class<?> getScannableClass()
+ {
+ return resourceClass;
+ }
+
+ public void registered(InjectorFactory factory)
+ {
+ // Wrap the Resteasy PropertyInjectorImpl in a Seam interceptor (for @Context injection)
+ seamComponent.addInterceptor(
+ new ResteasyContextInjectionInterceptor(
+ new PropertyInjectorImpl(getScannableClass(), providerFactory)
+ )
+ );
+
+ // NOTE: Adding an interceptor to Component at this stage means that the interceptor is
+ // always executed last in the chain. The sorting of interceptors of a Component occurs
+ // only when the Component metadata is instantiated. This is OK in this case, as the
+ // JAX RS @Context injection can occur last after all other interceptors executed.
+
+ }
+
+ public Object createResource(HttpRequest request, HttpResponse response, InjectorFactory factory)
+ {
+ // Push this onto event context so we have it available in ResteasyContextInjectionInterceptor
+ Contexts.getEventContext().set(ResteasyContextInjectionInterceptor.RE_HTTP_REQUEST_VAR, request);
+ Contexts.getEventContext().set(ResteasyContextInjectionInterceptor.RE_HTTP_RESPONSE_VAR, response);
+ log.debug("creating RESTEasy resource instance by looking up Seam component: " + seamComponent.getName());
+ return Component.getInstance(seamComponent.getName());
+ }
+
+ public void requestFinished(HttpRequest request, HttpResponse response, Object resource)
+ {
+ }
+
+ public void unregistered()
+ {
+ }
+
+}
More information about the seam-commits
mailing list