Friday, August 24, 2012

Migration to JBoss 7.1 (1 part)

My current project migrate from JBoss 5.1 to JBoss 7.1 This migration caused by best moment to do this. So first attempt to migrate to JBoss 7.0 was in the begging of this year but this migration fails. Main problem was in to small time period for migration and work was done on my personal initiative. This time project has JSF UI part that work under MyFaces implementation and this was the thin place that produces many problems. Nowadays web UI transfered to tomcat server instance and conflicts between JSF implementation make no affect to migration. But many problems has been found during migration. So this is one of series of post about the features of 7.1 version.

First few words about project. This is a e-commerce platform. Technically platform includes 5 ear applications with big common part. There are strong requirements due security so some parts of application configurations (also configuration to database) are encrypted and this requirement rises problems. I start with little introducing to JBoss 7.1. JBoss 7.1 based on module system and this provides so effective server startup. You personally choose what modules (libraries) should be used. Particularly, JBoss developer team cut classes from JDK. So if application needed special classes from sun packages or others you should write them manually.
Read more Modules placed into ${JBOSS_HOME}/modules folder and structure like Java packages. So in ${JBOSS_HOME}/sun/jdk/main placed module for special JDK classes. Each package should has one slot ("main" slot by default) like in sun.jdk package you can place folder "other" and declare another classes that application needs and use "main" slot for one application and "other" for another. Declaration of module placed in module.xml file (one for each slot). Here is an example of httpcomponents module:


<module name="org.apache.httpcomponents" xmlns="urn:jboss:module:1.1">
    <properties>
        <property name="jboss.api" value="private"/>
    </property>

    <resources>
        <resource-root path="httpclient-4.1.2.jar"/>
        <resource-root path="httpcore-4.1.4.jar"/>
        <resource-root path="httpmime-4.1.2.jar"/>
        <!-- Insert resources here -->
    </resource>

    <dependencies>
        <module name="javax.api"/>
        <module name="org.apache.commons.codec"/>
        <module name="org.apache.commons.logging"/>
        <module name="org.apache.james.mime4j"/>
    </dependencies>
</module>

In "resources" section placed definition of jar's included in module. In "dependencies" placed dependencies for this module. So if in jars used any classes which not from jre or dependencies libraries there will be ClassNotFoundException in runtime. if you place in dependency module declaration attribute export="true" than dependency module will be added to current module (this is for transitive module dependencies). <> In sun.jdk module you can find another module.xml declaraton schema:

<module name="sun.jdk" xmlns="urn:jboss:module:1.1">
    <resources>
        <!-- currently jboss modules has not way of importing services from
        classes.jar so we duplicate them here -->
        <resource-root path="service-loader-resources">
    </resource>
    <dependencies>
        <system export="true">
            <paths>
                <path name="com/sun/script/javascript"/>
                <path name="com/sun/jndi/dns"/>
                <path name="com/sun/jndi/ldap"/>
                <path name="com/sun/jndi/url"/>
                <path name="com/sun/jndi/url/dns"/>
                <path name="com/sun/security/auth"/>
                <path name="com/sun/security/auth/login"/>
                <path name="com/sun/security/auth/module"/>
                <path name="sun/misc"/>
                <path name="sun/io"/>
                <path name="sun/nio"/>
                <path name="sun/nio/ch"/>
                <path name="sun/security"/>
                <path name="sun/security/krb5"/>
                <path name="sun/util"/>
                <path name="sun/util/calendar"/>
                <path name="sun/util/locale"/>
                <path name="sun/security/provider"/>
                <path name="META-INF/services"/>
            </paths>
            <exports>
                <include -set="-set"/>
                    <path name="META-INF/services"/>
                </include/>
            </exports>
        </system>
    </dependencies>
</module>
Here is declaration for packages from JDK that will be exproted in runtime. More detailed information available here So in the begging we have 5 ear application, project common libraries places with external libraries in ${JBOSS_HOME}/server/default/deploy/lib folder of JBoss 5.1, applications configurations (in xml files, some of them is encrypted). The easiest way to port this libraries is to place them into one modules (we decide to place project common libraries in one module and other tools-libraries into another). The next step is to write dependencies for modules. Here is the begging of evil. Thanks to opensource projects that there is source code that can be checked out for what happens there. Best situation when you received in runtime ClassNotFoundException but in sometimes libraries such as XStream produce so strange exceptions that if there is no source code you will never get what you should do. For example like this:

Caused by: java.lang.NullPointerException
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.addClassAlias(ClassAliasingMapper.java:44) [xstream-1.3.1.jar:]
at com.thoughtworks.xstream.XStream.alias(XStream.java:939) [xstream-1.3.1.jar:]
at com.thoughtworks.xstream.XStream.setupAliases(XStream.java:588) [xstream-1.3.1.jar:]
at com.thoughtworks.xstream.XStream.(XStream.java:443) [xstream-1.3.1.jar:]
at com.thoughtworks.xstream.XStream.(XStream.java:385) [xstream-1.3.1.jar:]
at com.thoughtworks.xstream.XStream.(XStream.java:323) [xstream-1.3.1.jar:]

If we check source code of XStream class, we see:

        if (JVM.is14()) {
            alias("auth-subject", jvm.loadClass("javax.security.auth.Subject"));
            alias("linked-hash-map", jvm.loadClass("java.util.LinkedHashMap"));
            alias("linked-hash-set", jvm.loadClass("java.util.LinkedHashSet"));
            alias("trace", jvm.loadClass("java.lang.StackTraceElement"));
            alias("currency", jvm.loadClass("java.util.Currency"));
            aliasType("charset", jvm.loadClass("java.nio.charset.Charset"));
        }
What a surprise, we tried to load JDK class "javax.security.auth.Subject" that not included into JDK module.
I assume to write next post about the configuration of all server. Thats mean explanation about the standalone.xml (I don't think that in the closest future I work with domain of jbosses so now only about stanalone :)