10 Replies Latest reply on Jan 19, 2010 2:42 PM by Remy Maucherat

    WarStructure metadata locations are wrong

    Ales Justin Master

      A recent post on MC user forum exposed a buggy behavior of our .war handling.

      * http://community.jboss.org/message/517508#517508

       

      The reason for this error is, as I stated already, how we handle metadata locations in wars.

       

      WarStructure.class

                  // Check for jars in WEB-INF/lib
                  List<VirtualFile> archives = null;
                  try
                  {
                     VirtualFile webinfLib = file.getChild("WEB-INF/lib");
                     if (webinfLib != null)
                     {
                        archives = webinfLib.getChildren(webInfLibFilter);
                        // Add the jars' META-INF for metadata
                        for (VirtualFile jar : archives)
                        {
                           // either same as plain lib filter, null or accepts the jar
                           if (webInfLibMetaDataFilter == null || webInfLibMetaDataFilter == webInfLibFilter || webInfLibMetaDataFilter.accepts(jar))
                              metaDataLocations.add("WEB-INF/lib/" + jar.getName() + "/META-INF");
                        }
                     }
                  }
      

       

      Afair this was added to make persistence.xml work as per the EJB/JPA spec,

      being able to recognise persistent context from any war's lib.

       

      While this works for JPA, it can cause a bunch of weird errors, as see in the user case.

      e.g. we treat lib's CLMD as deployment's CLMD

       

      This actually completely breaks .war deployment.

      There are other we probably didn't even notice.

      e.g. my.war/WEB-INF/lib/services.jar/META-INF/foo-jboss-beans.xml


      I guess the solution is to remove those extra lib's metadata locations,

      and fix how we handle JPA's persistence.xml.

        • 1. Re: WarStructure metadata locations are wrong
          jaikiran pai Master

          Is there some way to configure which files to look for in the metadata locations? Something like (just an example):

          <metaDataPath>
                      <path name="META-INF"/> <!-- will look for all types of metadata files -->
          </metaDataPath>
          <metaDataPath>
                      <path name="lib/*.jar/META-INF"> <!-- for lib/somejar.jar/META-INF --> 
                             <include name="persistence.xml"/> <!-- consider only persistence.xml files -->
                      </path>
          </metaDataPath>
          
          • 2. Re: WarStructure metadata locations are wrong
            Ales Justin Master
            Is there some way to configure which files to look for in the metadata locations? Something like (just an example):

            As you can see there is a VirtuaFileFilter webInfLibMetaDataFilter, which is a global configuration.

            And you can always use custom jboss-structure.xml.


            But this is a user question. We need to discuss what to do with that JPA's persistence.xml. ;-)

            So, we don't break too much stuff ... which will probably be hard to do with proposed WarStructure's change.

            • 3. Re: WarStructure metadata locations are wrong
              Ales Justin Master

              I suggest we disable libs META-INFs as units metadata locations:

               

              Index: deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/war/WARStructure.java
              ===================================================================
              --- deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/war/WARStructure.java (revision 98870)
              +++ deployers-vfs/src/main/java/org/jboss/deployers/vfs/plugins/structure/war/WARStructure.java (working copy)
              @@ -46,10 +46,13 @@
                  /** The default filter which allows jars/jar directories */
                  public static final VirtualFileFilter DEFAULT_WEB_INF_LIB_FILTER = new SuffixMatchFilter(".jar", VisitorAttributes.DEFAULT);
              
              -   /** The web-inf/lib filter */
              +   /** The WEB-INF/lib filter */
                  private VirtualFileFilter webInfLibFilter = DEFAULT_WEB_INF_LIB_FILTER;
              
              -   /** The web-inf/lib/[some-archive]/META-INF filter */
              +   /** Do we use WEB-INF/lib/[some-archive]/META-INF as deployment's metadata location -- false by default */
              +   private boolean useLibsMetaData = false;
              +
              +   /** The WEB-INF/lib/[some-archive]/META-INF filter */
                  private VirtualFileFilter webInfLibMetaDataFilter;
              
                  /** Whether to include web-inf in the classpath */
              @@ -98,6 +101,16 @@
                  }
              
                  /**
              +    * Do we use .war lib's metadata locations as our own?
              +    *
              +    * @param useLibsMetaData the use libs metadata flag
              +    */
              +   public void setUseLibsMetaData(boolean useLibsMetaData)
              +   {
              +      this.useLibsMetaData = useLibsMetaData;
              +   }
              +
              +   /**
                   * Set the webInfLibMetaDataFilter.
                   *
                   * @param webInfLibMetaDataFilter the webInfLibFilter.
              @@ -186,12 +199,15 @@
                              if (webinfLib != null)
                              {
                                 archives = webinfLib.getChildren(webInfLibFilter);
              -                  // Add the jars' META-INF for metadata
              -                  for (VirtualFile jar : archives)
              +                  if (useLibsMetaData)
                                 {
              -                     // either same as plain lib filter, null or accepts the jar
              -                     if (webInfLibMetaDataFilter == null || webInfLibMetaDataFilter == webInfLibFilter || webInfLibMetaDataFilter.accepts(jar))
              -                        metaDataLocations.add("WEB-INF/lib/" + jar.getName() + "/META-INF");
              +                     // Add the jars' META-INF for metadata
              +                     for (VirtualFile jar : archives)
              +                     {
              +                        // either same as plain lib filter, null or accepts the jar
              +                        if (webInfLibMetaDataFilter == null || webInfLibMetaDataFilter == webInfLibFilter || webInfLibMetaDataFilter.accepts(jar))
              +                           metaDataLocations.add("WEB-INF/lib/" + jar.getName() + "/META-INF");
              +                     }
                                 }
                              }
                           }
              
              

               

              And I'll re-write JPA/persistence.xml parsing to include those we as well in the case of .war deployment.

              • 4. Re: WarStructure metadata locations are wrong
                jaikiran pai Master

                Just a FYI - For EJB3.1, beans can be deployed from .war files and the ejb-jar.xml might reside in WEB-INF/lib/somejar.jar/META-INF. Carlo has been working to add support for EJB deployments in .war files for forthcoming 6.0.0.M2, so not sure if he's already done something in this area.

                • 5. Re: WarStructure metadata locations are wrong
                  Carlo de Wolf Master

                  We shouldn't change too much from the basic parsing deployer setup for all JavaEE components which are allowed within a war scope.

                  public class PersistenceUnitParsingDeployer extends SchemaResolverDeployer<PersistenceMetaData>
                  {
                     public PersistenceUnitParsingDeployer()
                     {
                        super(PersistenceMetaData.class);
                        setName("persistence.xml");
                        setRegisterWithJBossXB(true);
                     }
                  }
                  
                  • 6. Re: WarStructure metadata locations are wrong
                    Ales Justin Master

                    We shouldn't change too much from the basic parsing deployer setup for all JavaEE components which are allowed within a war scope.

                    OK, I impled this with minimal changes needed for deployer devs.

                    All you need to do is enable "alternative" metadata locations

                    * see this test MetaDataTypeFilterTestCase

                    • 7. Re: WarStructure metadata locations are wrong
                      Scott Marlow Master

                      Is this fixed yet?

                       

                      I was looking into an AS trunk unit test failure(org.jboss.test.jpa.test.WebClassesJPAUnitTestCase) that started occuring after MC 2.2 was merged to AS trunk.

                       

                      From reading the AS console output (and some code), it appears that the JPA persistence unit didn't get processed (which would explain why the test entity isn't found later by the entity manager).

                       

                      The persistence.xml is contained in the web archive (test-jpa-webclasses.war) in /WEB-INF/classes/META-INF/ and looks correct.

                       

                      Steps to reproduce:

                       

                      1.  Start AS web profile with "./run.sh -c web" command.

                       

                      2.  change into testsuite folder and issue "./build.sh" command to build testsuite.

                       

                      3.  Run the web profile test "./build.sh run-web-profile-unit"

                       

                      Click on this link to see the "Unknown entity: org.jboss.test.jpa.support.TestEntity" error that we currently get.

                      • 8. Re: WarStructure metadata locations are wrong
                        Ales Justin Master

                        The persistence.xml is contained in the web archive (test-jpa-webclasses.war) in /WEB-INF/classes/META-INF/ and looks correct.

                         

                        While I moved libs metadata locations to ALTERNATIVE type, the spec locations remained the same:

                        * http://anonsvn.jboss.org/repos/jbossas/trunk/server/src/main/java/org/jboss/web/deployers/WARStructure.java

                         

                        String[] metaDataLocations = new String[]{"WEB-INF", "WEB-INF/classes/META-INF"};
                        

                         

                        For JPA parsing deployer to now properly work - picking up lib's persistence.xml - it needs to be properly configured, see TldParsingDeployer.

                        (we need to add MetaDataTypeFilter.ALL)

                        • 9. Re: WarStructure metadata locations are wrong
                          Scott Marlow Master
                          Has anyone created a jira for making the suggested change and is anyone working on making the JPA deployer change?
                          • 10. Re: WarStructure metadata locations are wrong
                            Remy Maucherat Novice

                            I don't understand exactly what the interaction with persistence.xml is, but all the locations configured in WARStructure (as posted by Ales) are valid metadata locations for TLDs and the web fragments. So I don't think they should change.

                             

                            Some other folks wanted JARs in EARs to be able to contain TLDs, which would mean adding the same metadata locations (META-INF inside JARs, recusively) to EARStructure.