All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.arquillian.maven.BaseCommand Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,  
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.arquillian.maven;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ContainerRegistry;
import org.jboss.arquillian.container.spi.client.container.DeploymentException;
import org.jboss.arquillian.container.spi.client.container.LifecycleException;
import org.jboss.arquillian.container.spi.client.deployment.TargetDescription;
import org.jboss.arquillian.core.spi.Manager;
import org.jboss.arquillian.core.spi.ManagerBuilder;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.GenericArchive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.importer.ZipImporter;

/**
 * BaseCommand
 * 
 * @author Aslak Knutsen
 * @author Davide D'Alto
 * @version $Revision: $
 * 
 * @requiresDependencyResolution test
 */
abstract class BaseCommand extends AbstractMojo
{
   private static final String ARQUILLIAN_XML_SYS_PROP = "arquillian.xml";

   private static final String LOADABLE_EXTESION_LOADER_CLASS = "org.jboss.arquillian.core.impl.loadable.LoadableExtensionLoader";
   
   public enum ClassLoadingStrategy 
   {
      COMPILE,
      TEST,
      PLUGIN
   }
   
   /**
    * The maven project.
    *
    * @parameter expression="${project}"
    */
   private MavenProject project;

   /**
    * The ClassLoading strategy to use: TEST, COMPILE or PLUGIN.
    * 
    * @parameter property="classloading"
    */
   private ClassLoadingStrategy classLoadingStrategy = ClassLoadingStrategy.TEST; 

   /**
    * @param classLoadingStrategy the classLoadingStrategy to set
    */
   public void setClassloading(String classloading)
   {
      this.classLoadingStrategy = ClassLoadingStrategy.valueOf(classloading.toUpperCase());
   }
   
   /**
    * The target directory the application to be deployed is located.
    *
    * @parameter expression="${echo.target}" default-value="${project.build.directory}/"
    */
   private File targetDir;

   /**
    * The file name of the application to be deployed.
    *
    * @parameter expression="${echo.filename}" default-value="${project.build.finalName}.${project.packaging}"
    */
   private String filename;

   /**
    * Location of the arquillian configuration file. It can be set either as location on the file system (Ex: ${basedir}/test/arquillian4test.xml)
    * or as a resource in the classpath (Ex: /arquillian4test.xml).
    *
    * @parameter expression="${arquillian.xml}"
    */
   private String arquillianXml;

   /**
    * The target directory the archive is located. The default is {@code project.build.directory}.
    *
    * @return the target directory the archive is located.
    */
   public final File targetDirectory()
   {
      return targetDir;
   }

   /**
    * The file name of the archive not including the directory. The default is
    * {@code project.build.finalName + . + project.packaging}
    *
    * @return the file name of the archive.
    */
   public final String filename()
   {
      return filename;
   }

   /**
    * The archive file.
    *
    * @return the archive file.
    */
   public final File file()
   {
      return new File(targetDir, filename);
   }

   /**
    * Return the value of the arquillianXml configuration property.
    */
   public final String arquillianXml()
   {
      return arquillianXml;
   }

   /**
    * The goal of the deployment.
    *
    * @return the goal of the deployment.
    */
   public abstract String goal();

   /**
    * Perform the defined goal, e.g. deploy / run / undeploy
    * 
    * @param container The chosen container to operate on
    * @throws LifecycleException
    * @throws DeploymentException
    */
   public abstract void perform(Manager manager, Container container) throws DeploymentException, LifecycleException;

   /* (non-Javadoc)
    * @see org.apache.maven.plugin.Mojo#execute()
    */
   @Override
   public void execute() throws MojoExecutionException, MojoFailureException
   {
      validateInput();
      initArquillianXml();

      getLog().info("Using configuration: " + System.getProperty(ARQUILLIAN_XML_SYS_PROP));
      getLog().info(goal() + " file: " + file().getAbsoluteFile());

      ClassLoader previousCL = Thread.currentThread().getContextClassLoader();
      try
      {
         ClassLoader cl = getClassLoader();
         Thread.currentThread().setContextClassLoader(cl);
         
         Class extension = cl.loadClass(LOADABLE_EXTESION_LOADER_CLASS);
         
         loadContainer(extension);
      }
      catch (Exception e) 
      {
         throw new MojoExecutionException("Could not perform goal: " + goal() + " on file " + file(), e);
      }
      finally
      {
         Thread.currentThread().setContextClassLoader(previousCL);
      }
   }

