11 Replies Latest reply on Feb 26, 2010 6:32 AM by Pete Muir

    Packager SPI

    Aslak Knutsen Master

      As a follow up from yesterdays Community meeting

       

      New packaging related SPIs:

      {code:java}

      package org.jboss.arquillian.spi; import org.jboss.shrinkwrap.api.Archive; /** * DeploymentAppender * * SPI used for modules who need to add classes/resources to the deployed archive. * * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a> * @version $Revision: $ */ public interface DeploymentAppender {    /**     * Create a archive containing the needed resources for this extension     * to run in-container.     *     * @return A Archive of any type     */    Archive<?> createArchive(); }

      {code}

       

       

      {code:java}

      package org.jboss.arquillian.spi; import org.jboss.shrinkwrap.api.Archive; /** * Extension point for client side deployment enhancements. * * Example: * - Annotations to help define meta data for the deployment * * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a> * @version $Revision: $ */ public interface UserArchiveProcessor {    /**     *     *     * @param userArchive The user defined deployment archive     * @param testClass The users test class     */    void process(Archive<?> userArchive, Class<?> testClass); }

      {code}

       

       

      {code:java}

      package org.jboss.arquillian.spi; import org.jboss.shrinkwrap.api.Archive; /** * Extension point to alter system defined deployments. * * Example: * - Add beans.xml to EE modules * * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a> * @version $Revision: $ */ public interface SystemArchiveProcessor {    /**     * Called once for each found ArchiveAppender     *     * @param rchive The system defined deployment archive     */    void process(Archive<?> archive); }

      {code}

       

       

      {code:java}

      package org.jboss.arquillian.spi; import java.util.Collection; import org.jboss.shrinkwrap.api.Archive; /** * Extension point for the DeployableContainer to prepare the Archives for deployment. * * Example: * - Create a EAR, WAR * * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a> * @version $Revision: $ */ public interface DeploymentPackager {    /**     * @param userArchive The user defined deployment archive     * @param systemArchives All found system defined deployment archives     * @return A archive to deploy     */    Archive<?> generate(Archive<?> userArchive, Collection<Archive<?>> systemArchives); }

      {code}

       

      And this is the current DeploymentGenerator impl that mix them all.

      {code:java}

      package org.jboss.arquillian.impl; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.jboss.arquillian.spi.DeploymentAppender; import org.jboss.arquillian.spi.DeploymentPackager; import org.jboss.arquillian.spi.ServiceLoader; import org.jboss.arquillian.spi.SystemArchiveProcessor; import org.jboss.arquillian.spi.UserArchiveProcessor; import org.jboss.shrinkwrap.api.Archive; /** * DeploymentAppenderArchiveGenerator * * @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a> * @version $Revision: $ */ public class ClientDeploymentGenerator implements DeploymentGenerator {    private ServiceLoader serviceLoader;       public ClientDeploymentGenerator(ServiceLoader serviceLoader)    {       Validate.notNull(serviceLoader, "ServiceLoader must be specified");             this.serviceLoader = serviceLoader;    }       /* (non-Javadoc)     * @see org.jboss.arquillian.impl.DeploymentGenerator#generate(java.lang.Class)     */    @Override    public Archive<?> generate(Class<?> testCase)    {       Validate.notNull(testCase, "TestCase must be specified");       DeploymentPackager packager = serviceLoader.onlyOne(DeploymentPackager.class);       Archive<?> userArchive = UserArchiveGenerator.generateArchive(testCase);       applyUserProcessors(userArchive, testCase);             List<Archive<?>> systemArchives = loadSystemArchives();       applySystemProcessors(systemArchives);       return packager.generate(userArchive, systemArchives);    }       private List<Archive<?>> loadSystemArchives()    {       List<Archive<?>> archives = new ArrayList<Archive<?>>();       Collection<DeploymentAppender> deploymentAppenders = serviceLoader.all(DeploymentAppender.class);          for(DeploymentAppender deploymentAppender : deploymentAppenders)       {          archives.add(deploymentAppender.createArchive());       }       return archives;    }    private void applyUserProcessors(Archive<?> userArchive, Class<?> testClass)    {       Collection<UserArchiveProcessor> processors = serviceLoader.all(UserArchiveProcessor.class);       for(UserArchiveProcessor processor : processors)       {          processor.process(userArchive, testClass);       }    }       private void applySystemProcessors(List<Archive<?>> systemArchives)    {       Collection<SystemArchiveProcessor> processors = serviceLoader.all(SystemArchiveProcessor.class);       for(SystemArchiveProcessor processor : processors)       {          for(Archive<?> systemArchive : systemArchives)          {             processor.process(systemArchive);          }       }    } }

      {code}

       

       

      The names are just the last names Pete suggested... (without the rename of DeploymentAppender to ArchiveAppender)

        • 1. Re: Packager SPI
          German Escobar Newbie

          I like it. Some observations though:

           

          1. The ClientDeploymentGenerator has a hard dependency to UserArchiveGenerator. I guess it will be loaded using the ServiceLoader.
          2. I would use the name DefaultDeploymentGenerator instead of ClientDeploymentGenerator.
          3. The SystemArchiveProcessor makes no sense if you don't know which system archive you are referring to. I would say we don't need processors for system archives, only for the TestArchive.
          • 2. Re: Packager SPI
            Aslak Knutsen Master
            1. The ClientDeploymentGenerator has a hard dependency to UserArchiveGenerator. I guess it will be loaded using the ServiceLoader.

            UserArchiveGenerator is the one that handles the @Deployment lookup. It's hard wired for now, at least until we find a good use case for letting it be configurable.

             

            1. I would use the name DefaultDeploymentGenerator instead of ClientDeploymentGenerator.

            It's called ClientDeploymentGenerator because it's doing the generation on the 'client side'. There is another one called NullDeploymentGenerator that does nothing and is run on the container side. This is not meant to be configurable since it's responsible for combining the whole Packager spi. With some upcoming refactoring the need for NullDeploymentGenerator should be gone tho..

             

            1. The SystemArchiveProcessor makes no sense if you don't know which system archive you are referring to. I would say we don't need processors for system archives, only for the TestArchive.

            I know it is a bit weak for the CDI EE module beans.xml issue, but it's the best solution that I've come up with so far.

            • 3. Re: Packager SPI
              Dan Allen Master

              On a first pass through, looks good.

               

              One question though.

               

              Is DeploymentAppender#createArchive() creating what we classify as a "system archive"? If so, I'd prefer that to be reflected in the method name:

               

              Archive<?> createSystemArchive();

               

              If I've go things mixed up, could you clarify where system archives show up?

              • 4. Re: Packager SPI
                Aslak Knutsen Master

                Is DeploymentAppender#createArchive() creating what we classify as a "system archive"? If so, I'd prefer that to be reflected in the method name:

                 

                Archive<?> createSystemArchive();

                Correct.. the DeploymentAppender interface is unchanged from the previous v. until we nail the naming.

                 

                I'm not sure I'm 100% sold on the 'System' name tho...

                • 5. Re: Packager SPI
                  Dan Allen Master

                  I spent some time thinking about the naming for system and user archives and I've come up with some suggestions.

                  System archive rename

                   

                  The term system seems to ambiguous to me. I'd like to recommend the following alternatives:

                   

                  • auxiliary - the archives are extra and they provide support, which I think is captured nicely in this term
                  • infrastructure - the extra archives really provide the infrastructure to execute the tests
                  • kernel - I only suggest this because on Linux, it is the complement to "user" (rather than system)

                   

                  I'm leaning towards auxiliary, so we would have as an example:

                   

                  Archive<?> createAuxiliaryArchive() 

                  User archive rename

                   

                  I think that we are misusing the term user. I wouldn't consider the developer writing tests a user. The archive they are creating is really the application archive. So here are some suggestions.

                   

                  • application - the deployment is really the application code that is being tested, so it is an application archive
                  • test - the archive is what is to be tested, so we could call it the test archive
                  • testable - we could even get more detailed and say this is the "testable" code

                   

                  I'm leaning towards application, so we would have as an example:

                   

                  public interface ApplicationArchiveProcessor { ... }
                  

                   

                  There may be an even better choice here. I'm still trying to think of what to call the user's code, which ultimately is what is being tested.

                  • 6. Re: Packager SPI
                    Pete Muir Master
                    I like it!
                    • 7. Re: Packager SPI
                      Aslak Knutsen Master
                      I guess we should follow up with AuxiliaryArchiveAppender ...
                      • 8. Re: Packager SPI
                        Aslak Knutsen Master

                        Then we have..

                         

                        {code:java}

                        // OnlyOne, prepare the final container deployment public interface DeploymentPackager {    Archive<?> generateDeployment(Archive<?> applicationArchive, Collection<Archive<?>> auxiliaryArchives); } // OnlyOne, generate a application archive based on the test case, ie handling @Deployment or @Artifact public interface ApplicationArchiveGenerator {    Archive<?> generateApplicationArchive(Class<?> testCaseClass); } // Multiple, extension point for adding more application archive helpers, ie @BeansXml, @EJBXml public interface ApplicationArchiveProcessor {    void process(Archive<?> applicationArchive, Class<?> testCaseClass); } // Multiple, extension point for adding other archives to the final deployment public interface AuxiliaryArchiveAppender {    Archive<?> createAuxiliaryArchive(); } // Multiple, extension point for addons to Axuilliary archives public interface AuxiliaryArchiveProcessor {    void process(Archive<?> auxiliaryArchive); }

                        {code}

                         

                        OnlyOne = Only one implementation can be configured at the same time.

                        Multiple = Multiple implementations can be used at the same time.

                        • 9. Re: Packager SPI
                          Pete Muir Master
                          BTW I suggest we call this group of SPIs the "enricher SPIs" - thoughts?
                          • 10. Re: Packager SPI
                            Aslak Knutsen Master

                            "Enricher SPIs" is a bit of a name clash with the TestEnricher spi, for testcase injection etc..

                             

                            http://anonsvn.jboss.org/repos/common/arquillian/trunk/spi/src/main/java/org/jboss/arquillian/spi/TestEnricher.java

                            • 11. Re: Packager SPI
                              Pete Muir Master
                              Yes, I realized this too later. So Packager SPIs it is :-)