One thing I've learned over the years working with both JBoss and Weblogic is that applications developed on BEA Weblogic tend to accumulate some very difficult to remove dependencies on Weblogic's proprietary APIs. Maybe this is not as big of a problem now that BEA has done a lot of work to increase their compliance with the Java Enterprise standard, but still it seems that porting the other way around (JBoss to Weblogic) is much easier.
Anyway, this page captures some of the important differences I encountered when porting a fairly large and mature J2EE application from Weblogic to JBoss.
Server configuration in JBoss is very different from Weblogic. Where Weblogic is configured with a single, monolithic
config.xml file for each Weblogic 'Domain', JBoss uses modular configuration to match it's modular, JMX-based micro-kernel architecture.
Parameterized Configuration Files
JBoss configuration files support substitution of system properties using an ANT-like syntax:http://community.jboss.org/wiki/SystemPropertiesInConfigFiles
Changing port numbers using ServiceBindingManager
JBoss also has a special JMX service that pre-processes the configuration files for other services. Sounds a little over the top, doesn't it? However, it works quite well and it beats searching around for port numbers in all the little configuration files.
The basic idea behind ServiceBindingManager is that it applies transformations (defined in it's configuration file) to all the other JMX bean configuration files as they are read. This means that ServiceBindingManager must be defined before the other JMX services that it's going to configure, so that means it goes in
Application and Resource Deployment
- Classpath tricks are not required in JBoss. Most non-application (third party) jars can be copied to into the deploy directory.
- JMS queues and topics can be defined in any number of separate XML files. By default, Queues are persistent. In Weblogic, you need to specify StoreEnabled="true" in the JMSQueue or JMSTopic element. Also, JMS destinations only have JNDI name (Weblogic destinations have both a 'name' and a JNDIName).
- JNDI names for DataSources in Weblogic are not quite standard. JBoss requires 'java:' in front of the JNDI name for a data source.
- JNDI names for the JTA TransactionManager and UserTransaction are different.
- With JBoss Clustering, there are two separate JNDI trees: One local JNDI, and one HA JNDI. See #Clustering
Using JBoss JNDI from the web container (locally)
One big difference here is that Weblogic allows you to use the same code to connect remotely and locally. In JBoss, this is not the best way. If you need the local JNDI in the web container (for example, you want to invoke some EJBs from a Servlet), then simply create a new InitialContext the usual way:
There is no need to use the 'authenticating' InitialContext set up in this case either. If you need to authenticate, simply perform a JAAS login. After the login all calls to any EJBs (for example) will authenticate with the EJB container automatically.
Connecting to JBoss JNDI Remotely
Connecting to the JBoss AS to reference EJBs, etc., is a little bit different:
Alternatively, you can use the
jndi.properties way of getting an initial context using a
jndi.properties file in the client's classpath, for example:
Then, the client code can be simplified to:
NOTE: If you use the
jndi.properties approach, make sure that you do not include this client-side jndi.properties file in the *server classpath!*. EJBs and servlets deployed in JBoss that use
new InitialContext() will not work properly if you do this!
Connecting to a JBoss AS cluster is slightly different:
- Naming on JBoss http://docs.jboss.org/jbossas/jboss4guide/r4/html/ch3.chapter.html
- Connecting to JBoss JNDI: http://docs.jboss.org/jbossas/jboss4guide/r4/html/ch3.chapter.html#d0e6825
- Connecting to HA JNDI: http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossHAJNDIUseCluster
- Clusteried JNDI: http://docs.jboss.org/jbossas/jboss4guide/r4/html/cluster.chapt.html#clustering-jndi
Authenticating Remote EJB Clients
For the most part, Spring's Hibernate support works fine inside JBoss (well, of course Hibernate works fine for obvious reasons). The main problem is that basically, using Spring's Hibernate Session management is not really needed in JBoss. You will want to consider using Hibernate's built in session management if you are using Hibernate 3.x, as this complies with the JCA specification more closely than Spring.
Spring's Hibernate Session Factory and JTA
If you are using Spring's Hibernate DAO support, you will need to tie Spring transactions to JTA in order for the Hibernate Session management in Spring to work properly. The JNDI names of the transaction manager (and the 'current transaction') are different in JBoss:
Additionally, if you are using Spring's Hibernate Session management features, you may encounter some messages in the logs about closing JDBC connections. This is because Spring uses a thread local to manage the Hibernate session, which requires it to close the session during the JTA commit (via the JTA Synchronization callbacks. This is actually wrong, and JBoss is just pointing this out for you). This causes one of the JBoss EJB interceptors to fail. The good news is that JBoss is as configurable as a doubled jointed monkey and you can simply disable the interceptor.
- See JBoss Troubleshooting Guide for the workaround.
- See JBoss4 docos for more about how the EJB container can be configured.
Web Container Differences
It seems that BEA never really bothered to read the Servlet standard because the Weblogic web container, while for the most part compliant, does some strange things in the fringe areas. Not that Tomcat is without it's quirks, but at least those quirks are outside of the standard.
URL patterns in the web deployment descriptor are more strict in JBoss because of Tomcat. URL patterns need to begin with a forward slash '/', and they may end with a '', but '' cannot be anywhere else in the URL pattern. For example:
This is outside the standard, but worth mentioning. In Tomcat the default is to provide directory listings, whereas in Weblogic the default is to not provide directory listings.
See Disable Directory Listing in Tomcat for the details.
In the default configuration JBoss AS 4.x there is a valve that closes all JCA connections (JDBC, JMS, etc.) whenever a web request completes. It's kind of like training wheels for novice J2EE programmers. I'm fairly certain that Weblogic doesn't do this.
See JBoss CachedConnectionValve for instructions on how to disable it.
JBoss security is heavily oriented towards JAAS, as opposed to Weblogic which has it's proprietary idea of how to do security. This leaves a bit of a problem for applications developed under Weblogic when trying to port to the more standards-compliant security in JBoss. Nevertheless, there are some ways that JBoss can be made to emulate many of the proprietary behaviors in Weblogic.
Defining a security 'realm'
In order to enable security in JBoss, a security domain must be defined. This consists of defining a
LoginModule in the JBoss security manager. In the default server configuration the security manager MBean looks in
conf/login-config.xml for all the
The basic elements are:
- Define an application policy in
- Reference the policy in the JBoss specific EJB deployment descriptor (
META-INF/jboss.xmlin the EJB JAR) and/or the JBoss specific web deployment descriptor (
- Define roles for methods and urls.
Connect and Authenticate
Weblogic provides a special constructor for
weblogic.jndi.WLInitialContextFactory) that simultaneously logs in and also creates the initial context. JBoss provides a similar functionality with
org.jboss.security.jndi.JndiLoginInitialContextFactory, but there are some important differences.
In Weblogic, the security realm is applied to the JNDI tree itself somehow, but in JBoss, each EJB JAR may or may not be associated with a particular security domain. It is as if the remote client is logging in to JNDI itself. For example:
The next section describes the equivalent in JBoss.
When using JndiLoginInitialContextFactory, you are providing credentials for the security domains associated with the EJBs you are going to call. It won't actually log in until it needs to.
NOTE: The initial context factory provided with Embedded JBoss has this behavior already.
JAAS Login from a Remote EJB client
NOTE: This is much more code than the previous example using
JndiLoginInitialContextFactory! You might want to consider using it and skipping this section.
In order to login with JAAS, you also need 'auth.conf' somewhere in the client's classpath. This should define the ClientLoginModule, which is what is going to essentially delegate authentication to the EJB container.
Here is the auth.conf file from the JBoss JAAS Howo:
Here is the example from the JBoss JAAS Howto:
Programmatic Login from the Web Container
Weblogic has a proprietary API that allows programmatic login from the web container. This API automatically propagates the user's identity down into the EJB layer as well, and that identity will remain for the lifetime of the HttpSession. This is obviously outside of JAAS and J2EE security standards, but it can be fairly easily simulated using JBoss's JAAS-based security.
- There must be a security domain defined, and it must be referenced by the EJBs.
client-loginsecurity domain must also be configured, this is what will be used to authenticate to the EJB container from the Web Container (which is an EJB client after all).
- The EJBs must have at least one security roles defined on them with J2EE declarative security, or no principal will be able to invoke them: The JBoss interceptors will throw exceptions.
- Use a Servlet Filter to perform JAAS login for every request (don't worry, this shouldn't be very expensive as the JBoss security domain will cache authorizations anyway).
Basically, this is doing the same thing as the remote EJB client login except:
- Since the web container is already inside JBoss, the JAAS configuration isn't in 'auth.conf'.
- Since multiple users will be simultaneously accessing the system, each web request needs to do a JAAS login/logout. The username and password can be stored in the HTTP Session. This makes sure that each thread does the proper EJB client authentication.
JAAS Login Filter
Here is an example of a Servlet Filter that does JAAS login from the JBoss JAAS Howto:
Of course, in real life you would want to store the username and password somewhere in the HTTP session rather than in the init parameters for the filter. You would probably also want to encrypt these so that cleartext passwords are not written to log files or anything like that.
Getting 'the current user'
Weblogic provides a static method that returns the current user as a
java.security.Principal. This concept is not really part of J2EE, as J2EE defines the concept of 'current user' with respect to an EJB SessionContext or an HttpServletRequest. That is to say, there is no single method defined for obtaining the current user in J2EE, you need to know the context.
JBoss provides a proprietary API that performs a very similar function:
Clustering on JBoss is very different from Weblogic clustering. The most important difference is that a JBoss cluster will have two JNDI trees:
- The local JNDI tree on each node in the cluster, this is the one that runs on port 1099 by default.
- The HA-JNDI tree, which contains resources that are clusterable.
This provides more detailed control (and much less confusion) over what is going to be in the cluster JNDI vs the local resources that the cluster node (JVM) only cares about. However, it does require a change in how clients connect because there are new possibilities.
See JBoss Clustering
JBoss specific tools and scripts
twiddle (command line JMX invoker)
The 'twiddle' script is a command line tool that can do things with the JMX mbeans deployed in the JBoss server while it's running.
- Use a specific JBoss server: where 1099 is the JNDI bootstrap port (This is the JNDI url).
- Show all MBeans:
- List JNDI:
JBoss Error Messages
- Discussion on TSS http://www.theserverside.com/discussions/thread.tss?thread_id=14756