Permalink
Browse files

Add a default scanning method for class annotated with the @Service a…

…nnotation
  • Loading branch information...
1 parent 7c6f750 commit 9c68f4a0fdbb8946afef0f203300cf38ea62ac65 @jfarcand jfarcand committed Jun 10, 2011
@@ -20,7 +20,7 @@
* A maker annotation that can be used when annotating {@link org.sonatype.restsimple.api.ServiceDefinition} or POJO
* used with the service-decriptor-creator module.
*/
-@Target({ElementType.METHOD})
+@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
@@ -23,9 +23,11 @@
public interface ServiceDefinitionConfig {
/**
- * Return the a list of ServiceDefinition.
+ * Return the a list of ServiceDefinition to generate. By default this method scan the classpath in search
+ * for class annotated with the @Service annotation, and search for method that returns an instance of {@link ServiceDefinition}
+ *
* @param injector a Guice {@link Injector}
- * @return the a list of ServiceDefinition.
+ * @return the a list of ServiceDefinition to generate.
*/
List<ServiceDefinition> defineServices(Injector injector);
@@ -46,6 +48,6 @@
*
* @param packageName the package name
*/
- void scan(Package packageName);
+ ServiceDefinitionConfig scan(Package packageName);
}
@@ -15,6 +15,9 @@
import com.google.inject.Injector;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.restsimple.annotation.Service;
import org.sonatype.restsimple.api.DefaultServiceDefinition;
import org.sonatype.restsimple.api.ServiceDefinition;
import org.sonatype.restsimple.jaxrs.impl.ContentNegotiationFilter;
@@ -28,6 +31,8 @@
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -41,6 +46,7 @@
* Base class for deploying {@link ServiceDefinition} to a JAXRS implementation.
*/
public class JaxrsConfig extends ServletModule implements ServiceDefinitionConfig {
+ private final Logger logger = LoggerFactory.getLogger(JaxrsConfig.class);
private Injector parent;
private Injector injector;
@@ -130,7 +136,37 @@ protected final void configureServlets() {
*/
@Override
public List<ServiceDefinition> defineServices(Injector injector) {
- return null;
+
+ Set<Class<?>> set = new HashSet<Class<?>>();
+ for (Package pkg : packages) {
+ //look for any classes annotated with @Service
+ set.addAll(Classes.matching(
+ annotatedWith(Service.class)
+ ).in(pkg));
+ }
+
+ List<ServiceDefinition> list = new ArrayList<ServiceDefinition>();
+ // Now let's find the method that returns a ServiceDefinition
+ for(Class<?> clazz : set) {
+
+ Object o = injector.getInstance(clazz);
+ Method[] methods = clazz.getMethods();
+ for(Method method: methods) {
+ Class<?> returnType = method.getReturnType();
+ ServiceDefinition sd;
+ if (returnType.equals(ServiceDefinition.class)) {
+ try {
+ sd = ServiceDefinition.class.cast(method.invoke(o, null));
+ list.add(sd);
+ } catch (IllegalAccessException e) {
+ logger.trace("defineServices",e);
+ } catch (InvocationTargetException e) {
+ logger.trace("defineServices",e);
+ }
+ }
+ }
+ }
+ return list;
}
/**
@@ -153,8 +189,9 @@ public Injector injector() {
* {@inheritDoc}
*/
@Override
- public void scan(Package packageName) {
+ public JaxrsConfig scan(Package packageName) {
packages.add(packageName);
+ return this;
}
}
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * The Apache License v2.0 is available at
+ * http://www.apache.org/licenses/LICENSE-2.0.html
+ * You may elect to redistribute this code under either of these licenses.
+ *******************************************************************************/
+package org.sonatype.restsimple.jaxrs.test.serviceDiscovery;
+
+import org.sonatype.restsimple.annotation.Service;
+import org.sonatype.restsimple.api.Action;
+import org.sonatype.restsimple.api.GetServiceHandler;
+import org.sonatype.restsimple.api.MediaType;
+import org.sonatype.restsimple.api.PostServiceHandler;
+import org.sonatype.restsimple.api.ServiceDefinition;
+import org.sonatype.restsimple.common.test.petstore.Pet;
+import org.sonatype.restsimple.common.test.petstore.PetstoreAction;
+
+import javax.inject.Inject;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+@Service
+public class PetServiceDiscovery {
+ private final static MediaType JSON = new MediaType(PetstoreAction.APPLICATION, PetstoreAction.JSON);
+
+ @Inject
+ ServiceDefinition serviceDefinition;
+
+ public ServiceDefinition pet() {
+ Action action = new PetstoreAction();
+
+ serviceDefinition
+ .withHandler(new GetServiceHandler("/get/:pet", action).consumeWith(JSON, Pet.class).producing(JSON))
+ .withHandler(new PostServiceHandler("/create/:pet", action).consumeWith(JSON, Pet.class).producing(JSON))
+ .extendWith(Extension.class);
+ return serviceDefinition;
+ }
+
+ @Path("/lolipet/{myPet}")
+ public final static class Extension {
+ @GET
+ @Consumes("application/vnd.org.sonatype.rest+json")
+ public Pet lolipet(){
+ return new Pet("lolipet");
+ }
+ }
+}
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * The Apache License v2.0 is available at
+ * http://www.apache.org/licenses/LICENSE-2.0.html
+ * You may elect to redistribute this code under either of these licenses.
+ *******************************************************************************/
+package org.sonatype.restsimple.jaxrs.test.serviceDiscovery;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
+import org.sonatype.restsimple.jaxrs.guice.JaxrsConfig;
+
+public class ServiceDiscoveryJaxrsConfig extends GuiceServletContextListener {
+
+ @Override
+ protected Injector getInjector() {
+ return Guice.createInjector( new JaxrsConfig().scan(ServiceDiscoveryJaxrsConfig.class.getPackage() ) );
+ }
+}
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * The Apache License v2.0 is available at
+ * http://www.apache.org/licenses/LICENSE-2.0.html
+ * You may elect to redistribute this code under either of these licenses.
+ *******************************************************************************/
+package org.sonatype.restsimple.jaxrs.test.serviceDiscovery;
+
+import com.google.inject.servlet.GuiceFilter;
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.Response;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.restsimple.common.test.petstore.PetstoreAction;
+import org.sonatype.restsimple.jaxrs.test.petstore.PetstoreJaxrsConfig;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class ServiceDiscoveryJaxrsTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceDiscoveryJaxrsTest.class);
+
+ protected Server server;
+
+ public int port;
+
+ public String targetUrl;
+
+ public String acceptHeader;
+
+ protected int findFreePort() throws IOException {
+ ServerSocket socket = null;
+
+ try {
+ socket = new ServerSocket(0);
+
+ return socket.getLocalPort();
+ }
+ finally {
+ if (socket != null) {
+ socket.close();
+ }
+ }
+ }
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpGlobal() throws Exception {
+ port = findFreePort();
+ server = new Server(port);
+ acceptHeader = PetstoreAction.APPLICATION + "/" + PetstoreAction.JSON;
+
+ targetUrl = "http://127.0.0.1:" + port;
+
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ context.addFilter(GuiceFilter.class, "/*", 0);
+ context.addEventListener(new PetstoreJaxrsConfig());
+ context.addServlet(DefaultServlet.class, "/");
+
+ server.setHandler(context);
+ server.start();
+ logger.info("Local HTTP server started successfully");
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void tearDown() throws Exception {
+ server.stop();
+ }
+
+ @Test(timeOut = 20000)
+ public void testPost() throws Throwable {
+ logger.info("running test: testPost");
+ AsyncHttpClient c = new AsyncHttpClient();
+
+ Response r = c.preparePost(targetUrl + "/create/myPets").setBody("{\"name\":\"pouetpouet\"}").addHeader("Content-Type", acceptHeader).addHeader("Accept", acceptHeader).execute().get();
+
+ assertNotNull(r);
+ assertEquals(r.getStatusCode(), 200);
+ System.out.println(r.getResponseBody());
+ assertEquals(r.getResponseBody(), "{\"name\":\"pouetpouet\"}");
+
+ c.close();
+ }
+
+ @Test(timeOut = 20000)
+ public void testExtensiont() throws Throwable {
+ logger.info("running test: testPost");
+ AsyncHttpClient c = new AsyncHttpClient();
+
+ Response r = c.prepareGet(targetUrl + "/lolipet/myPet").addHeader("Accept", acceptHeader).execute().get();
+
+ assertNotNull(r);
+ assertEquals(r.getStatusCode(), 200);
+ System.out.println(r.getResponseBody());
+ assertEquals(r.getResponseBody(), "{\"name\":\"lolipet\"}");
+
+ c.close();
+ }
+}
@@ -18,6 +18,9 @@
import com.google.sitebricks.Show;
import com.google.sitebricks.rendering.EmbedAs;
import com.google.sitebricks.rendering.With;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.restsimple.annotation.Service;
import org.sonatype.restsimple.api.DefaultServiceDefinition;
import org.sonatype.restsimple.api.ServiceDefinition;
import org.sonatype.restsimple.sitebricks.impl.SitebricksServiceDefinitionGenerator;
@@ -28,7 +31,8 @@
import org.sonatype.restsimple.spi.ServiceHandlerMapper;
import org.sonatype.restsimple.spi.scan.Classes;
-
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -41,6 +45,8 @@
*/
public class SitebricksConfig extends ServletModule implements ServiceDefinitionConfig {
+ private final Logger logger = LoggerFactory.getLogger(SitebricksConfig.class);
+
private Injector parent;
private Injector injector;
private final ServiceHandlerMapper mapper;
@@ -110,7 +116,36 @@ protected final void configureServlets() {
*/
@Override
public List<ServiceDefinition> defineServices(Injector injector) {
- return null;
+ Set<Class<?>> set = new HashSet<Class<?>>();
+ for (Package pkg : packages) {
+ //look for any classes annotated with @Service
+ set.addAll(Classes.matching(
+ annotatedWith(Service.class)
+ ).in(pkg));
+ }
+
+ List<ServiceDefinition> list = new ArrayList<ServiceDefinition>();
+ // Now let's find the method that returns a ServiceDefinition
+ for(Class<?> clazz : set) {
+
+ Object o = injector.getInstance(clazz);
+ Method[] methods = clazz.getMethods();
+ for(Method method: methods) {
+ Class<?> returnType = method.getReturnType();
+ ServiceDefinition sd;
+ if (returnType.equals(ServiceDefinition.class)) {
+ try {
+ sd = ServiceDefinition.class.cast(method.invoke(o, null));
+ list.add(sd);
+ } catch (IllegalAccessException e) {
+ logger.trace("defineServices",e);
+ } catch (InvocationTargetException e) {
+ logger.trace("defineServices",e);
+ }
+ }
+ }
+ }
+ return list;
}
/**
@@ -133,7 +168,8 @@ public Injector injector() {
* {@inheritDoc}
*/
@Override
- public void scan(Package packageName) {
+ public SitebricksConfig scan(Package packageName) {
packages.add(packageName);
+ return this;
}
}
Oops, something went wrong.

0 comments on commit 9c68f4a

Please sign in to comment.