Package org.jboss.forge.arquillian

Source Code of org.jboss.forge.arquillian.ForgeDeployableContainer$ForgeRunnable

/*
* 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 java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;

import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
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.Deployment;
import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.forge.arquillian.archive.ForgeArchive;
import org.jboss.forge.arquillian.archive.ForgeRemoteAddon;
import org.jboss.forge.arquillian.archive.RepositoryForgeArchive;
import org.jboss.forge.arquillian.protocol.ForgeProtocolDescription;
import org.jboss.forge.arquillian.protocol.FurnaceHolder;
import org.jboss.forge.arquillian.util.ShrinkWrapUtil;
import org.jboss.forge.furnace.Furnace;
import org.jboss.forge.furnace.addons.Addon;
import org.jboss.forge.furnace.addons.AddonId;
import org.jboss.forge.furnace.addons.AddonRegistry;
import org.jboss.forge.furnace.impl.FurnaceImpl;
import org.jboss.forge.furnace.impl.util.Files;
import org.jboss.forge.furnace.manager.AddonManager;
import org.jboss.forge.furnace.manager.impl.AddonManagerImpl;
import org.jboss.forge.furnace.manager.maven.addon.MavenAddonDependencyResolver;
import org.jboss.forge.furnace.manager.spi.AddonDependencyResolver;
import org.jboss.forge.furnace.repositories.AddonRepository;
import org.jboss.forge.furnace.repositories.AddonRepositoryMode;
import org.jboss.forge.furnace.repositories.MutableAddonRepository;
import org.jboss.forge.furnace.spi.ContainerLifecycleListener;
import org.jboss.forge.furnace.spi.ListenerRegistration;
import org.jboss.forge.furnace.util.Addons;
import org.jboss.forge.furnace.util.Callables;
import org.jboss.forge.furnace.util.ClassLoaders;
import org.jboss.forge.furnace.util.OperatingSystemUtils;
import org.jboss.forge.furnace.util.SecurityActions;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.descriptor.api.Descriptor;

/**
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
public class ForgeDeployableContainer implements DeployableContainer<ForgeContainerConfiguration>
{
   @Inject
   private Instance<Deployment> deploymentInstance;

   private final FurnaceHolder furnaceHolder = new FurnaceHolder();
   private ForgeRunnable runnable;
   private File addonDir;

   private MutableAddonRepository repository;
   private final Map<String, MutableAddonRepository> deploymentRepositories = new ConcurrentHashMap<String, MutableAddonRepository>();

   private final Map<Deployment, AddonId> deployedAddons = new HashMap<Deployment, AddonId>();
   private Thread thread;

   private boolean undeploying = false;
   private ForgeContainerConfiguration configuration;

   @Override
   public ProtocolMetaData deploy(final Archive<?> archive) throws DeploymentException
   {

      Deployment deployment = deploymentInstance.get();
      final AddonId addonToDeploy = getAddonEntry(deployment);

      if (undeploying)
      {
         System.out.println("Cleaning test runtime.");
         undeploying = false;
         cleanup();
      }

      if (archive instanceof ForgeArchive)
      {
         final MutableAddonRepository target = selectTargetRepository(archive);

         waitForConfigurationRescan(new Callable<Void>()
         {
            @Override
            public Void call() throws Exception
            {
               deployToRepository(archive, target, addonToDeploy);
               return null;
            }
         });

         waitForDeploymentCompletion(deployment, addonToDeploy);
      }
      else if (archive instanceof ForgeRemoteAddon)
      {
         ForgeRemoteAddon remoteAddon = (ForgeRemoteAddon) archive;
         AddonDependencyResolver resolver = new MavenAddonDependencyResolver(configuration.getClassifier());
         AddonManager addonManager = new AddonManagerImpl(runnable.furnace, resolver);

         AddonRepository target = selectTargetRepository(archive);
         addonManager.install(remoteAddon.getAddonId(), target).perform();

         waitForDeploymentCompletion(deployment, addonToDeploy);
      }
      else
      {
         throw new IllegalArgumentException(
                  "Invalid Archive type. Ensure that your @Deployment method returns type 'ForgeArchive'.");
      }

      return new ProtocolMetaData().addContext(furnaceHolder);
   }

   private <T> T waitForConfigurationRescan(Callable<T> action)
   {

      ConfigurationScanListener listener = new ConfigurationScanListener();
      ListenerRegistration<ContainerLifecycleListener> registration = runnable.furnace
               .addContainerLifecycleListener(listener);

      T result = Callables.call(action);

      while (runnable.furnace.getStatus().isStarting() || !listener.isConfigurationScanned())
      {
         try
         {
            Thread.sleep(100);
         }
         catch (InterruptedException e)
         {
            throw new RuntimeException("Sleep interrupted while waiting for configuration rescan.", e);
         }
      }

      registration.removeListener();

      return result;
   }

   private MutableAddonRepository selectTargetRepository(Archive<?> archive)
   {
      MutableAddonRepository target = repository;
      if (archive instanceof RepositoryForgeArchive
               && ((RepositoryForgeArchive) archive).getAddonRepository() != null)
      {
         final String repositoryName = ((RepositoryForgeArchive) archive).getAddonRepository();
         if (deploymentRepositories.get(repositoryName) == null)
         {
            target = waitForConfigurationRescan(new Callable<MutableAddonRepository>()
            {
               @Override
               public MutableAddonRepository call() throws Exception
               {
                  return (MutableAddonRepository) runnable.furnace.addRepository(AddonRepositoryMode.MUTABLE,
                           new File(addonDir, OperatingSystemUtils.getSafeFilename(repositoryName)));
               }
            });
            deploymentRepositories.put(repositoryName, target);
         }
         else
            target = deploymentRepositories.get(repositoryName);
      }
      return target;
   }

   private void waitForDeploymentCompletion(Deployment deployment, final AddonId addonToDeploy)
            throws DeploymentException
   {
      AddonRegistry registry = runnable.getForge().getAddonRegistry();
      Addon addon = registry.getAddon(addonToDeploy);
      try
      {
         Future<Void> future = addon.getFuture();
         if (!future.isDone())
         {
            future.get();
         }
         if (addon.getStatus().isFailed())
         {
            DeploymentException e = new DeploymentException("AddonDependency " + addonToDeploy
                     + " failed to deploy.");
            deployment.deployedWithError(e);
            throw new DeploymentException("AddonDependency " + addonToDeploy + " failed to deploy.", e);
         }
      }
      catch (Exception e)
      {
         deployment.deployedWithError(e);
         throw new DeploymentException("AddonDependency " + addonToDeploy + " failed to deploy.", e);
      }
   }

   private void deployToRepository(Archive<?> archive, MutableAddonRepository repository, final AddonId addonToDeploy)
   {
      File destDir = repository.getAddonBaseDir(addonToDeploy);
      destDir.mkdirs();
      ShrinkWrapUtil.toFile(new File(destDir.getAbsolutePath(), archive.getName()), archive);
      ShrinkWrapUtil.unzip(destDir, archive);
      System.out.println("Deploying [" + addonToDeploy + "] to repository [" + repository + "]");
      repository.deploy(addonToDeploy, ((ForgeArchive) archive).getAddonDependencies(), new ArrayList<File>());
      repository.enable(addonToDeploy);
   }

   private void cleanup()
   {
      try
      {
         stop();
         start();
      }
      catch (LifecycleException e)
      {
         throw new RuntimeException("Failed to clean up after test case.", e);
      }
   }

   @Override
   public void deploy(Descriptor descriptor) throws DeploymentException
   {
      throw new UnsupportedOperationException("Descriptors not supported by Furnace");
   }

   private AddonId getAddonEntry(Deployment deployment)
   {
      if (!deployedAddons.containsKey(deployment))
      {
         String[] coordinates = deployment.getDescription().getName().split(",");
         AddonId entry;
         if (coordinates.length == 3)
            entry = AddonId.from(coordinates[0], coordinates[1], coordinates[2]);
         else if (coordinates.length == 2)
            entry = AddonId.from(coordinates[0], coordinates[1]);
         else if (coordinates.length == 1)
            entry = AddonId.from(coordinates[0], UUID.randomUUID().toString());
         else
            entry = AddonId.from(UUID.randomUUID().toString(), UUID.randomUUID().toString());

         deployedAddons.put(deployment, entry);
      }
      return deployedAddons.get(deployment);
   }

   @Override
   public Class<ForgeContainerConfiguration> getConfigurationClass()
   {
      return ForgeContainerConfiguration.class;
   }

   @Override
   public ProtocolDescription getDefaultProtocol()
   {
      return new ForgeProtocolDescription();
   }

   @Override
   public void setup(ForgeContainerConfiguration configuration)
   {
      this.configuration = configuration;
   }

   @Override
   public void start() throws LifecycleException
   {
      try
      {
         this.addonDir = File.createTempFile("furnace", "test-addon-dir");
         System.out.println("Executing test case with addon dir [" + addonDir + "]");
         initContainer();
         startContainer();
      }
      catch (IOException e)
      {
         throw new LifecycleException("Failed to create temporary addon directory", e);
      }
      catch (Exception e)
      {
         throw new LifecycleException("Could not start Furnace runnable.", e);
      }
   }

   private void startContainer()
   {
      waitForConfigurationRescan(new Callable<Void>()
      {
         @Override
         public Void call() throws Exception
         {
            thread.start();
            return null;
         }
      });
   }

   private void initContainer()
   {
      runnable = new ForgeRunnable(ClassLoader.getSystemClassLoader());
      furnaceHolder.setFurnace(runnable.furnace);
      thread = new Thread(runnable, "Arquillian Furnace Runtime");
      repository = (MutableAddonRepository) runnable.furnace.addRepository(AddonRepositoryMode.MUTABLE, addonDir);
   }

   @Override
   public void stop() throws LifecycleException
   {
      stopContainer();
      Files.delete(addonDir, true);
   }

   private void stopContainer()
   {
      this.repository = null;
      this.deployedAddons.clear();
      this.deploymentRepositories.clear();
      this.runnable.stop();
      this.thread = null;
   }

   @Override
   public void undeploy(Archive<?> archive) throws DeploymentException
   {
      undeploying = true;
      AddonId addonToUndeploy = getAddonEntry(deploymentInstance.get());
      AddonRegistry registry = runnable.getForge().getAddonRegistry();
      System.out.println("Undeploying [" + addonToUndeploy + "] ... ");

      try
      {
         Addon addonToStop = registry.getAddon(addonToUndeploy);
         if (addonToStop.getStatus().isLoaded())
            ((MutableAddonRepository) addonToStop.getRepository()).disable(addonToUndeploy);
         Addons.waitUntilStopped(addonToStop);
      }
      catch (Exception e)
      {
         throw new DeploymentException("Failed to undeploy " + addonToUndeploy, e);
      }
      finally
      {
         repository.undeploy(addonToUndeploy);
      }
   }

   @Override
   public void undeploy(Descriptor descriptor) throws DeploymentException
   {
      throw new UnsupportedOperationException("Descriptors not supported by Furnace");
   }

   private class ForgeRunnable implements Runnable
   {
      private final Furnace furnace;
      private final ClassLoader loader;

      public ForgeRunnable(ClassLoader loader)
      {
         this.furnace = new FurnaceImpl();
         this.loader = loader;
      }

      public Furnace getForge()
      {
         return furnace;
      }

      @Override
      public void run()
      {
         try
         {
            ClassLoaders.executeIn(loader, new Callable<Object>()
            {
               @Override
               public Object call() throws Exception
               {
                  System.setProperty("org.jboss.forge.furnace.test", "true");
                 
                  furnace.setServerMode(true);
                  furnace.start(loader);

                  SecurityActions.cleanupThreadLocals(thread);
                  return null;
               }
            });
         }
         catch (Exception e)
         {
            throw new RuntimeException("Failed to start Furnace container.", e);
         }
      }

      public void stop()
      {
         furnace.stop();
      }
   }

   @Override
   public String toString()
   {
      String result = "Furnace: " + runnable.furnace.hashCode() + "\nStatus: " + runnable.furnace.getStatus() + "\n\n";
      for (AddonRepository repository : runnable.furnace.getRepositories())
      {
         result += repository + "\n";
      }
      result += "\n" + runnable.furnace;
      return result;
   }
}
TOP

Related Classes of org.jboss.forge.arquillian.ForgeDeployableContainer$ForgeRunnable

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.