We use Tomcat to host our WAR based applications. We are servlet container compliant J2EE applications with the exception of org.apache.catalina.authenticator.SingleSignOn.
We are being asked to move to a commercial Java EE application server.
What then are the benefits I'm not seeing?
What are the drawbacks that I haven't mentioned?
Mentioned were...
This is good, please more!
A Java EE server provides EJB and web containers. Enterprise JavaBeans (EJB) container: Manages the execution of enterprise beans for Java EE applications. Enterprise beans and their container run on the Java EE server.
While Tomcat has remained a lightweight, open-source servlet container, Websphere has become a large stack-based application server, one part of a larger group of interoperating IBM products under the same brand, including IDEs, portal services, data integration engines and more.
But even though Tomcat doesn't support some Java EE features out of the box, you can still use most of these features. You'll just need to include them as additional third-party dependencies in your application. The bottom line is that you can run Java EE applications on Tomcat.
Tomcat is a free, open source implementation of Sun's Java Servlets and Java Server Pages. It comes from the Apache Foundation's Jakarta project, which supplies pure Java tools, including the Struts web application development framework.
When we set out with the goal to Java EE 6 certify Apache Tomcat as Apache TomEE, here are some of the gaps we had to fill in order to finally pass the Java EE 6 TCK.
Not a complete list, but some highlights that might not be obvious even with the existing answers.
Transaction Management is definitely required for any certified server. In any web component (servlet, filter, listener, jsf managed bean) you should be able to get a UserTransaction
injected like so:
@Resource UserTransaction transaction;
You should be able use the javax.transaction.UserTransaction
to create transactions. All the resources you touch in the scope of that transaction should all be enrolled in that transaction. This includes, but is not limited to, the following objects:
javax.sql.DataSource
javax.persistence.EntityManager
javax.jms.ConnectionFactory
javax.jms.QueueConnectionFactory
javax.jms.TopicConnectionFactory
javax.ejb.TimerService
For example, if in a servlet you start a transaction then:
.. and then one of those things fails or you simply choose to call rollback()
on the UserTransaction
, then all of those things are undone.
To be very clear there are two kinds of connection pooling:
The Java EE specs do not strictly require connection pooling, however if you have connection pooling, it should be transaction aware or you will lose your transaction management.
What this means is basically:
close()
or any other method on the DataSource
.A common library used in Tomcat for connection pooling is commons-dbcp. We wanted to also use this in TomEE, however it did not support transaction-aware connection pooling, so we actually added that functionality into commons-dbcp (yay, Apache) and it is there as of commons-dbc version 1.4.
Note, that adding commons-dbcp to Tomcat is still not enough to get transactional connection pooling. You still need the transaction manager and you still need the container to do the plumbing of registering connections with the TransactionManager
via Synchronization
objects.
In Java EE 7 there's talk of adding a standard way to encrypt DB passwords and package them with the application in a secure file or external storage. This will be one more feature that Tomcat will not support.
WebServices security, JAX-RS SecurityContext, EJB security, JAAS login and JAAC are all security concepts that by default are not "hooked up" in Tomcat even if you individually add libraries like CXF, OpenEJB, etc.
These APIs are all of course suppose to work together in a Java EE server. There was quite a bit of work we had to do to get all these to cooperate and to do it on top of the Tomcat Realm
API so that people could use all the existing Tomcat Realm
implementations to drive their "Java EE" security. It's really still Tomcat security, it's just very well integrated.
Yes, you can drop a JPA provider into a .war file and use it without Tomcat's help. With this approach you will not get:
@PersistenceUnit EntityManagerFactory
injection/lookup@PersistenceContext EntityManager
injection/lookupEntityManager
hooked up to a transactional aware connection poolEntityManager
supportJTA-Managed EntityManager
basically mean that two objects in the same transaction that wish to use an EntityManager
will both see the same EntityManager
and there is no need to explicitly pass the EntityManager
around. All this "passing" is done for you by the container.
How is this achieved? Simple, the EntityManager
you got from the container is a fake. It's a wrapper. When you use it, it looks in the current transaction for the real EntityManager
and delegates the call to that EntityManager
. This is the reason for the mysterious EntityManager.getDelegate()
method, so users can get the real EntityManager if they want and make use of any non-standard APIs. Do so with great care of course and never keep a reference to the delegate EntityManager
or you will have a serious memory leak. The delegate EntityManager
will normally be flushed, closed, cleaned up and discarded when a transaction completes. If you're still holding onto a reference, you will prevent garbage collection of that EntityManager
and possibly all the data it holds.
EntityManager
you got from the containerEntityManager.getDelegate()
EntityManager
you created yourself via an EntityManagerFactory
-- you are 100% responsible for its management.I don't want to over simplify CDI, but I find it is a little too big and many people have not take a serious look -- it's on the "someday" list for many people :) So here is just a couple highlights that I think a "web guy" would want to know about.
You know all the putting and getting you do in a typical webapp? Pulling things in and out of HttpSession
all day? Using String
for the key and continuously casting objects you get from the HttpSession
. You've probably go utility code to do that for you.
CDI has this utility code too, it's called @SessionScoped
. Any object annotated with @SessionScoped
gets put and tracked in the HttpSession
for you. You just request the object to be injected into your Servlet via @Inject FooObject
and the CDI container will track the "real" FooObject instance in the same way I described the transactional tracking of the EntitityManager
. Abracadabra, now you can delete a bunch of code :)
Doing any getAttribute
and setAttribute
on HttpServletRequest
? Well, you can delete that too with @RequestScoped
in the same way.
And of course there is @ApplicationScoped
to eliminate the getAttribute
and setAttribute
calls you might be doing on ServletContext
To make things even cooler, any object tracked like this can implement a @PostConstruct
which gets invoked when the bean gets created and a @PreDestroy
method to be notified when said "scope" is finished (the session is done, the request is over, the app is shutting down).
CDI can do a lot more, but that's enough to make anyone want to re-write an old webapp.
There are some things added in Java EE 6 that are in Tomcats wheelhouse that were not added. They don't require big explanations, but did account for a large chunk of the "filling in the gaps".
@DataSourceDefinition
java:global
, java:app
, java:module
)@Resource MyEnum myEnum
and @Resource Class myPluggableClass
and @Resource(lookup="foo")
Minor points, but it can be incredibly useful to define DataSource
in the app in a portable way, share JNDI entries between webapps, and have the simple power to say "look this thing up and inject it"
As mentioned, not a complete list. No mention of EJB, JMS, JAX-RS, JAX-WS, JSF, Bean Validation and other useful things. But at least some idea of the things often overlooked when people talk about what Tomcat is and is not.
Also be aware that what you might have thought of as "Java EE" might not match the actual definition. With the Web Profile, Java EE has shrank. This was deliberately to address "Java EE is too heavy and I don't need all that".
If you cut EJB out of the Web Profile, here's what you have left:
It's a pretty darn useful stack.
Unless you want EJB proper, you don't need a full stack J2EE server (commercial or not).
You can have most J2EE features (such as JTA, JPA, JMS, JSF) with no full stack J2EE server. The only benefit of a full stack j2ee is that the container will manage all these on your behalf declaratively. With the advent of EJB3, if you need container managed services, using one is a good thing.
You can also have no cost full stack server such as Glasfish, Geronimo or JBoss.
You can also run embedded j2ee container managed services with embedded Glasfish for example, right inside Tomcat.
You may want an EJB container if you want to use session beans, message beans, timer beans nicely managed for you, even with clustering and fail over.
I would suggest to the management to consider upgrades based on feature need. Some of these EJB containers might just well use embedded Tomcat as their webserver so what gives!
Some managers just like to pay for things. Ask them to consider a city shelter donation or just go for BEA.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With