1 2 3 4 Previous Next 47 Replies Latest reply on Sep 8, 2005 7:17 PM by starksm64 Go to original post
      • 30. Re: HARDeployer removal proposal
        sebersole

        I'll have a think through this "registration" bit for the admin console. Seems easy enough, though.

        For the deployer bit, here's what I have done so far (which I think is enough to remove the deployer...):
        1) Added code similiar to what Adrian posted regarding grabbing the classloader and "scanning it" for mappings. One additional thing I want to look at here is possibly using the new getDeploymentInfo() method Scott mentions and using getDeploymentInfo().ucl instead of Thread.currentThread().getContextClassLoader() to drive that. Maybe unfounded, but I am worried about start() coming from a source that perhaps does not go through the ServiceController.
        2) Based on the new getDeploymentInfo() method, I internalized all the logic that used to be in HARDeployer.accepts() into the Hibernate MBean startService() method. It uses that to attempt to determine a "HarUrl".
        3) The MBean is now capable of operating in essentially two modes. The first mode kicks in if the deployment was determined to be a HAR (see #2). Otherwise, it uses the code discussed in #1 to scan the classpath looking for mappings.
        4) added a new attribute "scanForMappingsEnabled" which is used in "har deployment mode" to enable the classpath scanning logic even in that mode (in addition to using the HarUrl as a mapping source).

        I think all this combined covers all the functionality we wanted to see here. Using "har deployment mode", users can continue to use .har archives (see below) to create "segmented" multi-SessionFactory deployments. Using "non-har deployment mode", users can simply include a service descriptor defining a Hibernate MBean that will then scan the deployment's classpath for mappings. All without the need for the HARDeployer.

        I still need to register ".har" as an accepted SARDeployer extension.

        • 31. Re: HARDeployer removal proposal
          starksm64

          What about a multi-session embedded mode. The Mappings attribute would be an HibernateMapping[] array object (something you may need to create) that is umarshalled from the xml based on the jbossxb schema mappings applied in the hibernate-mapping-3.0.xsd:

           <mbean code="org.jboss.hibernate.har.HARDeployer" name="jboss.har:service=HARDeployer">
           <attribute name="Mappings" serialDataType="jbxb">
           <hbm:mappings
           xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:hbm="urn:jboss:hibernate-mapping"
           xs:schemaLocation="urn:jboss:hibernate-mapping hibernate-mapping-3.0.xsd"
           >
           <hibernate-mapping package="org.jboss.test.hibernate.model">
          
           <!-- there is no "Edit Role" function, so map Role as an immutable class -->
           <class name="Role" table="t_role" mutable="false">
          
           <!-- there are few roles, and they are not updated so cache them -->
           <cache usage="read-only"/>
          
           <id name="id" type="long" unsaved-value="null">
           <generator class="increment"/>
           </id>
          
           <property name="name" unique="true" not-null="true" update="false" length="25"/>
           <property name="description" length="150"/>
           <property name="timeOfCreation" update="false" not-null="true"/>
          
           <!--
           this is the "inverse" association of the User.userRoles collection. This
           mapping demonstrates that an "inverse" end of a many-to-many does not need
           to be the same type of collection mapping as the other end!
           -->
           <bag name="users" lazy="true" table="t_user_role" inverse="true" order-by="timeOfCreation asc">
           <!-- the foreign key of the Role -->
           <key column="role_id"/>
           <!-- the foreign key of the User -->
           <many-to-many column="user_id" class="User" outer-join="true"/>
           <!-- Since Users are not cached, make sure we use an outer join! -->
           </bag>
          
           </class>
          
          
          
           <!-- A named HQL query. This uses a subquery, so it won't
           work on MySQL! -->
          
           <query name="unassignedRolesByUser.HQL">
           <![CDATA[
           from Role role
           where not :user in ( select u.id from role.users u )
           order by role.name desc
           ]]>
           </query>
          
          
           <!-- For MySQL 4.0, which has no support for subselects, we
           need to use an ON-clause condition which is not provided
           by HQL. So we will use a named SQL query instead. -->
          
           <sql-query name="unassignedRolesByUser.MySQL">
           <![CDATA[
           select {rol.*}
           from t_role rol
           left join t_user_role ur
           on ur.role = rol.id and ur.user = :user
           where ur.id is null
           order by rol.name desc
           ]]>
           <return alias="rol" class="Role"/>
           <synchronize table="t_user_role"/>
           </sql-query>
          
          
           </hibernate-mapping>
           <hibernate-mapping package="org.jboss.test.hibernate.model">
          
           <class name="User" table="t_user">
          
           <id name="id" type="long" unsaved-value="null">
           <generator class="increment"/>
           </id>
          
           <!-- Use a timestamp for optimistic locking -->
           <version name="timeOfLastUpdate" type="calendar"/>
          
           <!-- We don't change the handle, so map it with update="false". -->
           <property name="handle" unique="true" not-null="true" update="false"/>
          
           <!-- password is a keyword in some databases, so quote it -->
           <property name="password" column="`password`" not-null="true"/>
          
           <property name="email"/>
          
           <!-- We can't change the creation time, so map it with update="false". -->
           <property name="timeOfCreation" update="false" not-null="true"/>
          
           <!-- Mapping for the component class Name -->
           <component name="name">
           <property name="firstName"/>
           <!-- initial is a keyword in some databases, so quote it -->
           <property name="initial" column="`initial`"/>
           <property name="lastName"/>
           </component>
          
           <!--
           A many-to-many association modelled using a composite-element mapping
           (this lets us keep track of the time of creation for the link. We use an
           <idbag>, since that gives us a nice surrogate key.
           -->
           <idbag name="userRoles" lazy="true" table="t_user_role" order-by="timeOfCreation asc" cascade="save-update">
           <!-- the surrogate primary key -->
           <collection-id column="id" type="long">
           <generator class="increment"/>
           </collection-id>
           <!-- the foreign key of the User -->
           <key column="user"/>
           <!--
           a composite-element holding the associated Role and User, and the
           creation time of the link
           -->
           <composite-element class="UserRole">
           <!-- for convenience, a backpointer to the User -->
           <parent name="user"/>
           <!-- an "extra" column -->
           <property name="timeOfCreation"/>
           <!-- the foreign key of the Role -->
           <many-to-one name="role" cascade="save-update" outer-join="false"/>
           <!-- since Roles are cached, disable outerjoining! -->
           </composite-element>
           </idbag>
          
           <!--
           Usually, when we access the user's roles, we don't care about the creation
           time of the link, etc. - we just want the roles themselves. So we map
           another collection to the same table. This demonstrates how inverse="true"
           can be used for purposes other than modelling a bi-directional association!
           -->
           <bag name="roles" lazy="true" table="t_user_role" inverse="true" order-by="timeOfCreation asc" cascade="save-update" batch-size="9">
           <!-- we access this collection often, so cache it. -->
           <cache usage="transactional"/>
           <!-- the foreign key of the User -->
           <key column="user_id"/>
           <!-- the foreign key of the Role -->
           <many-to-many column="role_id" class="Role" outer-join="false"/>
           <!-- since Roles are cached, disable outerjoining! -->
           </bag>
          
           <!--
           A simple collection of values. This collection table has a composite
           primary key consisting of the user and password columns.
           -->
           <set name="previousPasswords" table="t_old_passwords" lazy="true">
           <!-- the foreign key of the User-->
           <key column="user_id"/>
           <!-- the element (of value type) -->
           <element type="string" column="pswd"/>
           </set>
          
           </class>
          
           </hibernate-mapping>
           </hbm:mappings>
           </attribute>
           </mbean>
          




          • 32. Re: HARDeployer removal proposal
            sebersole

            Well the Hibernate Configuration only accepts meta-data in a limited number of ways, all of which boil down to expecting some form of xml. So basically we'd be having jbossxb do the transformation from xml into a HibernateMapping[], and then transforming each HibernateMapping back to XML to pass to the Hibernate Configuration. Or am I missing something? I guess we could do something like Emmanuel is doing for the annotations. He extends the Configuration to plug in a new annotation-based Binder (which is the thing which interprets the incoming meta-data).

            Not to mention that maintaining the DTD is hard enough without having to duplicate stuff over to a schema.

            • 33. Re: HARDeployer removal proposal
              starksm64

              XML to Object back to XML is pointless. If there is not a usable object based metamodel then its not going to work. It seems like this is something to think about going forward as this is where everything else is going.

              • 34. Re: HARDeployer removal proposal
                sebersole

                So what is the "right" way to have '.har' recognized as a standard extension routed to the SARDeployer?

                • 35. Re: HARDeployer removal proposal
                  starksm64

                  It should be done by editing the org.jboss.deployment.SARDeployer-xmbean.xml Suffixes attribute, but the SARDeployer.accepts method is still using hard-coded values. This needs to be replaced with a traversal through the suffixes, and moved to the SubDeployerSupport base class where the suffixes attribute actually lives.

                  All of the deployers using simple suffix matching need to be updated to delegate to the SubDeployerSupport.accepts method for at least that part of the testing.

                  • 36. Re: HARDeployer removal proposal
                    sebersole

                    So I just added the following...

                    To org.jboss.deployment.SARDeployer-xmbean.xml:

                    <mbean>
                     <description>The SAR deployer handles the JBoss service archive deployments.
                     </description>
                     <class>org.jboss.deployment.SARDeployer</class>
                    
                     ...
                    
                     <attribute access='read-write' getMethod='getSuffixes' setMethod='setSuffixes'>
                     <description>Get an array of suffixes of interest to this subdeployer</description>
                     <name>Suffixes</name>
                     <type>[Ljava.lang.String;</type>
                     <descriptors>
                     <!-- Taken verbatim from old SARDeployer.accepts() -->
                     <value value=".sar,.sar/,.har,.har/,.deployer, .deployer/,service.xml,deployer.xml" />
                     </descriptors>
                     </attribute>
                    
                     ...
                    </mbean>
                    


                    To SubDeployerSupport:
                     public boolean accepts(DeploymentInfo sdi)
                     {
                     String[] acceptedSuffixes = getSuffixes();
                     if ( acceptedSuffixes == null ) return false;
                     String urlStr = sdi.url.toString();
                     for ( int i = 0; i < acceptedSuffixes.length; i++ )
                     {
                     if ( urlStr.endsWith( acceptedSuffixes ) ) return true;
                     }
                     return false;
                     }
                    


                    And removed SARDeployer.accepts().

                    This seems to break existing hars for watch though, because SARDeployer.init() sets the watch to "META-INF/jboss-service.xml" for exploded deployments. The HARDeployer explicitly required a "META-INF/hibernate-service.xml" descriptor. So should we force users to change this? Or should I modify SARDeployer further to conditionally set the watch based on the suffix matched? If so, I would think this should be configurable also...

                    • 37. Re: HARDeployer removal proposal
                      sebersole

                      Another question (yes another ;)

                      Now that HARDeployer can be removed, what should I do with the stuff in deploy/jboss-hibernate.deployer? Should that stuff just get moved to the various "server/xxx/lib"s?

                      • 38. Re: HARDeployer removal proposal
                        starksm64

                        Yes, the service classes need to be in the server lib directory.

                        To this point the suffix has had no correlation to the watch url. It was either the url in the case of a packed deployment/file, or the same deployer specific descriptor under META-INF for unpacked deployments. I'm inclined to keep it that way instead of introducing a suffix specific descriptor for now.

                        • 39. Re: HARDeployer removal proposal
                          sebersole

                          So then I will note in the docs that they will have to rename hibernate-service.xml to jboss-service.xml if doing an exploded har

                          • 40. Re: HARDeployer removal proposal
                            bsbodden

                            Steve,
                            Could you post a summary of what you did then to remove the HarDeployer and the changes needed to the SARDeployer to handle HARs? (including registering the .har extension). I ask this because I was following what you did with the HARDeployer before for integrating a product with JBoss and I know that others have also followed that pattern. With our integration we are also using a deployer to just pass the archive URL to the actual service which did seem like a lot of code for such little amount of work.

                            Thanks,
                            Brian Sam-Bodden

                            • 41. Re: HARDeployer removal proposal
                              sebersole

                              Well the first bit was adding code needed to locate one's deployment url inside of the MBean; this takes advantage of an MBean now being able to get a reference to its DeploymentInfo. Have a look at the Hibernate mbean; specifically startService() and determineHarUrl():
                              http://anoncvs.forge.jboss.com/viewrep/JBoss/hibernate/src/main/org/jboss/hibernate/jmx/Hibernate.java?r=1.18

                              All I *really* had to do with SARDeployer was to register the '.har' extension (there was more, but that was simply because SARDeployer did not previously really do anything with registered extensions). In your install layout, there is a directory /server/${server-config}/conf/xmdesc; within that directory there is a file named 'org.jboss.deployment.SARDeployer-xmbean.xml' (if there isn't look at either the 'default' or 'all' server configs). In that file you need to add/set the value for the Suffixes attribute:
                              http://anoncvs.forge.jboss.com/viewrep/JBoss/jboss/src/etc/conf/default/xmdesc/org.jboss.deployment.SARDeployer-xmbean.xml?r=1.2

                              That was essentially it.

                              • 42. Re: HARDeployer removal proposal
                                yangju

                                Talking about multiple sessionfactories, I am facing this issue now and hope you guys can give me some directions.
                                I am using jboss 4.0.2 and hibernate3. We have a central database and a bunch of administration databases. I wish I could define multiple har mbeans in one har's hibernate-service.xml. However, the jboss wiki page http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossHibernate3 mentions that "Only one org.jboss.hibernate.jmx.Hibernate MBean may be defined within a given hibernate-service.xml descriptor". Does this means that if I want to have another sessionfactory, I need to create another har file? If so, can I have the same set of .hmb files in these hars?
                                The situation is made worse by the fact that we cannot have an exploded har inside an exploded ear. In production, we always deploy exploded ear so that support can modify some configurations. The same thing for har. We would like to modify har's config in the middle of our production.

                                Is it a good idea to clone one har mbean at runtime (using MBeanServer API) and modify its datasource attribute and then use the new instance of mbean for the second database? This is what I did before but not sure it is a good idea. What about those hbm mappings? If I just clone the har mbean, does the new sessionfactory can see those mappings defined in another sessionfactory?

                                Thanks and I am looking forward to some advices.

                                Richard

                                • 43. Re: HARDeployer removal proposal
                                  sebersole

                                  So you need to understand that the purpose of defining a .har file is to 'partition' the the mapping files used to build a session factory, because the mappings are auto discovered within the bounds of that containing .har.

                                  If you define multiple Hibernate mbeans within the same .har each of the managed session factories will be constructed from all the discovered mappings. Typically that is nonsense; typically you have certain entities mapped to one datasource and other mapped to another. Thus that comment.

                                  You actually can define multiple Hibernate mbeans if you choose; you just need to be aware of these ramifications.

                                  • 44. Re: HARDeployer removal proposal
                                    sebersole

                                    So Norman ran into an interesting issue trying out this deployer-less har stuff. Just curious if this is expected behavior...

                                    Basically, he found that you could not have mappings/classes contained in a war file. The issue was that at the time of the call into the Hibernate mbean's startService() method the classpath does not contain the appropriate entries from the war; it does contain the war file/directory itself (i.e. the top-level) but not WEB-INF/classes nor WEB-INF/lib/{jar}.

                                    He says he set up the classloaders correctly for sharing from the war.

                                    So does that sound expected?