From 838c7f5b10b1bdcd33bb5853d261b72e3da3a891 Mon Sep 17 00:00:00 2001 From: Antonio Goncalves Date: Tue, 12 May 2015 15:10:36 +0200 Subject: [PATCH] FORGE-2177: Being able to create a new REST endpoint --- .../addon/javaee/JavaEEPackageConstants.java | 3 +- .../rest/ui/AbstractRESTNewCommand.java | 58 ++++++ .../addon/javaee/rest/ui/RestMethod.java | 38 ++++ .../rest/ui/RestNewEndpointCommand.java | 124 ++++++++++++ .../javaee/servlet/ui/ServletMethod.java | 2 +- .../rest/ui/RestNewEndpointCommandTest.java | 188 ++++++++++++++++++ 6 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/AbstractRESTNewCommand.java create mode 100644 javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestMethod.java create mode 100644 javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommand.java create mode 100644 javaee/tests/src/test/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommandTest.java diff --git a/javaee/api/src/main/java/org/jboss/forge/addon/javaee/JavaEEPackageConstants.java b/javaee/api/src/main/java/org/jboss/forge/addon/javaee/JavaEEPackageConstants.java index c72d15336a..d25daa6402 100644 --- a/javaee/api/src/main/java/org/jboss/forge/addon/javaee/JavaEEPackageConstants.java +++ b/javaee/api/src/main/java/org/jboss/forge/addon/javaee/JavaEEPackageConstants.java @@ -27,5 +27,6 @@ public interface JavaEEPackageConstants // CDI String DEFAULT_CDI_PACKAGE = "beans"; String DEFAULT_CDI_EXTENSIONS_PACKAGE = DEFAULT_CDI_PACKAGE + "." + "extensions"; - + // REST + String DEFAULT_REST_PACKAGE = "rest"; } diff --git a/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/AbstractRESTNewCommand.java b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/AbstractRESTNewCommand.java new file mode 100644 index 0000000000..afe44cb973 --- /dev/null +++ b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/AbstractRESTNewCommand.java @@ -0,0 +1,58 @@ +package org.jboss.forge.addon.javaee.rest.ui; + +import static org.jboss.forge.addon.javaee.JavaEEPackageConstants.DEFAULT_REST_PACKAGE; + +import org.jboss.forge.addon.javaee.rest.RestFacet; +import org.jboss.forge.addon.parser.java.facets.JavaSourceFacet; +import org.jboss.forge.addon.parser.java.ui.AbstractJavaSourceCommand; +import org.jboss.forge.addon.projects.Project; +import org.jboss.forge.addon.ui.command.PrerequisiteCommandsProvider; +import org.jboss.forge.addon.ui.context.UIContext; +import org.jboss.forge.addon.ui.result.NavigationResult; +import org.jboss.forge.addon.ui.result.navigation.NavigationResultBuilder; +import org.jboss.forge.addon.ui.util.Categories; +import org.jboss.forge.addon.ui.util.Metadata; +import org.jboss.forge.roaster.model.source.JavaSource; + +/** + * @author Antonio Goncalves + */ +public abstract class AbstractRestNewCommand> extends AbstractJavaSourceCommand + implements PrerequisiteCommandsProvider +{ + + @Override + public Metadata getMetadata(UIContext context) + { + return Metadata.from(super.getMetadata(context), getClass()) + .category(Categories.create(Categories.create("Java EE"), "REST")); + } + + @Override + protected boolean isProjectRequired() + { + return true; + } + + @Override + protected String calculateDefaultPackage(UIContext context) + { + return getSelectedProject(context).getFacet(JavaSourceFacet.class).getBasePackage() + "." + + DEFAULT_REST_PACKAGE; + } + + @Override + public NavigationResult getPrerequisiteCommands(UIContext context) + { + NavigationResultBuilder builder = NavigationResultBuilder.create(); + Project project = getSelectedProject(context); + if (project != null) + { + if (!project.hasFacet(RestFacet.class)) + { + builder.add(RestSetupWizard.class); + } + } + return builder.build(); + } +} diff --git a/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestMethod.java b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestMethod.java new file mode 100644 index 0000000000..af74e3cb8a --- /dev/null +++ b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestMethod.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Eclipse Public License version 1.0, available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.jboss.forge.addon.javaee.rest.ui; + +/** + * @author Antonio Goncalves + */ +public enum RestMethod +{ + GET("doGet", javax.ws.rs.GET.class), + POST("doPost", javax.ws.rs.POST.class), + PUT("doPut", javax.ws.rs.PUT.class), + DELETE("doDelete", javax.ws.rs.DELETE.class); + + private String methodName; + + private Class methodAnnotation; + + private RestMethod(String methodName, Class methodAnnotation) + { + this.methodName = methodName; + this.methodAnnotation = methodAnnotation; + } + + public Class getMethodAnnotation() + { + return methodAnnotation; + } + + public String getMethodName() + { + return methodName; + } +} diff --git a/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommand.java b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommand.java new file mode 100644 index 0000000000..41a1947314 --- /dev/null +++ b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommand.java @@ -0,0 +1,124 @@ +/** + * Copyright 2014 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Eclipse Public License version 1.0, available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.jboss.forge.addon.javaee.rest.ui; + +import javax.inject.Inject; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; + +import org.jboss.forge.addon.projects.Project; +import org.jboss.forge.addon.text.Inflector; +import org.jboss.forge.addon.ui.context.UIBuilder; +import org.jboss.forge.addon.ui.context.UIContext; +import org.jboss.forge.addon.ui.context.UIExecutionContext; +import org.jboss.forge.addon.ui.input.UIInput; +import org.jboss.forge.addon.ui.input.UISelectMany; +import org.jboss.forge.addon.ui.metadata.WithAttributes; +import org.jboss.forge.addon.ui.util.Metadata; +import org.jboss.forge.roaster.model.source.JavaClassSource; +import org.jboss.forge.roaster.model.source.MethodSource; + +/** + * Creates a new REST Endpoint + * + * @author Antonio Goncalves + */ +public class RestNewEndpointCommand extends AbstractRestNewCommand +{ + @Inject + @WithAttributes(label = "Methods", description = "REST methods to be defined") + private UISelectMany methods; + + @Inject + @WithAttributes(label = "Path", description = "The root path of the endpoint") + private UIInput path; + + @Inject + private Inflector inflector; + + @Override + public Metadata getMetadata(UIContext context) + { + return Metadata.from(super.getMetadata(context), getClass()) + .name("REST: New Endpoint") + .description("Creates a new REST Endpoint"); + } + + @Override + protected String getType() + { + return "REST"; + } + + @Override + protected Class getSourceType() + { + return JavaClassSource.class; + } + + @Override + public void initializeUI(UIBuilder builder) throws Exception + { + super.initializeUI(builder); + builder.add(methods).add(path); + } + + @Override + public JavaClassSource decorateSource(UIExecutionContext context, Project project, JavaClassSource source) + throws Exception + { + if (path.hasValue()) + { + source.addAnnotation(Path.class).setStringValue("/" + path.getValue()); + } + else + { + source.addAnnotation(Path.class).setStringValue("/" + inflector.lowerCamelCase(getNamed().getValue())); + } + + for (RestMethod method : methods.getValue()) + { + MethodSource doGet = source.addMethod().setPublic().setName(method.getMethodName()) + .setReturnType("javax.ws.rs.core.Response"); + doGet.addAnnotation(method.getMethodAnnotation()); + + switch (method) + { + case GET: + doGet.addAnnotation(javax.ws.rs.Produces.class).setStringArrayValue(new String[] { MediaType.TEXT_PLAIN }); + doGet.setBody("return Response.ok(\"method " + method.getMethodName() + " invoked\").build();"); + break; + case POST: + source.addImport(UriBuilder.class); + doGet.addAnnotation(javax.ws.rs.Consumes.class).setStringArrayValue( + new String[] { MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON }); + doGet.addParameter(String.class, "entity"); + doGet.setBody("return Response.created(UriBuilder.fromResource(" + getNamed().getValue() + + ".class).build()).build();"); + break; + case PUT: + source.addImport(UriBuilder.class); + doGet.addAnnotation(javax.ws.rs.Consumes.class).setStringArrayValue( + new String[] { MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON }); + doGet.addParameter(String.class, "entity"); + doGet.setBody("return Response.created(UriBuilder.fromResource(" + getNamed().getValue() + + ".class).build()).build();"); + break; + case DELETE: + doGet.addAnnotation(javax.ws.rs.Path.class).setStringValue("/{id}"); + doGet.addParameter(Long.class, "id").addAnnotation(PathParam.class).setStringValue("id"); + doGet.setBody("return Response.noContent().build();"); + break; + } + } + + return source; + } +} diff --git a/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/servlet/ui/ServletMethod.java b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/servlet/ui/ServletMethod.java index e1a895641c..8954de2fb9 100644 --- a/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/servlet/ui/ServletMethod.java +++ b/javaee/impl/src/main/java/org/jboss/forge/addon/javaee/servlet/ui/ServletMethod.java @@ -7,7 +7,7 @@ package org.jboss.forge.addon.javaee.servlet.ui; /** - * @author Lincoln Baxter, III + * @author Antonio Goncalves */ public enum ServletMethod { diff --git a/javaee/tests/src/test/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommandTest.java b/javaee/tests/src/test/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommandTest.java new file mode 100644 index 0000000000..65d17b38be --- /dev/null +++ b/javaee/tests/src/test/java/org/jboss/forge/addon/javaee/rest/ui/RestNewEndpointCommandTest.java @@ -0,0 +1,188 @@ +/** + * Copyright 2014 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Eclipse Public License version 1.0, available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.jboss.forge.addon.javaee.rest.ui; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.jboss.forge.addon.javaee.JavaEEPackageConstants.DEFAULT_REST_PACKAGE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; +import javax.ws.rs.Path; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.forge.addon.javaee.ProjectHelper; +import org.jboss.forge.addon.javaee.rest.RestFacet; +import org.jboss.forge.addon.javaee.rest.config.RestConfigurationStrategyFactory; +import org.jboss.forge.addon.parser.java.facets.JavaSourceFacet; +import org.jboss.forge.addon.parser.java.resources.JavaResource; +import org.jboss.forge.addon.projects.Project; +import org.jboss.forge.addon.shell.test.ShellTest; +import org.jboss.forge.addon.ui.controller.CommandController; +import org.jboss.forge.addon.ui.metadata.UICommandMetadata; +import org.jboss.forge.addon.ui.result.Failed; +import org.jboss.forge.addon.ui.result.Result; +import org.jboss.forge.addon.ui.test.UITestHarness; +import org.jboss.forge.arquillian.AddonDependencies; +import org.jboss.forge.arquillian.archive.AddonArchive; +import org.jboss.forge.roaster.model.JavaClass; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * + * @author Antonio Goncalves + */ +@RunWith(Arquillian.class) +public class RestNewEndpointCommandTest +{ + @Deployment + @AddonDependencies + public static AddonArchive getDeployment() + { + return ShrinkWrap.create(AddonArchive.class).addBeansXML().addClass(ProjectHelper.class); + } + + @Inject + private UITestHarness uiTestHarness; + + @Inject + private ShellTest shellTest; + + @Inject + private ProjectHelper projectHelper; + + private Project project; + + @Before + public void setUp() + { + project = projectHelper.createJavaLibraryProject(); + projectHelper.installJAXRS_2_0(project, RestConfigurationStrategyFactory.createUsingWebXml("/rest")); + } + + @Test + public void checkCommandMetadata() throws Exception + { + try (CommandController controller = uiTestHarness.createCommandController(RestNewEndpointCommand.class, + project.getRoot())) + { + controller.initialize(); + // Checks the command metadata + assertTrue(controller.getCommand() instanceof RestNewEndpointCommand); + assertTrue(controller.getCommand() instanceof AbstractRestNewCommand); + UICommandMetadata metadata = controller.getMetadata(); + assertEquals("REST: New Endpoint", metadata.getName()); + assertEquals("Java EE", metadata.getCategory().getName()); + assertEquals("REST", metadata.getCategory().getSubCategory().getName()); + assertEquals(5, controller.getInputs().size()); + assertFalse("Project is created, shouldn't have targetLocation", controller.hasInput("targetLocation")); + assertTrue(controller.hasInput("named")); + assertTrue(controller.hasInput("targetPackage")); + assertTrue(controller.hasInput("overwrite")); + assertTrue(controller.hasInput("methods")); + assertTrue(controller.hasInput("path")); + assertTrue(controller.getValueFor("targetPackage").toString().endsWith(DEFAULT_REST_PACKAGE)); + } + } + + @Test + public void checkCommandShell() throws Exception + { + shellTest.getShell().setCurrentResource(project.getRoot()); + Result result = shellTest.execute("rest-new-endpoint --named Dummy", 10, TimeUnit.SECONDS); + + Assert.assertThat(result, not(instanceOf(Failed.class))); + Assert.assertTrue(project.hasFacet(RestFacet.class)); + } + + @Test + public void testCreateNewRestEndpoint() throws Exception + { + try (CommandController controller = uiTestHarness.createCommandController(RestNewEndpointCommand.class, + project.getRoot())) + { + controller.initialize(); + controller.setValueFor("named", "MyEndpoint"); + controller.setValueFor("targetPackage", "org.jboss.forge.test"); + assertTrue(controller.isValid()); + assertTrue(controller.canExecute()); + Result result = controller.execute(); + Assert.assertThat(result, is(not(instanceOf(Failed.class)))); + } + + JavaSourceFacet facet = project.getFacet(JavaSourceFacet.class); + JavaResource javaResource = facet.getJavaResource("org.jboss.forge.test.MyEndpoint"); + Assert.assertNotNull(javaResource); + Assert.assertThat(javaResource.getJavaType(), is(instanceOf(JavaClass.class))); + assertEquals(0, javaResource.getJavaType().getSyntaxErrors().size()); + assertTrue(javaResource.getJavaType().hasAnnotation(Path.class)); + assertEquals("/myEndpoint", javaResource.getJavaType().getAnnotation(Path.class).getStringValue()); + } + + @Test + public void testCreateNewServletWithPath() throws Exception + { + try (CommandController controller = uiTestHarness.createCommandController(RestNewEndpointCommand.class, + project.getRoot())) + { + controller.initialize(); + controller.setValueFor("named", "MyEndpoint"); + controller.setValueFor("targetPackage", "org.jboss.forge.test"); + controller.setValueFor("path", "myPath"); + assertTrue(controller.isValid()); + assertTrue(controller.canExecute()); + Result result = controller.execute(); + Assert.assertThat(result, is(not(instanceOf(Failed.class)))); + } + + JavaSourceFacet facet = project.getFacet(JavaSourceFacet.class); + JavaResource javaResource = facet.getJavaResource("org.jboss.forge.test.MyEndpoint"); + Assert.assertNotNull(javaResource); + Assert.assertThat(javaResource.getJavaType(), is(instanceOf(JavaClass.class))); + assertEquals(0, javaResource.getJavaType().getSyntaxErrors().size()); + assertTrue(javaResource.getJavaType().hasAnnotation(Path.class)); + assertEquals("/myPath", javaResource.getJavaType().getAnnotation(Path.class).getStringValue()); + } + + @Test + public void testCreateNewServletWithMethods() throws Exception + { + try (CommandController controller = uiTestHarness.createCommandController(RestNewEndpointCommand.class, + project.getRoot())) + { + controller.initialize(); + controller.setValueFor("named", "MyEndpoint"); + controller.setValueFor("targetPackage", "org.jboss.forge.test"); + controller.setValueFor("methods", Arrays.asList(RestMethod.GET, RestMethod.POST)); + assertTrue(controller.isValid()); + assertTrue(controller.canExecute()); + Result result = controller.execute(); + Assert.assertThat(result, is(not(instanceOf(Failed.class)))); + } + + JavaSourceFacet facet = project.getFacet(JavaSourceFacet.class); + JavaResource javaResource = facet.getJavaResource("org.jboss.forge.test.MyEndpoint"); + Assert.assertNotNull(javaResource); + Assert.assertThat(javaResource.getJavaType(), is(instanceOf(JavaClass.class))); + assertEquals(0, javaResource.getJavaType().getSyntaxErrors().size()); + assertTrue(javaResource.getJavaType().hasAnnotation(Path.class)); + JavaClass javaClass = javaResource.getJavaType(); + assertEquals(2, javaClass.getMethods().size()); + } +} \ No newline at end of file