‘ll get right to the punch line: The choice between implementing real-world server-side solutions in Java vs. alternate technologies is not a foregone conclusion. More often than not, the concrete APIs and services offered by the Java 2 Standard Edition and Java 2 Enterprise Edition platforms meet or exceed the competition, but in several key areas related to server development, the tools available on these popular platforms are weak.
When a project’s requirements coincide with Java’s server-side weaknesses, the resultant Java solution can be difficult to build, non-portable, and hard to maintain. This is why my overall grade for using Java to build the various real-world servers businesses demand is only a B-.
This assessment of Java’s advantages and disadvantages regarding server-side development breaks along three somewhat orthogonal axes. I examine the platform’s facilities imbuing Java solutions with key server attributes: scalability, extensibility, throughput, security, manageability, and code-base maintainability. Java provides wonderful support for some of these attributes, but for others it falls far short of ideal in terms of convenience and support.
J2SE has several advantages for real-world services. An analysis of Java’s performance against its competition indicates that its platform independence, binary standards for code distribution, and J2SE’s inherent stability combine to give the Java platform portability advantages that far outweigh the competition. In fact, projects whose requirements coincide with these strengths simply can’t be built on alternate platforms (at least, not without exponentially more effort).
Examining non-technical areas and focusing on project management, the J2SE and J2EE platforms enjoy a large base of developers, decent tool sets, and wide industry support. From a project-management perspective, Java is in a league whose only other member is the suite of tools and technologies soon to be offered by Microsoft Corp.—those of the Visual Studio .NET platform.
With that in mind, let’s now get to the bottom of the strengths and weaknesses of Java as an enterprise server technology.
Server-side applications are standalone entities providing services to remote client applications. The prevailing wisdom is that server applications have special requirements that distinguish servers from other types of software and define a different measure of quality. Judging Java as a server-development platform requires evaluating the available APIs and services for realizing scalability, extensibility, throughput, security, manageability, and code-base maintainability.
Scalability: A high-quality server must handle high volumes of client sessions and/or individual client interactions (requests). The quality of a server is connected to its capacity for simultaneous sessions and requests.
J2EE is all about scalability. The J2EE platform defines component models (servlets and Enterprise Java Beans, specifically) with very high scalability potential. The session and request models in J2EE have activation/passivation and resource-pooling mechanisms that imbue servlet, EJB, and Java Messaging Service (JMS) solutions with a similarly high capacity for simultaneous sessions and requests.
The J2EE model is more or less equivalent to those provided by equivalent platforms: COM+/MTS and “pure” CORBA application servers. With respect to scalability, a good server design on the J2EE platform is limited only by the underlying hardware and O/S layers.
Entity Enterprise Java Beans have specifically come under fire for not being as scalable as, for example, MTS components, which are inherently stateless. I don’t agree with this argument, but a concerned designer could specifically omit the use of entity beans. Sticking to stateless session beans and handling all database interactions programmatically (through pooled JDBC connections) in bean code would be equivalent to the stateless server component model preferred by those who argue for MTS.
Extensibility: Business rules and vertical market logic must be able to be plugged into existing servers without recompilation or serious reconfiguration of the server. Component standards are also important; without them, code reuse is impossible.
On a basic level, the J2SE platform is very extensible. Java uses late-linking and a binary standard for classes that allow you to include new component implementations usually just by adding them to the Java classpath (or placing them in a similarly distinguished location available to the VM’s class loaders). J2SE thus provides a portable, simple extension mechanism for classes. There are lots of extensible servers implemented on J2SE, from small open-source projects to very large proprietary ones. The very volume of generic server types and frameworks (Jini, ObjectSpace Voyager and other agent-based systems, Apache and other non-J2EE servlet containers, to name just a few) implemented using J2SE attest to J2SE’s inherent extensibility.
J2EE, built on top of J2SE, defines its own reusable component types: servlets and EJBs. These generic component models are designed with specific classes of server solutions in mind. Where a project’s goals and servlet or EJB designs coincide, it is obviously easier to extend off-the-shelf servers than build your own servers from scratch.
It’s important to note, however, that not all server solutions will be optimally implemented using servlets or EJBs, or even on the J2EE platform. For example, I was involved in a project with explicitly low scalability requirements; no more than 40 client sessions would be attached to a server. A prototype implementation using EJBs performed significantly slower than an alternative built using just J2SE. That’s because the EJB design sacrifices some per-client performance to guarantee high scalability. Again, J2SE’s late-linking and binary code compatibility are the foundations for building very extensible servers without J2EE.Measuring Server Quality
Throughput: Server quality is also measured by how quickly the server can process a clump of requests. Throughput is different than scalability, which is the number of simultaneous requests a server can handle. Throughput measures how quickly the server processes individual requests.
|Java does not currently have non-blocking I/O, which virtually guarantees Java server implementations bind one thread per client connection.|
Java server implementations built on J2SE, including J2EE implementations, either ignore the blocking I/O problem (sacrificing throughput and scalability in the offing) or write proprietary non-block libraries to replace the functionality of the java.io package.
For example, the WebLogic application server has shipped with a proprietary non-blocking I/O library since the earliest versions. Remote method invocation (RMI) developers are regularly reminded about the trade-off between scalability and throughput in RMI servers, which use the J2SE java.io package. A high volume of simultaneous requests will bring an RMI server to a halt, since one thread is required to handle each unique client request.
Java 2 Version 1.4 is set to include a non-blocking I/O package which should alleviate this scalability vs. throughput problem. But for projects that can’t use that platform, early project analysis must determine whether Java’s non-blocking I/O is a serious impediment to project success.
Security: The ability for a server to prevent access to unprivileged clients is de rigueur, as is the ability for the server to participate in constructing and communicating with clients across secured network connections. Higher-quality servers allow administrators to define client-access policy to a high level. For example, individual server-side resource access is provided to only a specific set of users.
J2SE and J2EE each have their own completely unrelated access and administration mechanisms. J2SE has a programmatic security API, based around individual methods securing themselves against unprivileged access by adding security guard blocks. On the other hand, the only portable security services mandated by the J2EE specification use deployment-time configuration files, which are convenient to use (much easier to implement and change than J2SE-based security) but provides a relatively coarse level of access control.
|These rules cannot be implemented using J2EE’s defined security configuration files without torturous, invasive, up-front design.|
Security is a lurking problem in J2EE-based servers. Developer culture tends to put off security implementation for a system until a relatively late development stage. I know from personal experience that ignoring the incompatibility between J2SE and J2EE security structures can be a project killer. After the J2EE (servlet and EJB) components are completed, it is devastating to realize your project’s complex security requirements can’t be implemented without very significant refactoring.
|Sun has not provided concrete direction in the area of server manageability.|
Code-base and Deployment Maintainability: Code-base and deployment maintenance in Java is a double-edged sword: There are significant advantages—and significant weaknesses. The dominance of the Java language on the J2SE and J2EE platforms is perhaps these platforms’ greatest strength with respect to code-base maintenance. An adept programmer can pick up the code from any other programmer and, if not understand it right away, can at least figure it out with minimum effort. (Compare that to the .NET platform’s avowed multilingual capabilities: I really can’t imagine a VB, a C#, and a COBOL programmer getting together to share or understand each other’s code.)
|The dominance of the Java language on the J2SE and J2EE platforms is perhaps these platforms’ greatest strength with respect to code-base maintenance.|
Where J2SE and J2EE fall quite short is in the area of version management and compatibility. There is no standard way to label a Java class with a particular version number or to indicate what versions of classes are compatible with what other versions. Similarly, other resources, such as data files, internationalization resources, etc., can’t really be stamped with version information. There is a weak standard for labeling JAR files with version information, but this information is not used by any of the standard class loaders or resource APIs, so there is basically no practical support for this type of versioning.
J2EE does not have a standard, portable scheme for deployments. Often this most significant hurdle to deploying a working J2EE-based solution is making sure an administrator is in place who knows the deployment and configuration vagaries of the chosen container implementation.
|Where issues of security, throughput, and management are secondary to platform-independence, the project will be implemented in Java—or it will fail.|
For a project with cross-platform requirements, the Java platform is virtually the only contender. Where issues of security, throughput, and management are secondary to platform-independence, the project will be implemented in Java—or it will fail.
A large part of standard Java APIs are dedicated to extending platform-independence to container- and implementation-independence. Take a look at the stated goals of the specifications; you’ll see that JDBC, JMS, J2EE, JNDI, and most other JXYZs state portability and implementation-independence as a goal. Despite reports of its demise, the software component marketplace—at least the Java part of it—is based around these open, implementation- and container-independent standards.
Project Management: Java has been embraced by tool vendors that run the gamut from open-source, freeware tools such as GNU Emacs to powerful commercial design and developments tools (TogetherJ, JBuilder, and VisualAge, to name a few). What I love about Java is how a team of developers using wildly different tools can successfully complete a project—even from far-flung locations. A developer with a minimum of free tools can participate in a Java project. The minimum set of tools includes the JDK, a decent editor (Emacs + Ant, for example), and a source-code management system, such as a concurrent versions system (CVS). (See “Six Years and Counting: The State of the Java Market” for more details about Java tools.)
In addition, most standard Java services have free reference implementations for Linux, Solaris, and Windows platforms. So, a J2EE project with a database component can be sufficiently replicated using the J2EE reference implementation and a database. The same code developed against this set of implementations should work without modification when run in an iPlanet or WebLogic server using any other RDBMS for which a JDBC driver exists.
The community of capable Java developers is large. Because of the component model complexities, however, a capable Java programmer is not a proficient EJB or servlet developer. In fact, it’s hard to find “guru”-level EJB developers, because design patterns for EJBs and servlets—which are not truly OO component models and often are inappropriate targets for traditional “gang of four” design patterns—are not firmly established. When considering using either J2SE or J2EE as a server-side application platform, you must consider the potentially high cost of putting together a team that can implement a solution. (For more details, look for our story on the “Java Skills Gap” and the Java Pro Developers’ Survey in early June in Part II of the “Judging Java” series.)Build Your Platform Around Technology Needs
Early in project design, a Java-based solution is well served by considering the weaknesses (outlined above) of Java for server-side development, specifically server management and security. These are non-trivial attributes of your server that, if neglected, can seriously impact the quality of the resultant solution; Java does not provide concrete or even well-defined solutions for these issues. I’m not recommending doing a full up-front design in these two areas; rather, I suggest that you consider what technologies are going to get what you need, and what facilities your candidate platform supports in those two areas.
For example, if you are considering J2EE, then you’ll eventually need a plan for dealing with security. Is the project likely to require complex security rules? If so, how will those be implemented? Will you use a specific container’s proprietary security APIs, roll your own security infrastructure, or simply rely on the coarse-grained (but portable) security facilities included in all J2EE containers?
As for J2EE management: Will you hook in to the container’s management infrastructure, design your own, or go with an open standard, such as JMX (betting that JMX will eventually be rolled in to J2EE and you’ll reap portability rewards in the future)?The up-front time spent considering these issues—where Java provides the weakest support—may add days or weeks to your timeline. However, neglecting these issues could well add many more weeks or months to the process.
One disadvantage of Java in the project-management sphere is the paradoxical high cost of some application servers. One would think that with open, portable standards, individual implementations would be in much stronger competition because migration is relatively easy. When a vendor tries to gouge a development company, the company just switches over to another implementation. The competition should be even more pronounced where very low-cost or even free alternative container implementations exist.
|I can’t explain the reluctance to use a cheaper J2EE container, but I’m gratified to know my code will still run in the $18,000 container if called upon to do so.|
So, Give Me the Breakdown
A high-quality server has coding requirements to guarantee some level of scalability, extensibility, throughput, manageability, security, and code-base/deployment maintainability. The J2SE and J2EE platforms provide good support for some areas but are weak in others. A viable candidate platform is one that has facilities to support a project’s requirements. Where the platform is weak, then affordable third-party solutions must exist, or you must realistically be able to build what you need and add it to the platform.
Where the Java platforms are weak, there are third-party solutions—often implementations based on open standards—which guarantee a high degree of portability. Open standards also provide a framework for you to “roll your own” subsystem solutions, which will also retain compatibility with third-party solutions you might choose to use in the future. Java’s wealth of open-abstraction APIs is, in my humble opinion, one of Java’s greatest advantages.