Package org.jboss.forge.arquillian

Source Code of org.jboss.forge.arquillian.ArquillianPlugin

/*
* Copyright 2013 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.arquillian;

import static org.jboss.forge.arquillian.commandcompleter.TestFrameworkCompleter.OPTION_TEST_FRAMEWORK;
import static org.jboss.forge.arquillian.commandcompleter.ContainerCommandCompleter.*;

import org.apache.maven.model.Profile;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.jboss.forge.arquillian.commandcompleter.ContainerCommandCompleter;
import org.jboss.forge.arquillian.commandcompleter.ProfileCommandCompleter;
import org.jboss.forge.arquillian.commandcompleter.TestFrameworkCompleter;
import org.jboss.forge.arquillian.container.Configuration;
import org.jboss.forge.arquillian.container.Container;
import org.jboss.forge.arquillian.container.ContainerDirectoryParser;
import org.jboss.forge.arquillian.container.ContainerType;
import org.jboss.forge.arquillian.testframework.ProvidesFacetForQualifier;
import org.jboss.forge.arquillian.testframework.TestFrameworkFacet;
import org.jboss.forge.arquillian.testframework.TestFrameworkFacetInstaller;
import org.jboss.forge.maven.MavenCoreFacet;
import org.jboss.forge.parser.JavaParser;
import org.jboss.forge.parser.java.JavaClass;
import org.jboss.forge.parser.java.JavaSource;
import org.jboss.forge.parser.xml.Node;
import org.jboss.forge.parser.xml.XMLParser;
import org.jboss.forge.project.Project;
import org.jboss.forge.project.dependencies.Dependency;
import org.jboss.forge.project.dependencies.DependencyBuilder;
import org.jboss.forge.project.dependencies.ScopeType;
import org.jboss.forge.project.facets.DependencyFacet;
import org.jboss.forge.project.facets.JavaExecutionFacet;
import org.jboss.forge.project.facets.JavaSourceFacet;
import org.jboss.forge.project.facets.ResourceFacet;
import org.jboss.forge.project.facets.events.InstallFacets;
import org.jboss.forge.resources.FileResource;
import org.jboss.forge.resources.java.JavaResource;
import org.jboss.forge.shell.PromptType;
import org.jboss.forge.shell.Shell;
import org.jboss.forge.shell.events.PickupResource;
import org.jboss.forge.shell.plugins.*;

import javax.enterprise.event.Event;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.Properties;

@Alias("arquillian")
@RequiresProject
@RequiresFacet({ DependencyFacet.class, JavaSourceFacet.class })
@Help("This plugin will help you setting up Arquillian tests.")
public class ArquillianPlugin implements Plugin
{

   static
   {
      Properties properties = new Properties();
      properties.setProperty("resource.loader", "class");
      properties.setProperty("class.resource.loader.class",
            "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");

      Velocity.init(properties);
   }

   public static final String ARQ_CORE_VERSION_PROP_NAME = "version.arquillian_core";
   public static final String ARQ_CORE_VERSION_PROP = "${" + ARQ_CORE_VERSION_PROP_NAME + "}";

   private String arquillianVersion;

   private DependencyFacet dependencyFacet;

   @Inject
   private Project project;

   @Inject
   private BeanManager beanManager;

   @Inject
   private Event<PickupResource> pickup;

   @Inject
   @Current
   private JavaResource resource;

   @Inject
   private Shell shell;

   @Inject
   private ContainerInstaller containerInstaller;

   @Inject
   private ContainerDirectoryParser containerDirectoryParser;

   @Inject
   @Any
   private Event<ContainerInstallEvent> installEvent;

   @Inject
   private Event<InstallFacets> installFacetsEvent;

   @Inject
   @Any
   private Instance<TestFrameworkFacetInstaller> testFrameworkFacetInstallers;

   @SetupCommand
   public void installContainer(
         @Option(name = OPTION_CONTAINER_NAME, required = true, completer = ContainerCommandCompleter.class) String containerName,
         @Option(name = OPTION_CONTAINER_TYPE, required = false) ContainerType containerType,
         @Option(name = OPTION_TEST_FRAMEWORK, required = false, completer = TestFrameworkCompleter.class, defaultValue = "junit") String selectedTestFramework)
   {
      String containerId = Container.idForDisplayName(containerName);
      this.dependencyFacet = project.getFacet(DependencyFacet.class);

      installArquillianBom();
      installTestFramework(selectedTestFramework);
      installContainer(containerId);
      configureSelectedContainer(containerId);
   }

   private void installContainer(String containerId)
   {
      List<Container> containers;
      try
      {
         containers = containerDirectoryParser.getContainers();
      }
      catch (IOException e)
      {
         throw new RuntimeException(e);
      }

      boolean foundContainer = false;
      for (Container container : containers)
      {
         if (container.getId().equals(containerId))
         {
            containerInstaller.installContainer(container);

            installEvent.fire(new ContainerInstallEvent(container));

            foundContainer = true;
            break;
         }
      }

      if (!foundContainer)
      {
         throw new RuntimeException("Container not recognized");
      }
   }

   private void configureSelectedContainer(String containerId)
   {
      ResourceFacet resources = project.getFacet(ResourceFacet.class);
      FileResource<?> resource = (FileResource<?>) resources.getTestResourceFolder().getChild("arquillian.xml");
      Node arquillianConfig = null;
      if (!resource.exists())
      {
         arquillianConfig = createNewArquillianConfig();
      }
      else
      {
         arquillianConfig = XMLParser.parse(resource.getResourceInputStream());
      }

      // Make sure a container config exists for this container (otherwise activating it will fail)
      Node containerConfig = arquillianConfig.getSingle("container@qualifier=" + containerId);
      if (containerConfig == null)
      {
         arquillianConfig.createChild("container@qualifier=" + containerId);
         resource.setContents(XMLParser.toXMLString(arquillianConfig));
      }
   }

   @Command(value = "configure-container")
   public void configureContainer(@Option(name = "profile", required = true, completer = ProfileCommandCompleter.class) String profileId)
   {
      // loop, user presses ctrl-c to exit
      while (true)
      {
         Profile profile = getProfile(profileId);
         Container container;
         try
         {
            container = getContainer(profile);
         } catch (IOException e)
         {
            throw new RuntimeException(e);
         }

         // TODO: show current values in options list
         Configuration configuration = shell.promptChoiceTyped(
               "Which property do you want to set? (default values shown)\n(Press Enter to return to shell)",
               container.getConfigurations(), null);
         if (configuration == null)
         {
            break;
         }

         ResourceFacet resources = project.getFacet(ResourceFacet.class);
         FileResource<?> resource = (FileResource<?>) resources.getTestResourceFolder().getChild("arquillian.xml");

         Node xml = null;
         if (!resource.exists())
         {
            xml = createNewArquillianConfig();
         } else
         {
            xml = XMLParser.parse(resource.getResourceInputStream());
         }

         // TODO show current value
         String value = shell.prompt("What value do you want to assign to the " + configuration.getName() + " property?");
         addPropertyToArquillianConfig(xml, container.getId(), configuration.getName(), value);

         resource.setContents(XMLParser.toXMLString(xml));
      }
   }

   private Container getContainer(Profile profile) throws IOException
   {
      String profileId = profile.getId().replaceFirst("^arq-", "arquillian-");
      for (Container container : containerDirectoryParser.getContainers())
      {
         if (container.getProfileId().equals(profileId))
         {
            return container;
         }
      }

      throw new RuntimeException("Container not found for profile " + profile);
   }

   private Profile getProfile(String profile)
   {
      MavenCoreFacet mavenCoreFacet = project.getFacet(MavenCoreFacet.class);
      List<Profile> profileList = mavenCoreFacet.getPOM().getProfiles();
      for (Profile p : profileList)
      {
         if (p.getId().equals(profile))
         {
            return p;
         }
      }

      throw new RuntimeException("Profile " + profile + " could not be found");
   }

   private Node createNewArquillianConfig()
   {
      return XMLParser
            .parse("<arquillian xmlns=\"http://jboss.org/schema/arquillian\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
                  + "            xsi:schemaLocation=\"http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd\"></arquillian>");
   }

   private void addPropertyToArquillianConfig(Node xml, String container, String key, String value)
   {
      xml.getOrCreate("container@qualifier=" + container)
         .getOrCreate("configuration")
         .getOrCreate("property@name=" + key)
         .text(value);
   }

   @Command(value = "create-test", help = "Create a new test class with a default @Deployment method")
   public void createTest(
         @Option(name = "class", required = true, type = PromptType.JAVA_CLASS) JavaResource classUnderTest,
         @Option(name = "enableJPA", required = false, flagOnly = true) boolean enableJPA, final PipeOut out)
         throws FileNotFoundException
   {
      final TestFrameworkFacet testFrameworkFacet = project.getFacet(TestFrameworkFacet.class);
      final JavaSourceFacet java = project.getFacet(JavaSourceFacet.class);
      final JavaSource<?> javaSource = classUnderTest.getJavaSource();

      final VelocityContext context = initializeVelocityContext(enableJPA, javaSource);

      final StringWriter writer = new StringWriter();
      Velocity.mergeTemplate(testFrameworkFacet.getTemplateName(), "UTF-8", context, writer);

      final JavaClass testClass = JavaParser.parse(JavaClass.class, writer.toString());
      java.saveTestJavaSource(testClass);
      pickup.fire(new PickupResource(java.getTestJavaResource(testClass)));
   }

   private VelocityContext initializeVelocityContext(boolean enableJPA, JavaSource<?> javaSource)
   {
      VelocityContext context = new VelocityContext();
      context.put("package", javaSource.getPackage());
      context.put("ClassToTest", javaSource.getName());
      context.put("classToTest", javaSource.getName().toLowerCase());
      context.put("packageImport", javaSource.getPackage());
      context.put("enableJPA", enableJPA);
      return context;
   }

   /**
    * This command exports an Archive generated by a @Deployment method to disk. Because the project's classpath is not
    * in the classpath of Forge, the @Deployment method can't be called directly.The plugin works in the following
    * steps: 1 - Generate a new class to the src/test/java folder 2 - Compile the user's classes using mvn test-compile
    * 3 - Run the generated class using mvn exec:java (so that the project's classes are on the classpath) 4 - Delete
    * the generated class
    */
   @Command(value = "export", help = "Export a @Deployment configuration to a zip file on disk.")
   @RequiresResource(JavaResource.class)
   public void exportDeployment(@Option(name = "keepExporter", flagOnly = true) boolean keepExporter, PipeOut out)
   {

      final JavaSourceFacet javaSourceFacet = project.getFacet(JavaSourceFacet.class);
      try
      {
         JavaResource testJavaResource = javaSourceFacet.getTestJavaResource("forge/arquillian/DeploymentExporter.java");
         if (!testJavaResource.exists())
         {
            generateExporterClass(javaSourceFacet);
         }

         runExporterClass(out);

         if (!keepExporter)
         {
            testJavaResource.delete();
         }
      }
      catch (Exception ex)
      {
         throw new RuntimeException("Error while calling generated DeploymentExporter ", ex);
      }
   }

   private void runExporterClass(PipeOut out) throws IOException
   {
      JavaExecutionFacet facet = project.getFacet(JavaExecutionFacet.class);
      facet.executeProjectClass("forge.arquillian.DeploymentExporter", resource.getJavaSource().getQualifiedName());
   }

   private void generateExporterClass(JavaSourceFacet java) throws FileNotFoundException
   {

      VelocityContext context = new VelocityContext();

      StringWriter writer = new StringWriter();
      Velocity.mergeTemplate("DeploymentExporter.vtl", "UTF-8", context, writer);
      JavaClass deploymentExporter = JavaParser.parse(JavaClass.class, writer.toString());

      java.saveTestJavaSource(deploymentExporter);
      java.saveTestJavaSource(deploymentExporter);
   }

   private void installArquillianBom()
   {
      DependencyBuilder arquillianBom = DependencyBuilder.create().setGroupId("org.jboss.arquillian")
            .setArtifactId("arquillian-bom").setPackagingType("pom").setScopeType(ScopeType.IMPORT);

      arquillianVersion = dependencyFacet.getProperty(ARQ_CORE_VERSION_PROP_NAME);
      if (arquillianVersion == null)
      {
         List<Dependency> dependencies = dependencyFacet.resolveAvailableVersions(arquillianBom);
         Dependency dependency = shell.promptChoiceTyped("Which version of Arquillian do you want to install?",
               dependencies, DependencyUtil.getLatestNonSnapshotVersion(dependencies));
         arquillianVersion = dependency.getVersion();
         dependencyFacet.setProperty(ARQ_CORE_VERSION_PROP_NAME, arquillianVersion);
      }

      // need to set version after resolve is done, else nothing will resolve.
      if (!dependencyFacet.hasDirectManagedDependency(arquillianBom))
      {
         arquillianBom.setVersion(ARQ_CORE_VERSION_PROP);
         dependencyFacet.addDirectManagedDependency(arquillianBom);
      }
   }

   private void installTestFramework(String selectedTestFramework)
   {
      resolveTestFrameworkInstaller(selectedTestFramework).install();
   }

   private TestFrameworkFacetInstaller resolveTestFrameworkInstaller(String testFramework)
   {
      try
      {
         return testFrameworkFacetInstallers.select(new ProvidesFacetForQualifier(testFramework)).get();
      }
      catch (Exception e)
      {
         throw new RuntimeException("Unable to resolve provider for selected test framework [" + testFramework + "]", e);
      }

   }
}
TOP

Related Classes of org.jboss.forge.arquillian.ArquillianPlugin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.