12 Replies Latest reply on Jan 6, 2006 1:13 PM by christian.bauer

    Embeddable bootstrap API

    bill.burke

      I want to move to a generic deployment mechanism for the Embeddable EJB3 stuff and need feedback from those working with this.

      The way it would work is that there would be two generic deployments. One for tomcat, one for junit/standalone apps.

      There is a MainDeployer service like in the current kernel and a Deployer for each deployment type: EJB, AOP, beans.

      The junit/standalone deployment has a Scanner service that looks at java.class.path for all jars and directories. For each one of these paths, it tries to deploy it with the MainDeploy.

      For WARs and Tomcat, there will be a Scanner for looking through servletContext.getResourcepaths("/WEB-INF/lib"); and WEB-INF/classes. Again, for each URL it will ask the MainDeployer to deploy it.

      With this mechanism, you just throw your aop.xml, beans.xml, and ejb.jars in your classpath or WEB-INF/lib and they are automatically picked up. So, if you need to deploy different bean files (for instance, if you want JMS), or to fine tune the AOP stuff, you can just add these files to your classpath or WEB-INF/lib WEB-INF/classes

      The question is, is this good enough for a default deployment? Christian had a lot of input into this. What does he think?

      So the base beans file would be:

      <bean name="MainDeployer class="org.jboss...MainDeployer"/>
      
      <bean name="Scanner" class="...Scanner"/>
      
      <bean name="EJB3Deployer" class="...EJB3Deployer"/>
      <bean name="BeansDeployer class="...BeansDeployer"/>
      <bean name="AOPDepoyer".../>
      


      And that's it. There would be a static class to initialize this file and create the base Kernel or a servletcontextinitializer for the web case. Is that good enough?

        • 1. Re: Embeddable bootstrap API
          christian.bauer

          I guess there are 5 primary deployment scenarios in JSE:

          - scan the whole classpath (default, but very slow)
          - scan a directory of .class files
          - scan several directories of .class files
          - scan a JAR
          - scan several JARs

          The "deploy-dir-from-resource" etc. mechanism is actually OK, if it would work as expected, be tested, and if it would have less cryptic names and better documentation.

          For webapp the WEB-INF/lib and WEB-INF/classes sounds right, but I should have to option to disable one or the other.

          Frankly, I don't even know what you mean when you say "EJB, AOP, beans" or what a "base beans" configuration file is. Why, as a user, should I care about this distinction and internal implementation detail?

          ---

          Playing user:

          I write EJB session and entity beans and drop them into my classpath directory or package them in a JAR in whatever way I like. Ideally I want to list all these components somewhere, so I can include and exclude stuff that isn't finished during development. But, despite the hundreds of postings about problems on the forum, automagic deployment scanning is what I have to use. Next stop, configuration.

          I don't want to see or touch more than 1 configuration file where I enter my datasource, and 1 persistence.xml. I don't want to copy a configuration file that I will never edit. If I want JMS I expect that I drop in 1 JAR and maybe 1 more configuration file (although defaults should be sensible). I expect that the configuration files have names that make sense to me immediately.

          I want to start the server with 1 line of code or one option in web.xml. I want to deploy my EJBs with 1 line of code or 1 line in a configuration file, to trigger the right scanner magic and hope for the best.

          ---

          Your goal should be to satisfy a stupiduser with these requirements, no distractions. You also know my opinion about the library issue, 40-50 JARs are still about 35 too many.

          In other words: place yourself in the situation of a user who has to work with this stuff for the first time in his life. He wants to write a few session and entity beans to work with a database. As a rule, everything he does, be it copy a file, edit it, or set a configuration option, has to be done for a very very good reason, and that step has to be explained to him. If you find any step that does not make perfect sense from the perspective of this user, it should be hidden away and not exposed immediately. Every step counts and will forever influence how this user thinks about the friendliness of the software he is working with. Every new term or name he has to learn during that process (AOP, beans, foobar) should be avoided.

          PS: E-EJB3, MC, and Seam share a lot of configuration options and even duplicate a few things (like the JTA bootstrap) but with slightly different names for properties. These are open JIRA issues that should be resolved at the same time.

          • 2. Re: Embeddable bootstrap API
            christian.bauer

            Another thing we can do easily is exclude all known JARs from scanning for the "search the whole classpath" strategy.

            • 3. Re: Embeddable bootstrap API
              maxandersen

              wouldn't that be too much black magic ?
              (maybe not if it users can redefine what the "exclude-jar-list" contains)

              • 4. Re: Embeddable bootstrap API
                christian.bauer

                Well, after fighting it for a few months now, I consider automatic scanning and deployment to be much more difficult to handle than maintaining a list of all my components somewhere. It should at least be possible to disable it and maintain a list of components.

                Say I'm working on 5 SLSBs but I didn't really finish them. That means they compile but can't be deployed properly. However, I still want to deploy and test my application, maybe because I'm working on a different part. Now my only choice is to go into each of the 5 SLSBs and comment the @Stateless annotation. This is even worse for entity beans, because you rarely map a whole entity bean before testing it. However, you can disable automatic scanning of HEM with an undocumented setting, so this at least avoided further frustration.

                • 5. Re: Embeddable bootstrap API
                  maxandersen

                  Yes - I fully agree that automatic scanning only solves a minor issue (needing to list the components somewhere) and introduces a cumbersome debugging process when doing development.



                  • 6. Re: Embeddable bootstrap API
                    bill.burke



                    Frankly, I don't even know what you mean when you say "EJB, AOP, beans" or what a "base beans" configuration file is. Why, as a user, should I care about this distinction and internal implementation detail?


                    Well, you were complaining on JIRA that there should be one bootstrap mechanism for the Kernel. EJB3 requires AOP and beans deployments to work. We could create a common mechanism to bootstrap.

                    BTW, do you know how JBoss works? You set up a Scanner that points to a particular directory. The scanner looks at the directory for deployments and tells a MainDeployer to deploy them. This is what we could do for your scenario.

                    deployable-classes/
                    deployable-jars/
                    undeployable-jars/
                    undeployable-classes/

                    You would set up a scanner for the deployable ones and this is what I want to set up for E-EJB3.


                    ---

                    Playing user:

                    I write EJB session and entity beans and drop them into my classpath directory or package them in a JAR in whatever way I like. Ideally I want to list all these components somewhere, so I can include and exclude stuff that isn't finished during development. But, despite the hundreds of postings about problems on the forum, automagic deployment scanning is what I have to use. Next stop, configuration.


                    So, you're saying that you *DONT* want to automatically scan java.class.path by default.

                    I see a problem here depending on what the user is doing. If you are unit testing, you don't want to have to list all the things you want deployed. You just want it to work. Same with a web archive. In development, you really want to specify all the stuff you want to deploy?

                    IMO, the simplest solution is that the user just creates JAR files and calls one line of bootstrap code. That's it. Or, in the WAR case, just add the listener to web.xml. This is the least amount of steps to do and works for unit testing and production. Yet, you're saying that in practice this doesn't work? Or, that this just doesn't work if you're doing development only.


                    How about this for an API?

                    public interface KernelDeployments
                    {
                     public void scanClasspath();
                     public void scanClasspath(List excludeList);
                     public void deploy(String fileOrDirName);
                     public void deploy(URL url);
                     public void deployDirectory(String dirName);
                     public void deployDirectory(URL url);
                     public void exclude(String fileOrDirName);
                     public void exclude(URL url);
                     public void shutdown();
                    }
                    


                    The dumb user just does:

                    KernelDeployer bootstrap = KernelBootstrap.begin();
                    bootstrap.scanClasspath();

                    A more advanced user could do:

                    bootstrap.exclude("foobar.jar");
                    bootstrap.scanClasspath();

                    And have a beans file that encapsulates this information:

                    <bean name="KernelDeployments" class="...">
                     <attribute name="scanClasspath">true</attribute>
                     <attribute name="excludeClasspath">
                     <list>
                     <element>foobar.jar</element>
                     <element>unready-directory</element>
                     </list>
                     </attribute>
                    


                    • 7. Re: Embeddable bootstrap API
                      starksm64

                      This is intersecting with the equivalent vfs and virtual deployments of the mc, so is that where you envision this being created?

                      • 8. Re: Embeddable bootstrap API
                        bill.burke

                         

                        "scott.stark@jboss.org" wrote:
                        This is intersecting with the equivalent vfs and virtual deployments of the mc, so is that where you envision this being created?


                        yes, I didn't see any work on this anywhere...is it progressing at all? I was going to prototype something eventually so that I could get something going for E-EJB3.

                        • 9. Re: Embeddable bootstrap API
                          starksm64

                          Yes, there is a vfs prototype that I wanted to talk about today on the call that did not happen. Where this gets added and what needs to be done to get to the point of building the new deployers is what we need to get straight.

                          • 10. Re: Embeddable bootstrap API
                            dimitris

                            Wherever it goes, I think it should be under new package names in jboss HEAD (and not the older jboss-pojo checkout), so we can slowly integrate this with what we have now.

                            • 11. Re: Embeddable bootstrap API
                              christian.bauer

                               

                              "bill.burke@jboss.com" wrote:

                              Well, you were complaining on JIRA that there should be one bootstrap mechanism for the Kernel. EJB3 requires AOP and beans deployments to work. We could create a common mechanism to bootstrap.

                              BTW, do you know how JBoss works? You set up a Scanner that points to a particular directory. The scanner looks at the directory for deployments and tells a MainDeployer to deploy them. This is what we could do for your scenario.

                              deployable-classes/
                              deployable-jars/
                              undeployable-jars/
                              undeployable-classes/

                              You would set up a scanner for the deployable ones and this is what I want to set up for E-EJB3.


                              That looks like a reasonable implementation strategy, assuming that "classes" are directories with .class files.


                              So, you're saying that you *DONT* want to automatically scan java.class.path by default.


                              With the "minimum" number of JARs this takes like 10 seconds last time I tested, to find a handful of classes in the many many thousands of classes.


                              I see a problem here depending on what the user is doing. If you are unit testing, you don't want to have to list all the things you want deployed. You just want it to work. Same with a web archive. In development, you really want to specify all the stuff you want to deploy?


                              I'm really trying to be pragmatic with this. Since I've spent many hours on the automagic scanning and deployment, reading documentation, trying, browsing the source code, forums, etc., I would just kill for the option to list my stuff somewhere and be done. I'm assuming that regular users feel the same.


                              IMO, the simplest solution is that the user just creates JAR files and calls one line of bootstrap code. That's it. Or, in the WAR case, just add the listener to web.xml. This is the least amount of steps to do and works for unit testing and production. Yet, you're saying that in practice this doesn't work? Or, that this just doesn't work if you're doing development only.


                              This is _not_ an option. I can not create a JAR file when I click on my "Run Tests" button in my IDE. I won't wait another 3 seconds longer to let that JAR file build everytime. I don't want to write an Ant script, no matter how small, so I can run my unit tests in the IDE. I want to click on my "Run Tests" button and I expect it to run the configured unit tests.


                              public interface KernelDeployments
                              {
                              public void scanClasspath();
                              public void scanClasspath(List excludeList);


                              Array here instead of List.


                              public void deploy(String fileOrDirName);
                              public void deploy(URL url);


                              OK, so I assume that means: "deploy all JARs found in this directory or that URL, or, deploy all .class files found in this directory or URL, or, deploy this JAR file"?


                              public void deployDirectory(String dirName);
                              public void deployDirectory(URL url);


                              Why would I use these methods? Or do you want to separate JAR from .class deployment? If yes, then they all need different names. The first two should probably be deployJars() and the second two should be deployClasses().


                              public void exclude(String fileOrDirName);
                              public void exclude(URL url);


                              And they should be named excludeJars() if that is what they do.


                              public void shutdown();
                              }

                              The dumb user just does:

                              KernelDeployer bootstrap = KernelBootstrap.begin();
                              bootstrap.scanClasspath();

                              A more advanced user could do:

                              bootstrap.exclude("foobar.jar");
                              bootstrap.scanClasspath();

                              And have a beans file that encapsulates this information:
                              ...


                              That seems reasonable. I still think we should have an internal list of excludes that will never be scanned. There is no reason why we should scan through thousands of JBoss and Hibernate classes on every deploy.


                              • 12. Re: Embeddable bootstrap API
                                christian.bauer

                                turin42
                                well yes, let's just assume that scanClasspath() is the default, and the options are a) there is a built-in list of excluces and b) I can specify my own excludes
                                that's the primary deployment method
                                and then we add a few deployFoo() methods that are more fine-grained alternatives

                                patriot1burke
                                ok

                                turin42
                                the deployFoo() methods should say what they are deploying, I'd probably make it three separate things:
                                1. deploy this directory full of JARs
                                2. deploy this directory full of .class files
                                3. deploy this particular JAR
                                not sure how the exclude() mechanism best fits into all of this

                                patriot1burke
                                well, you can't scan and deploy at the same time
                                that's the only thing

                                turin42
                                ok, so exclude() is only for scanClasspath()

                                patriot1burke
                                you could scan and exclude though

                                turin42
                                it shouldn't be a method then, i guess
                                but scanClasspath(String[] excludeJARs, String[] excludeClasses)

                                patriot1burke
                                ok
                                looks like I'm gonna have to become an Ecplise user to get this stuff working well :(

                                turin42
                                yeah, there is some special stuff with scanning going on there, max and emmanuel talked about it
                                they should know the details

                                turin42
                                btw, i guess it would be nice to offer relative resource locations on that API
                                like you did with deployByResource()
                                it was just a bit too much
                                with the new API the user will have to figure out a way to get a URL or directory name in a portable fashion
                                maybe something like getUrlForResource()
                                that uses the right classloaders internally and hides the 5 lines of code