GlassFish Embedded: A Simple Way To Run Jakarta EE Apps
Jan Blavins shares how he builds both a server component and a client component in his project using the GlassFish Embedded container with little effort.
Join the DZone community and get the full member experience.
Join For FreeA long-time GlassFish user and active member of the GlassFish community, Jan Blavins uses GlassFish Embedded in an interesting way to take advantage of some of its unique features compared to traditional application servers. Here's my interview with him about using GlassFish Embedded in his project.
Ondro: Hi Jan, recently you raised a few issues in the Eclipse GlassFish project. What do you think of the project, the team, and the community around it?
Jan: The GlassFish project is pretty active these days. They have helped me with some complex issues that I have raised. I want to thank the whole GlassFish team, especially the people from OmniFish, who belong to the main contributors to the GlassFish project and helped me a lot with my issues with GlassFish.
Running GlassFish Embedded is pretty straightforward — you start GlassFish within a client application and deploy the server application to the running embedded GlassFish. The embedded server is created and destroyed by the tool on each tool session.
Ondro: What's your relationship with GlassFish? When did you start using it?
Jan: I started using GlassFish while GlassFish was in Oracle's hands as a reference implementation of Java EE. Some time ago, there were suggestions that GlassFish was not being actively maintained. Since Oracle's donation of GlassFish to the Eclipse Foundation, with support from the Foundation's GlassFish team and the OmniFish team (that also provides commercial support), the GlassFish project is very active, and the community around it is certainly present and responsive. That's one more reason for me to continue using GlassFish in the future.
Ondro: You told me that you use GlassFish Embedded in your project. Can you explain what your project is about?
Jan: My project is APILoader. APILoader is, I believe (quite possibly wrongly) the seed for the next generation of software performance testing tools. I won't say a lot about APILoader since it hasn't been released yet, and there is IP to protect. But I can say a bit about how it uses GlassFish Embedded.
For an individual, I intend that APILoader be deployed using GlassFish Embedded. This obviates the server administration, as the server is created and destroyed by the tool on each tool session.
Ondro: Sure, it would be interesting to hear how you use GlassFish Embedded. Can you explain the architecture of your application and how GlassFish Embedded fits into that?
Jan: OK. I'll first explain the context of APILoader and then how I use GlassFish to implement the desired architecture. Some software performance engineers work in teams and need to share artifacts. For them, a server-based tool is appropriate. Others work individually. For them, a server-based tool is an overkill, implying, as it does, server administration. So, APILoader has a server component and a client component, but they are deployed differently depending on the needs of their users. In all deployments, the database remains external.
For teams, I intend that APILoader be deployed as a server installation with multiple clients. The engineers share the server and the database for artefacts, and use the clients for isolation. APILoader supports accounts and projects. Accounts are hermetically sealed sets of projects. Projects are separated sets of artefacts, but with the option to copy selected artefact types between them. So engineers can work completely separately by using different accounts, or they can work in the same account, sharing account-level resources but with separate sets of project-level artefacts. Or they can work on the same project and share account and project-level resources. A team might use different accounts for testing different products where artefact sharing is unlikely. That team might use a different project for performance testing of each release of one product, initially populating each project selectively from its predecessor.
For an individual, I intend that APILoader be deployed using GlassFish Embedded. This obviates the server administration, as the embedded server is created and destroyed by the tool on each tool session. The individual can still use accounts and projects to separate the artefact sets for different pieces of work.
There is potentially a hybrid approach where each engineer runs an embedded GlassFish instance, but they choose to share a single (networked) database. The issue is that the 'database' in APILoader is distributed, with some data held in a relational database and some held in files associated with the server. So, in this scenario, those artefacts that are held in the database would be shared, but those held by the server are not (since each engineer has their own (embedded) server). This scenario doesn't appear useful as it stands because the relational database is used to access the file-based artefacts held by the server, and only a subset of file-based artefacts would be reachable by each engineer. It could be made an installation option that the file-based artefacts be held in one repository, independent of the servers. Then all artefacts would be shared. It would appear that the installation is shared by the team but with a greater degree of isolation for each engineer since the server isn't shared.
Ondro: It sounds like your architecture is very flexible. But it might also be a bit complicated to set up. Did you face any challenges with it or some approach that didn't work so well?
Jan: Running GlassFish Embedded is pretty straightforward — you start GlassFish within a client application and deploy the server application to the running embedded GlassFish. There is very little to do in the server application to cater for being runnable both as a remote server or embedded. (Or maybe there was more than I remember, but it is a once-only thing.)
However, there is one major consideration. GlassFish Embedded runs in the same JVM as the client. In remote server mode, it doesn't — it runs in a separate JVM process, often on a remote machine. This has significant implications for static resources. In embedded use, a static resource is shared between the client application and the embedded server. This allows some tempting shortcuts in coding that won't work in non-embedded deployment.
With EJBs, the serialisation is done automatically. With http-based communication, it would have to be done explicitly via SOAP, XML, or Gson/JSON.
Ondro: And how does it all work together? Isn't it too complicated to develop the application as a separate client and server? Would it not be simpler to use those shortcuts you mentioned and just implement them as a single desktop application?
Jan: Yes, it would be simpler. However, I still have to write the server so that distributed teams can share artifacts in a shared server. With the same approach for the desktop application and the client-server deployment, it's actually simpler for me in the end. The APILoader client is a (very) fat GUI. It started life as a web client, but I found myself spending inordinate amounts of time on the minutiae of HTML presentation. So now it's a GUI. As such, communication with the server presents new options. I have chosen to use remote EJBs. These work just as well against a remote or embedded GlassFish server. Once you overcome the issue of making the remote class definitions available to the client application, server EJBs are pretty straightforward to use. And, with a GUI client, they are simpler to use than HTTP-based messaging. The APILoader server and client communicate complex objects. With EJBs, the serialization is done automatically. With HTTP-based communication, it would have to be done explicitly via SOAP, XML, or GSON/JSON.
Note that the APILoader client is not an enterprise client. So, it isn't deployed to the server to run, and the EJBs aren't injected. Instead, the client gets access to the server's remotely accessible methods by doing context lookup()
calls.
Ondro: And how do you package the application in the end to address the two different deployment options?
Jan: A benefit of using GlassFish Embedded is simplified distribution inside the APILoader application to those clients who select the standalone option. Packaging and distributing the APILoader only has to cater to one brand of server and one release of that server. GlassFish Embedded is started from the application, and the server part is deployed to it in the same way as it can be deployed on a separate server.
On the other hand, the server option is packaged without any server. It is a convenient option in bigger teams because the server environment is usually better understood by infrastructure teams, which usually deploy the application to a preconfigured server.
Ondro: Thank you, Jan, for sharing your experience with GlassFish and architectural decisions in your APILoader project. I hope readers will find it inspiring if they have similar architectural challenges.
More information about GlassFish Embedded:
- Introduction to Embedded Eclipse GlassFish (GlassFish official documentation)
- GlassFish 7.0 Delivers Support for JDK 17 and Jakarta EE 10 (at InfoQ)
- Embedded GlassFish in less than 10 Minutes (video by John Yeary)
- How to upgrade to Jakarta EE 10 and GlassFish 7 (at OmniFish blog)
Published at DZone with permission of Ondro Mihalyi, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments