I created the Zenbi Architecture for basically two reasons. First, during my experience at a large financial institution, where I was the technical lead of the J2EE Websphere team, I saw that software development was extremely complex and that the J2EE Architecture itself was also too complex for what it could provide. I wanted to create a new architecture that was aimed at mainly one thing: simplicity. The architecture should be easy to understand and developing and maintaining systems with it should also be easy. At the same time, it should provide all the things that J2EE was meant to offer: scalability, performance, security, robustness, etc.
The second motivation was the fact that more and more things start moving towards the Cloud. Google was and is one of the main driving forces behind this trend. My architecture should be suited for Cloud-based deployment, relieving users from needing a technical infrastructure.
Being a long-time Java fan, the architecture was going to be based on Java. Javier Paniza, a Spanish developer, blogged about Java and simplicity and said something that perfectly represented my feelings about Java vs. software development:
"The productivity in Java world is a cultural problem, not a technical one. That is not a Java fault, it's our fault, we, the Java developers, need to design very beautiful architectures, to apply everywhere the GoF patterns, to do everything reusable, to put 3 tiers in all our systems and to use web services for all. We are not looking for simplicity, therefore we have not found it. But, Java is a very elegant language that allows simpler approach to software development."
The name "Zenbi" is a Japanese word, that you can write in 2 different ways: the first means "Perfection and Completeness", the second means "The good and the beautiful". That was my aim.
The Zenbi Architecture is a completely outside-the-box design:
- There is no application server or webserver. The server side consists out of a cluster of standalone Java applications
- There is no SOAP/WSDL for communication
- Everything is Java
- JavaFX based Java Applets
- Java 6
An architectural overview of the architecture is provided in the following picture (click to enlarge):
Now follows an explanation of the different components:
The Client is a Rich Internet Application, a JavaFX based Java Applet. Ever since the introduction of JavaFX (Java 6u10), the applet engine has improved, namely with the addition of the Java Deployment Toolkit. The most important thing about the Client is that the client holds the user-session! This is possible, because new (signed) Java Applets are actually first-class applications, despite being launched from the Cloud.
Server-side we have a cluster of RMI-Servers. An RMI-Server is a stateless standalone Java Application, that communicates with the Client via RMI. It is completely stateless, holds no session information and treats every request from a Client independently. If we do have to remember some state at the server-side, then we use the database for this, but this is extremely rare. The RMI-servers are 100% independent and know nothing of each other. Each one runs on a separate machine and has a separate ip-address. Because they are stateless, nothing has to be managed or replicated among the server instances.
As you can see in the picture, the Applet Jar, that is started from the index.html file, receives a list of ip-addresses where the RMI-Servers are located. When the user logs in initially, the Client remembers the username and the password and uses those for each individual request. The server is stateless and authentication and authorization therefore has to be done each time. How does a Client pick a server? Easy, it just picks one at random. If it doesn't respond, it picks another. So what do we have here? Infinite scalability, load balancing and fail-over, all basically for free! And all possible because we have a Rich Client that holds the user session.
Actually, the list of ip-addresses is refreshed before each individual request, so that, in case of permanent server failure, that server can be removed from the list, so that it won't be tried again. Also, you can modify and migrate your RMI-Servers without the Client even having to restart their application. Each RMI-Server also has a weight, so that you can add heavier hardware later and that hardware will be used more often than the less powerful older servers. This weight is also specified in the text-file.
SSL is used for communication. The public key truststore is downloaded by the Client from the HTTP-Server.
Despite the advantages, RMI has 2 main drawbacks, for which I had to come up with a solution:
- In RMI, when you serialize an object, all referred objects are also serialized. That means that if the Client requests one object, possibly thousands of other objects could be serialized as well, severely degrading performance.
- If an Exception is thrown at Server-side, you don't want it to propagate to the Client, since the stacktrace could contain security sensitive information.
Basically the Controllers specify all the methods that can be called by the Client. They call the DAO's to retrieve the necessary objects from the database and they return something from the domain-model. But as explained earlier, these domain objects are not suited to be sent over to the Client, because of the Serialization issues. They have to be mapped to the Transfermodel first.
The Transfermodel is designed to be sent over the line. So, it might not be the most beautiful OO-model, since that would mean lots of references, but objects of the Transfermodel (Transferobjects) are small and efficient. The Client does not actually call the Controllers, but rather the RMI-Controllers, which in turn call the Controllers and map the result to the Transfermodel using Dozer. If an Exception occurs, then the RMI-Controllers determine whether it is a functional exception (checked) or a technical one (unchecked), and a TransferError object is returned with the appropriate error message.
This means that the return type of all methods of the RMI-Controllers is GenericTransferObject, which can be a TransferError or another Transferobject from the TransferModel. It could also be a TransferVoid, if there is nothing to return.
Comparison to JEE
- Performance: RMI over JRMP is much faster than text-based protocols, such as SOAP over HTTP. Also, there is no more marshalling involved and no more application server overhead. Starting and stopping instances is much faster too. These are two charts depicting the speeds of the various protocols (source). SOAP can be compared to XML-RPC. Clearly, RMI is superior (click to enlarge):
Also when it comes to local development, the performance advantage is clearly noticeable. No more lengthy server reboots and redeploys that can take from dozens of seconds to minutes. Both RMI-Server and Client start within 3 seconds (using Application and Applet run configurations in Eclipse). Compare that to this!
- Robustness: This architecture is extremely robust, since every RMI-server is completely independent from the others. The Java application itself, the Operating System, even the hardware can be deployed redundantly. Every RMI-Server instance is completely separate from the others, does not even know about the others and is certainly not affected by a crash of one of the others, be it at hardware, OS or Java level. There is no single-point-of-failure between the Client and the Server. Also, the simplicity of the architecture and the absence of the application server layer make errors much less likely.
- Scalability: Maybe the strongest point of the architecture, besides its simplicity. Because the cluster of RMI-Servers can be expanded infinitely, because there is no single-point-of-throughput between the Client and the Server and because there is no overhead associated with scaling up, this architecture provides the best theoretically possible scalability.
Many people will wonder how it is possible that a single person comes up with something that might be superior to JEE in several ways. It's simple: The entire JEE / J2EE architecture comes from a different time. It comes from a time when there was no Spring, no Hibernate, no Dozer, no C3P0, no Jakarta Commons, etc. The standalone platform just wasn't suited for enterprise development. Now, it is. And because of Java(FX) Applets, we can now hold user-state at the Client-side and do scalability, load balancing and fail-over at the Client-side, opening up new possibilities. All the problems an application server was designed to solve, can now be solved in another way, making the application server no longer necessary.
The Development Factory
Besides the architecture itself, I have also created a reference implementation in the form of a Skeleton System, that serves as a template for customer systems that can be created with the Zenbi Architecture. This Skeleton System already has role-based authorization, multi-language support and usage-statistics, so this doesn't have to be implemented separately for each system. Of course, a development factory needs a buildserver. I have described the Zenbi Buildserver here.
And finally, I have created a System Manager, that takes care of deploying the various applications to the actual servers. The RMI-Servers are deployed to in parallel, so that a new version can be brought online very fast. File-transfers to the servers are done via SFTP, so that it is safe for Cloud-based deployments across the Internet.
Of course, no architecture is without drawbacks. This one too, has three drawbacks that I will discuss now:
- First of all, a JavaFX Applet does not integrate very well with HTML based platforms, such as Google Maps, Facebook or YouTube. Since integration is increasingly important, this is a serious drawback. You have to consider whether this is important to you before choosing Rich Internet Applications.
- The need for a Java Virtual Machine on the client computer. For most people, this is no problem, but large bureaucratic companies may have policies about this.
- "Write Once, Run Everywhere", the paradigm that made Java great, is dead. Completely and utterly dead. The cause? Smartphones and Tablets. These two are powerful hand-held computers now and their capabilities will keep increasing. Users will more and more use them as replacements for PCs. Still, none of these devices support Java SE, which is necessary to run the Client. Most of them (i.e. all except Apple) support proprietary versions of Java ME, that allow them to run Java-based fat clients, but Java Applets are not supported and I don't think they ever will be. Oracle does not seem to give it much priority and while it is a drawback of the Zenbi Architecture, it is a complete fiasco for Java.
I hope this article gives you a good understanding of how the Zenbi Architecture works and the benefits it provides. In the end, my primary aim was simplicity, since that is the base of all other good things. If you have any further questions or if you like to know more about this architecture, you can of course always contact me.
Perfection is achieved
not when there is nothing more to add,
but when there is nothing left to take away
- Antoine de Saint-Exupéry -
not when there is nothing more to add,
but when there is nothing left to take away
- Antoine de Saint-Exupéry -
Gert-Jan Schouten, MSc. is a Senior Software Architect / Engineer specialized in Java and Development Infrastructure. At this blog, he writes about his personal visions and thoughts.
Back to blog-index