12 Replies Latest reply on Apr 15, 2009 8:07 AM by skajotde

    Web Beans + JPA

    pmuir

      Another integration issue for Web Beans/JSR299 - this time around JPA.

      The JSR299 spec says that any entities (either specified using @Entity or orm.xml) should not be simple beans (i.e. have injection/interception facilities). As per the other integrations with the container, I would like to this via the SPI, and have add this to our JPA integration point

      /**
       * Gets the class for each entity in the application
       *
       * @return the entity classes
       */
       public Collection<Class<?>> discoverEntities();


      I spoke to Emmanuel - the Class should be a sufficiently unique identifier here.

      https://svn.jboss.org/repos/webbeans/ri/trunk/spi/src/main/java/org/jboss/webbeans/jpa/spi/JpaServices.java

      From this arise two questions

      1) How do we hook into Hibernate to get this info out of it's session configuration (Emmanuel had a couple of ideas)?

      2) How do we access the hibernate session configuration from an MC bean, given we know the deployment unit?

        • 1. Re: Web Beans + JPA
          epbernard

          I've been thinking about it a bit more.
          Unfortunately, I don't think it should be the job of Hibernate to give that info. Here is my reasoning:
          - if an app uses 2 persistence providers (different), then you need to get the entities from both and an app server I think is required to work well with other providers.

          So that would mean that the container has to scan the entities (it does it already today via the PersistenceUnitInfo API) and understand the ORM.xml files to extract the list of entities.

          thoughts?

          • 2. Re: Web Beans + JPA
            alrubinger

            Emmanuel, I agree; reporting entities is out of scope for Hibernate.

            Probably this reporting is best handled by some integration layer in AS, a central registry that we can expose via an MC bean maybe?

            The problem comes when we start talking about this notion of extra scanning (==time). As an aside I've got in the back of my mind using MDR as that central authority (currently jboss-metadata has its own scanners again).


            More on this when I'm back next week I suppose. I've got to take deeper look at what's currently going on before offering any meaningful solutions. :)

            S,
            ALR

            • 3. Re: Web Beans + JPA
              wolfc

              I disagree:

              The JPA consumer (AS / Embedded) has no facility to identify an entity. This is custom logic per JPA provider.
              For example the JPA provider could have a @WhopperEntity which is an extension to the standard @Entity (extra cheese).
              In which case we'll never find it.

              • 4. Re: Web Beans + JPA
                epbernard

                So Carlo,
                Are you asking for a *standard* way to get the list of entities. ie a EntityManagerFactory.getEntities()

                This is not be easy to get for a few reasons, one of them being that you probably want to return some metadata model rather than the plain class and that it would take time to do in the JPA EG (hence likely be -1ed). But if we all agree that it's the only solution, then I am willing to do it.

                • 5. Re: Web Beans + JPA
                  pmuir

                  I agree with Carlo, whilst for the narrow scope of making WB spec compliant, I only need @Entity/orm.xml (i.e. spec'd entities) it would be much more user friendly to also extend this to provider specific entities (case in point is hbm.xml).

                  If necessary for EE6/AS6 we can do a simple impl:

                  * expose an SPI Iterable discoverOrmXml(); which should return all orm.xml in a DU (AS already has a facility to find meta-inf files in JARS), and parse it in WB for class names
                  * check entities for @Entity in WB
                  * make it possible to replace this simple impl if a container wants to (we would want to do so in JBoss for a hibernate-aware version - speed + hbm.xml)

                  • 6. Re: Web Beans + JPA
                    epbernard

                    If WB does check for @Entities and orm.xml it also needs to read the right META-INF/persistence.xml or a representation of it because:
                    - classes might not be scanned
                    - some non annotated class can be explicitly listed

                    • 7. Re: Web Beans + JPA
                      epbernard

                      If we are OK to go the non standard route, I can look at adding a method on HibernateEntityManagerFactory.
                      Set<Class<?>> getEntities();
                      returning the list of entities.

                      Or even better you can do

                      Collection metadatas = (Map) ( (HibernateEntityManagerFactory) emf ).getSessionFactory().getAllClassMetadata().values();

                      for(ClassMetadata metadata : metadatas) {
                      Class<?> entityType = metadata.getMappedClass(EntityMode.POJO);
                      if (entityType != null)
                      doStuffCauseItsAnEntity( entityType );
                      }

                      • 8. Re: Web Beans + JPA
                        pmuir

                         

                        "epbernard" wrote:
                        If WB does check for @Entities and orm.xml it also needs to read the right META-INF/persistence.xml or a representation of it because:
                        - classes might not be scanned
                        - some non annotated class can be explicitly listed


                        I would have to do a generic solution here I think, as we want JPA to work ootb when we are in e.g. Tomcat (non-spec requirement).

                        Is there some code I take from Hibernate or JBoss JPA for this? I would need to relicense it under APL.

                        • 9. Re: Web Beans + JPA
                          pmuir

                          I mean, is there some code I can take :-)

                          • 10. Re: Web Beans + JPA
                            epbernard

                            https://anonsvn.jboss.org/repos/hibernate/core/trunk/entitymanager/src/main/java/org/hibernate/ejb/packaging/PersistenceXmlLoader.java

                            is your best shot.

                            Enumeration<URL> xmls = Thread.currentThread()
                             .getContextClassLoader()
                             .getResources( "META-INF/persistence.xml" );
                            if ( ! xmls.hasMoreElements() ) {
                             log.info( "Could not find any META-INF/persistence.xml file in the classpath");
                            }
                            while ( xmls.hasMoreElements() ) {
                             URL url = xmls.nextElement();
                             log.trace( "Analysing persistence.xml: {}", url );
                             List<PersistenceMetadata> metadataFiles = PersistenceXmlLoader.deploy(
                             url,
                             integration,
                             cfg.getEntityResolver(),
                             PersistenceUnitTransactionType.JTA ); //might be RESOURCE_LOCAL in EE?
                             for ( PersistenceMetadata metadata : metadataFiles ) {
                             String provider = metadata.getProvider(); //could be used for a shortcut if Hibernate
                             List<String> classes = metadata.getClasses();
                             //same for mappingFiles can be orm.xml or hbm.xml with Hibernate
                             Set<String> jarFiles = ...; //need to scan these for @Entity @Embedded @MappedSuperclass
                             boolean exclude = metadata.getExcludeUnlistedClasses();
                             //if exclude == true => do not scan @Entity @Embedded @MappedSuperclass in the *main* jar
                            
                             }
                            }


                            you will also need orm.xml parsing and check for , <mapped-superclass > and
                            consider as the default package.



                            • 11. Re: Web Beans + JPA
                              wolfc

                              Alternatively, if you're on the VDF you can pick up the PersistenceMetaData attachment from the PerisistenceParsingDeployer.

                              http://anonsvn.jboss.org/repos/jbossas/projects/jpa/trunk/deployers/src/main/java/org/jboss/jpa/deployers/PersistenceParsingDeployer.java

                              • 12. Re: Web Beans + JPA
                                skajotde

                                 

                                "epbernard" wrote:
                                If we are OK to go the non standard route, I can look at adding a method on HibernateEntityManagerFactory.
                                Set<Class<?>> getEntities();
                                returning the list of entities.

                                Or even better you can do

                                Collection<ClassMetadata> metadatas = (Map<ClassMetadata>) ( (HibernateEntityManagerFactory) emf ).getSessionFactory().getAllClassMetadata().values();

                                for(ClassMetadata metadata : metadatas) {
                                Class<?> entityType = metadata.getMappedClass(EntityMode.POJO);
                                if (entityType != null)
                                doStuffCauseItsAnEntity( entityType );
                                }


                                I think it is good way, so

                                public Collection<Class<?>> discoverEntities();


                                is executed in context of deployed PU. EMF should take responsibility to discover which entities belong to it and expose API to get that information. So code for hibernate is ready, and for EMF which now doesn't expose similair API code discoverEntities should throw exception ..?