   void initArquillianXml()
   {
      if (arquillianXml() != null) {
         System.setProperty(ARQUILLIAN_XML_SYS_PROP, arquillianXml());
      }
   }

   void validateInput()
   {
      File deploymentFile = file();
      if (!deploymentFile.exists())
      {
         throw new IllegalArgumentException("Specified file does not exist:" + deploymentFile
               + ". Verify 'target' and 'filename' configuration.");
      }
      
      if( (classLoadingStrategy == ClassLoadingStrategy.TEST || classLoadingStrategy == ClassLoadingStrategy.COMPILE) && project == null)
      {
         throw new IllegalArgumentException("Can not use 'classloading' strategy " + classLoadingStrategy + " outside a project");
      }
   }

   private void loadContainer(Class... extensions) throws Exception
   {
      Manager manager = startManager(extensions);
      try
      {
         perform(manager, selectContainer(manager));
      }
      catch (Exception e)
      {
         manager.shutdown();
         throw e;
      }
   }

   private Manager startManager(Class... extensions)
   {
      Manager manager = getFromContext(Manager.class);
      if (isStarted(manager))
         return manager;

      manager = startNewManager(extensions);
      putInContext(Manager.class, manager);
      return manager;
   }

   private boolean isStarted(Manager manager)
   {
      return manager != null;
   }

   Manager startNewManager(Class... extensions)
   {
      Manager manager = ManagerBuilder.from().extensions(extensions).create();
      manager.start();
      return manager;
   }

   private Container selectContainer(Manager manager)
   {
      // TODO: Add support for multi configuration
      Container container = createRegistry(manager).getContainer(TargetDescription.DEFAULT);
      getLog().info("to container: " + container.getName());
      return container;
   }

   Archive createDeployment()
   {
      getLog().info(goal() + " file: " + file().getAbsoluteFile());

      File deploymentFile = file();
      Archive deployment = ShrinkWrap.create(ZipImporter.class, deploymentFile.getName())
            .importFrom(deploymentFile).as(GenericArchive.class);
      return deployment;
   }

   private ContainerRegistry createRegistry(Manager manager)
   {
      ContainerRegistry registry = getFromContext(ContainerRegistry.class);
      if (registry != null)
         return registry;

      registry = manager.resolve(ContainerRegistry.class);
      validateRegistry(registry);
      putInContext(ContainerRegistry.class, registry);
      return registry;
   }

   private void validateRegistry(ContainerRegistry registry)
   {
      if (registry == null)
      {
         throw new IllegalStateException(
               "No ContainerRegistry found in Context. Something is wrong with the classpath.....");
      }

      if (registry.getContainers().size() == 0)
      {
         throw new IllegalStateException(
               "No Containers in registry. You need to add the Container Adaptor dependencies to the plugin dependency section");
      }
   }

   protected ClassLoader getClassLoader() throws Exception
   {
      ClassLoader classLoader = getFromContext(ClassLoader.class);
      if (classLoader != null)
         return classLoader;

      synchronized (BaseCommand.class)
      {
         List urls = new ArrayList();
         List classPathElements;
         
         switch (classLoadingStrategy)
         {
            case COMPILE :
               classPathElements = project.getCompileClasspathElements();
               break;
            case TEST :
               classPathElements = project.getTestClasspathElements();
               break;
            case PLUGIN :
               classPathElements = new ArrayList();
               break;

            default :
               classPathElements = new ArrayList();
               break;
         }

         for (String object : classPathElements)
         {
            String path = (String) object;
            urls.add(new File(path).toURI().toURL());
         }
         URLClassLoader urlClassLoader = new URLClassLoader(urls.toArray(new URL[]{}), BaseCommand.class.getClassLoader());
         putInContext(ClassLoader.class, urlClassLoader);
         return urlClassLoader;
      }
   }

   @SuppressWarnings("unchecked")
    T getFromContext(Class key) {
      return (T) getPluginContext().get(key);
   }

   @SuppressWarnings("unchecked")
    T putInContext(Class key, T value) {
      return (T) getPluginContext().put(key, value);
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy