7 Replies Latest reply on Mar 16, 2009 6:10 AM by jaikiran

    Ordering a deployer which needs multiple inputs

    jaikiran

      If i have n number of deployers in a chain, is there a specific order these deployers follow while deploying an unit?

      Right now, i have the following scenario:

      public class FirstDeployer extends AbstractDeployer
      {
      
       public FirstDeployer()
       {
       setStage(REAL);
      
       // our only input is JBossMetaData
       setInput(JBossMetaData.class);
      
       // we generate FirstOutput.class as the output
       setOutput(FirstOutput.class);
       }
      
       public void deploy(DeploymentUnit unit)
       {
       // do something and add output
       unit.addAttachment(FirstOutput.class);
       }
      
      }
      
      
      


      public class SecondDeployer extends AbstractRealDeployerWithInput<JBossMetaData>
      {
      
       public SecondDeployer()
       {
       // set a visitor
       setDeploymentVisitor(new SimpleVisitor());
      
       // we generate SecondOutput.class as the output
       setOutput(SecondOutput.class);
       }
      
       private class SimpleVisitor implements DeploymentVisitor<JBossMetaData>
       {
       public void deploy(DeploymentUnit unit, JBossMetaData jbmeta)
       {
       // we generate SecondOutput.class as the output
       unit.addAttachment(SecondOutput.class);
       }
      
       }
      
      }
      



      public class FinalDeployer extends AbstractDeployer
      {
      
       public FinalDeployer()
       {
       setStage(REAL);
      
       // we rely on 2 inputs
       // 1) FisrtOutput.class Generated from FirstDeployer
       // 2) SecondOutput.class generated from SecondDeployer
       addInput(FirstOutput.class);
       addInput(SecondOutput.class);
      
       // we generate FinalOutput.class as the output
       setOutput(FinalOutput.class);
       }
      
       public void deploy(DeploymentUnit unit)
       {
       // we expect both the inputs to be present in the unit at this point
       FirstOutput one = unit.getAttachment(FirstOutput.class);
       SecondOutput second = unit.getAttachment(SecondOutput.class);
       }
      
      }
      
      
      


      As can be seen:

      * There are 3 deployers - FirstDeployer, SecondDeployer and FinalDeployer. Each are for the REAL stage.
      * The FirstDeployer generates FirstOutput.class as output
      * The SecondDeployer generates SecondOutput.class as output
      * Ordering between FirstDeployer and SecondDeployer is NOT of concern in this example, since each one is independent
      * The FinalDeployer expects 2 inputs - one from FirstDeployer and one from SecondDeployer. Ordering IS important here. So when FinalDeployer is invoked, for deploying the unit, it expects both the inputs to be available (as attachments) in the unit. So both the FirstDeployer and SecondDeployer should have processed the unit before reaching the FinalDeployer.

      However, from what i see, the FinalDeployer is invoked before the SecondDeployer and hence when the FinalDeployer tries to get hold of SecondOutput, it gets a null.

      Shouldn't the inputs add some sort of dependency/ordering within the deployers? More importantly, since the FinalDeployer relies on 2 inputs, shouldn't it be called only after *both* inputs are available? Right now, from the logs it appears to me that this FinalDeployer is being invoked when atleast one of the input is available.

      As a ugly hack (for testing) i set the relative order for the FinalDeployer and i see that it gets called after both the FirstDeployer and SecondDeployer are invoked (the original intention).

      public class FinalDeployer extends AbstractDeployer
      {
      
       public FinalDeployer()
       {
       setStage(REAL);
      
       // we rely on 2 inputs
       // 1) FisrtOutput.class Generated from FirstDeployer
       // 2) SecondOutput.class generated from SecondDeployer
       addInput(FirstOutput.class);
       addInput(SecondOutput.class);
      
       // we generate FinalOutput.class as the output
       setOutput(FinalOutput.class);
      
       // let's go last
       setRelativeOrder(Integer.MAX_VALUE);
       }
      ...
      
      }
      
      

      By the way, the setRelativeOrder - what is it relative to?



        • 1. Re: Ordering a deployer which needs multiple inputs
          alesj

          This should work.
          Can you post the log from DeployersImpl,
          after new deployer is added and it is ordered for its stage;
          DeployersImpl::addDeployer

           String stageName = stage.getName();
           List<Deployer> deployers = deployersByStage.get(stageName);
           if (deployers == null)
           deployers = Collections.emptyList();
           deployers = insert(deployers, wrapper);
           deployersByStage.put(stageName, deployers);
          
           this.deployers.add(wrapper);
          
           StringBuilder builder = new StringBuilder();
           builder.append("Added deployer ").append(deployer).append(" for stage ").append(stageName).append('\n');
           for (Deployer temp : getDeployersList(stageName))
           {
           builder.append(temp);
           builder.append("{inputs=").append(temp.getInputs());
           builder.append(" outputs=").append(temp.getOutputs());
           builder.append("}\n");
           }
           log.debug(builder);
          


          • 2. Re: Ordering a deployer which needs multiple inputs
            jaikiran

            Before i post the logs, the example i showed in my first post was theoretical/trimmed down version of the actual deployers. These logs will contain the real deployer names. I'll explain what each deployers expects as input and what it produces as output.

            Here's the log output from DeployersImpl:

            2009-03-13 14:30:24,252 DEBUG [org.jboss.deployers.plugins.deployers.DeployersImpl] Added deployer org.jboss.ejb3.nointerface.deployers.FinalDeployer@1cd3dd7 for stage Real
            org.jboss.ejb3.nointerface.deployers.FinalDeployer@1cd3dd7{inputs=[org.jboss.metadata.ejb.jboss.JBossMetaData, org.jboss.ejb3.Ejb3Deployment] outputs=[]}
            org.jboss.ejb3.nointerface.test.deployers.EjbModuleDeployer@75c744{inputs=[org.jboss.metadata.ejb.jboss.JBossMetaData] outputs=[org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData, org.jboss.beans.metadata.spi.BeanMetaData]}
            org.jboss.ejb3.nointerface.test.deployers.EjbComponentDeployer@12ca580{inputs=[org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData] outputs=[org.jboss.beans.metadata.spi.BeanMetaData]}
            org.jboss.deployers.vfs.deployer.kernel.KernelDeploymentDeployer@391da0{inputs=[org.jboss.beans.metadata.spi.BeanMetaData, org.jboss.kernel.spi.deployment.KernelDeployment] outputs=[org.jboss.beans.metadata.spi.BeanMetaData]}
            org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer@a0e990{inputs=[org.jboss.beans.metadata.spi.BeanMetaData] outputs=[]}
            
            

            In the logs,

            1) The FinalDeployer is the FinalDeployer that i had posted in the trimmed/theoretical example in my first post. Relies on JBossMetaData *and* Ejb3Deployment as the inputs
            2) The EjbModuleDeployer is the SecondDeployer (refered in my first post). This generates (output) Ejb3Deployment required by the FinalDeployer.

            That log shows that the FinalDeployer is considered *before* EjbModuleDeployer.

            Now when i set the relative order of FinalDeployer to Integer.MAX_VALUE, i'll get this log :

            2009-03-13 14:36:57,683 DEBUG [org.jboss.deployers.plugins.deployers.DeployersImpl] Added deployer org.jboss.ejb3.nointerface.deployers.FinalDeployer@150f0a7 for stage Real
            org.jboss.ejb3.nointerface.test.deployers.EjbModuleDeployer@ca5bff{inputs=[org.jboss.metadata.ejb.jboss.JBossMetaData] outputs=[org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData, org.jboss.beans.metadata.spi.BeanMetaData]}
            org.jboss.ejb3.nointerface.test.deployers.EjbComponentDeployer@151ac10{inputs=[org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData] outputs=[org.jboss.beans.metadata.spi.BeanMetaData]}
            org.jboss.deployers.vfs.deployer.kernel.KernelDeploymentDeployer@1dcc4cd{inputs=[org.jboss.beans.metadata.spi.BeanMetaData, org.jboss.kernel.spi.deployment.KernelDeployment] outputs=[org.jboss.beans.metadata.spi.BeanMetaData]}
            org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer@72d873{inputs=[org.jboss.beans.metadata.spi.BeanMetaData] outputs=[]}
            org.jboss.ejb3.nointerface.deployers.FinalDeployer@150f0a7{inputs=[org.jboss.metadata.ejb.jboss.JBossMetaData, org.jboss.ejb3.Ejb3Deployment] outputs=[]}
            
            

            As expected the FinalDeployer is the last one.



            • 3. Re: Ordering a deployer which needs multiple inputs
              jaikiran

              Okay, i have found the culprit - thanks to the logs you asked for. The EjbModuleDeployer (a.k.a SecondDeployer) even though it attaches the Ejb3Deployment to the unit, it never declares/exposes it as an output (i.e. doesn't addOutput):

              public class EjbModuleDeployer...
              {
              
               public EjbModuleDeployer()
               {
               addOutput(JBossEnterpriseBeanMetaData.class);
               addOutput(BeanMetaData.class);
              
               // Jaikiran: The Ejb3Deployment is not set as an output
               // even though this deployer adds it as an attachment to the unit. see below
               }
              
               public void deploy(DeploymentUnit unit)
               {
               // do some stuff
              
               // Add Ejb3Deployment to unit (even though the deployer doesn't declare this as an output)
               unit.addAttachment(Ejb3Deployment.class,obj);
               }
              
               ...
              }
              

              Adding a addOutput(Ejb3Deployment.class) should fix this issue for me. I believe the ordering of the deploying is done based on the input/output of various deployers.

              But, i still think MC should have handled this differently (not complaining ;-) ). The FinalDeployer was expecting 2 inputs and until the 2 inputs were available, it shouldn't have been invoked.

              • 4. Re: Ordering a deployer which needs multiple inputs
                alesj

                 

                "jaikiran" wrote:

                I believe the ordering of the deploying is done based on the input/output of various deployers.

                The order of _deployers_ is done based on inputs/outputs.
                This is not dynamic, it's resolved when a deployer is added per deployment stage.

                "jaikiran" wrote:

                But, i still think MC should have handled this differently (not complaining ;-) ). The FinalDeployer was expecting 2 inputs and until the 2 inputs were available, it shouldn't have been invoked.

                This can be achieved, but then you need to make this as a true dependency item.
                Which is not a common use case as attachments normally don't come on the fly,
                but are generated via some deployment flow,
                which needs to be predictable / consistent.
                Hence the 'static' natural order via inputs/outputs is perfect.

                • 5. Re: Ordering a deployer which needs multiple inputs
                  jaikiran

                   

                  "alesj" wrote:
                  "jaikiran" wrote:

                  I believe the ordering of the deploying...

                  The order of _deployers_ is done based on inputs/outputs.
                  This is not dynamic, it's resolved when a deployer is added per deployment stage.

                  Yep.

                  "alesj" wrote:

                  "jaikiran" wrote:

                  But, i still think MC should have handled this differently (not complaining ;-) ). The FinalDeployer was expecting 2 inputs and until the 2 inputs were available, it shouldn't have been invoked.

                  This can be achieved, but then you need to make this as a true dependency item.
                  Which is not a common use case as attachments normally don't come on the fly,
                  but are generated via some deployment flow,
                  which needs to be predictable / consistent.
                  Hence the 'static' natural order via inputs/outputs is perfect.



                  I agree with the 'static' natural order via inputs/outputs is the correct way. No issues :) However what i meant in my earlier post was something along the following lines:


                  1) The static ordering (mentioned above) decides the order when the deployer is checked for relevance for deploying a unit - This works currently in MC

                  2) When the deployer gets picked up in this order, check the "required inputs" for this deployer and also check the "attachments in the unit" being deployed, to see if *all* the required inputs are available. If yes, then the deployer is invoked. If not, then just ignore this deployer for deploying the current unit. Note that this #2 is currently what is missing in MC.


                  • 6. Re: Ordering a deployer which needs multiple inputs
                    alesj

                     

                    "jaikiran" wrote:

                    2) When the deployer gets picked up in this order, check the "required inputs" for this deployer and also check the "attachments in the unit" being deployed, to see if *all* the required inputs are available. If yes, then the deployer is invoked. If not, then just ignore this deployer for deploying the current unit. Note that this #2 is currently what is missing in MC.

                    This can easily be abstracted into helper deployer.

                    If that's really what you need, I'll create one in Deployers.
                    Open up a JIRA in JBDEPLOY and assign it to me. ;-)

                    • 7. Re: Ordering a deployer which needs multiple inputs
                      jaikiran