If you’ve spent any time building Java enterprise applications, you’ve likely heard the term Application Client Container — but most tutorials gloss over it in favor of web layers and REST APIs. That’s a mistake, especially if you’re maintaining or modernizing a system that relies on direct EJB access, JNDI lookups, or container-managed security. I’ve worked with Jakarta EE stacks long enough to know that the ACC is one of the most underappreciated pieces of the platform, and understanding it properly can save you hours of debugging and architectural confusion.
What Exactly Is an Application Client Container?
The Application Client Container (ACC) is a Jakarta EE (formerly Java EE) runtime environment that manages the execution of standalone Java client applications. Unlike a browser-based thin client that delegates most processing to the server, an ACC-hosted application runs in its own JVM on the user’s machine while still participating in the full enterprise security, naming, and transaction model provided by the server.
Think of it this way: your application server has a web container for servlets and JSPs, an EJB container for session beans and message-driven beans, and then — on the client side — the Application Client Container for standalone Java programs. The ACC bridges the gap between a desktop application and enterprise backend services, giving fat client applications the same managed runtime capabilities that server-side components enjoy.
According to the Jakarta EE specification (currently maintained by the Eclipse Foundation), the ACC provides dependency injection, JNDI access, JAAS-based security, and lifecycle management for client-side modules packaged in .jar files (Eclipse Foundation, Jakarta EE 10 Platform Specification, 2022).
The Three-Tier Architecture and Where the ACC Lives
To appreciate what the ACC actually does, you need to see it in the context of the classic three-tier enterprise Java architecture:
- Client Tier: This is where the ACC operates. It handles fat clients — standalone Java programs running on the user’s machine — as well as applet containers (now deprecated) and web browser clients.
- Middle Tier: This is the server side, where the EJB container manages your session beans and the web container handles servlets and JSPs.
- Backend Tier: Databases, legacy systems, message brokers, and other enterprise resources live here.
The ACC sits firmly in the client tier, but its whole purpose is to give the client application seamless, managed access to resources in the middle and backend tiers. When a fat client needs to call a remote stateless session bean, it doesn’t have to manage that connection manually — the ACC handles the bootstrapping, the security context propagation, and the naming resolution.
Thin Client vs. Fat Client: Understanding the Real Difference
One of the most common points of confusion I see in enterprise Java discussions is conflating thin clients and fat clients. They solve different problems and operate in completely different runtime environments. Here’s a direct comparison:
| Feature | Thin Client (Browser/Web) | Fat Client (Application Client Container) |
| Runtime Location | Server-side rendering | Client-side JVM on user’s machine |
| UI Technology | HTML, JavaScript, CSS | Swing, JavaFX, console-based |
| Resource Access | Via HTTP or REST APIs | Direct JNDI, RMI-IIOP |
| Security Model | HTTP sessions, JWT tokens | JAAS, IIOP credential propagation |
| Deployment Method | URL access via browser | appclient launcher or Java Web Start |
| Container Managed DI | Via CDI in web context | Full DI via @EJB, @Resource, @Inject |
| Typical Use Case | Public-facing web apps | Internal enterprise tools, batch clients |
The takeaway: a fat client managed by the ACC has a richer, more direct relationship with the enterprise backend. A thin client has to go through HTTP layers, which adds latency and limits access patterns. For internal tools where you control the client machine, the fat client model remains genuinely powerful.
Core Components of the Application Client Container
The ACC isn’t a monolithic black box — it’s a collection of well-defined services that work together to give your client application an enterprise-grade runtime. Here’s what actually makes it tick.
The Client-Side JVM
Everything starts with the client-side JVM installed on the user’s machine. The ACC bootstraps within this JVM, handling class loading, memory management, and OS-level communication. This is fundamentally different from the server’s JVM — your client application doesn’t share heap space or thread pools with the application server. The JVM is the foundation, and the ACC builds its services on top of it.
The Deployment Descriptor: application-client.xml
Every Jakarta EE client application can include a deployment descriptor called application-client.xml. This XML file, bundled inside the client .jar, tells the ACC how to configure the runtime:
- The main class entry point for the application
- JNDI references to remote EJBs, JMS queues, and data sources
- Security role definitions and the CallbackHandler class
- Environment entries for configuration values
Since Java EE 5, annotations like @EJB and @Resource have made the descriptor optional in many cases. But for complex deployments with multiple resource references and security role mappings, application-client.xml gives you explicit, reviewable configuration that annotations alone can’t always provide cleanly.
JNDI Lookup and Naming Services
The Java Naming and Directory Interface (JNDI) is how a client application locates remote enterprise resources. When your ACC bootstraps, it configures a JNDI InitialContext that points to the application server’s naming service. Your client can then look up remote EJBs, JMS connection factories, or data source references using their logical names.
In practice, you might see something like a lookup for a session bean using the portable global JNDI name format: java:global/MyApp/MyEJB/MyBeanImpl!com.example.MyBeanRemote. The ACC resolves this against the server’s naming registry and returns a remote proxy that the client can invoke directly.
Dependency Injection in the Client Tier
One of the features that distinguishes the ACC from a plain Java SE application is its support for dependency injection. You can annotate fields or setter methods in your main application client class with @EJB to inject remote EJB references, @Resource to inject environment entries or JMS resources, and @Inject for CDI-managed beans where supported.
This eliminates a lot of boilerplate JNDI lookup code and makes the client application’s dependencies explicit and testable. The ACC processes these annotations during startup, before calling your main() method, so by the time your application logic runs, all injected references are already resolved.
RMI-IIOP: The Communication Protocol
Remote Method Invocation over the Internet Inter-ORB Protocol — RMI-IIOP — is the wire protocol the ACC uses to communicate with remote EJBs. It’s an adaptation of standard Java RMI that runs over CORBA’s IIOP transport, which was designed specifically for interoperability across heterogeneous platforms and languages.
For most Java-to-Java enterprise communication, RMI-IIOP is transparent — you write your remote interface, the ACC marshals the parameters, sends the call over the wire, and delivers the result back deserialized. The protocol handles object serialization, error propagation, and the remote reference lifecycle automatically.
JAAS Authentication and Security
Security in the ACC is handled through the Java Authentication and Authorization Service (JAAS). When your client application needs to authenticate, the ACC uses a configured CallbackHandler to collect credentials — typically a username and password — and submits them to the application server’s security realm.
Once authenticated, the client’s security principal is propagated over the IIOP connection to the EJB container. This means your server-side components can enforce role-based access control on EJB methods, and the authorization check happens against the identity established by your ACC client’s JAAS login — not some anonymous caller.
For SSL/TLS transport security, the ACC supports encrypted IIOP connections, ensuring that credentials and application data are protected in transit. In regulated environments like banking and healthcare, this combination of JAAS authentication and encrypted transport is often a hard requirement (Oracle, Java EE 8 Security API Specification).
How the ACC Runtime Actually Works: A Walkthrough
Walking through the ACC lifecycle helps demystify what happens between typing the launch command and your application’s main() method executing.
Step 1 — Packaging
The developer packages the client application into a .jar file containing compiled classes and the application-client.xml descriptor. This .jar is typically bundled as a module inside an Enterprise Archive (.ear) file alongside the EJB and web modules.
Step 2 — Server-Side Deployment
The .ear file is deployed to the application server. The server recognizes the application client module and makes necessary stubs and interface classes available for download. GlassFish, for example, generates client-side stubs during deployment that the ACC needs to communicate with the EJBs.
Step 3 — Client Launch
On the client machine, the developer or end-user launches the application using the ACC launcher provided by the server vendor. With GlassFish, that command looks like this:
appclient -client MyAppClient.jar
Step 4 — Container Bootstrap
The ACC initializes the client-side JVM environment, reads application-client.xml, configures the JNDI InitialContext pointing to the server, and performs dependency injection on the main client class. All of this happens before your code runs.
Step 5 — Authentication
If the application requires authentication, the JAAS CallbackHandler prompts the user for credentials. The ACC submits these to the server and establishes a security context that persists for the lifetime of the client session.
Step 6 — Remote Communication and Response Handling
With the context established, your application calls remote methods on EJB proxies. The ACC serializes the call parameters, transmits them via RMI-IIOP, and deserializes the response back into Java objects. From your code’s perspective, it looks like a local method call — the distribution is handled transparently.
ACC vs. Web Container vs. EJB Container: Clearing Up the Confusion
Since the ACC shares the Jakarta EE platform with web and EJB containers, it’s worth being precise about what each manages and where it runs. Many developers I’ve spoken with conflate the EJB container with the ACC, which causes real confusion when debugging deployment issues.
| Feature | Web Container | EJB Container | Application Client Container |
| Location | Application server | Application server | Client machine |
| Manages | Servlets, JSPs, CDI beans | Session beans, MDBs | Standalone Java apps |
| Protocol | HTTP/HTTPS | RMI-IIOP internally | RMI-IIOP to server |
| DI Support | Yes (CDI, @Inject) | Yes (CDI, @EJB) | Yes (@EJB, @Resource) |
| Security | HTTP sessions, filters | Container-managed, JAAS | JAAS authentication |
| Client Type | Thin (browser) | N/A (server-side) | Fat (standalone JVM) |
The critical distinction: the ACC is the only Jakarta EE container that runs on the client machine. The web and EJB containers are entirely server-side. If you’re troubleshooting a client application that’s failing to look up an EJB, the problem is almost always in the ACC configuration — not in the EJB container itself.
Application Client Container Security: More Than Just a Login Prompt
Security in enterprise Java client applications is more nuanced than most people realize. The ACC’s security model has several layers, and understanding each one helps you configure it correctly rather than fighting mysterious authentication failures.
JAAS-Based Login
The ACC requires a JAAS CallbackHandler class to collect user credentials. This class implements the javax.security.auth.callback. The CallbackHandler interface responds to NameCallback and PasswordCallback requests from the JAAS framework. You specify the handler class in application-client.xml or as a command-line argument to the appclient launcher.
Security Context Propagation
Once the client authenticates, the security principal travels with every outbound RMI-IIOP call. The EJB container on the server side receives this identity and uses it to enforce method-level security annotations like @RolesAllowed and @DenyAll. This is what makes the ACC a genuine enterprise client — authentication isn’t just a local login, it flows end-to-end through the entire call chain.
Transport-Level Encryption
For production deployments in regulated industries, you’ll typically configure IIOP over SSL. The ACC client and application server negotiate TLS, ensuring credentials and business data are encrypted in transit. This is configured through the server’s ORB (Object Request Broker) settings, and the client-side SSL configuration properties passed to the appclient launcher.
The ACC in Modern Architectures: Still Relevant in 2026?
I want to be direct here: for most new greenfield development, you wouldn’t design a system around the Application Client Container. REST APIs, gRPC, and GraphQL have addressed the remote service access problem with lighter tooling and better cloud compatibility. But dismissing the ACC entirely would be a mistake for several reasons.
Where the ACC Still Makes Sense
- Regulated industries: Banking, healthcare, and government systems often have strict security and auditability requirements that JAAS container-managed security satisfies cleanly. Replacing a working ACC-based system with REST just to modernize the tech stack is rarely worth the risk.
- Legacy integration: If your backend is already built around EJBs and JNDI, introducing an ACC-based client is simpler than adding a REST layer in front of every EJB just to support a desktop client.
- Batch processing: Heavy batch jobs that need transactional integrity and direct access to enterprise resources can run as ACC-managed processes, participating in the same transaction and security model as server-side components.
- Containerized deployments: Docker has changed how ACC applications get deployed. A GlassFish appclient environment can be packaged into a container image, allowing ACC-based batch clients to be orchestrated with Kubernetes alongside microservices.
What Has Replaced It for New Development
For new systems, the trend is clear. REST APIs over HTTPS handle authentication via OAuth 2.0 and OpenID Connect, which scale better in cloud environments than JAAS/IIOP. Jakarta REST (formerly JAX-RS) and frameworks like Spring Boot have made the web container the default home for enterprise business logic exposed to clients. The ACC’s niche has narrowed, but it hasn’t disappeared.
According to the 2023 Jakarta EE Developer Survey conducted by the Eclipse Foundation, RMI-IIOP usage has declined significantly in new projects, but a meaningful percentage of surveyed organizations still run application client containers in production environments, primarily in financial services and government sectors (Eclipse Foundation Developer Survey, 2023).
Best Practices for Java EE Client Application Deployment
If you’re working with an ACC-based application — building one, maintaining one, or migrating away from one — these practices will save you real pain:
- Prefer DI over JNDI lookups: Annotation-based injection with @EJB and @Resource is cleaner, easier to test, and eliminates brittle lookup strings scattered through your code.
- Externalize configuration: Put server hostnames, port numbers, and environment-specific settings in environment entries inside application-client.xml rather than hardcoding them in your source.
- Always propagate security: Never bypass JAAS authentication, even in development environments. Testing with production-equivalent security prevents surprises in regulated audits.
- Package carefully: The client .jar needs all required remote interfaces and stubs. Missing a required stub class produces cryptic ClassNotFoundException errors at runtime that look completely unrelated to the actual problem.
- Test with the real launcher: Running your main class directly without the appclient launcher bypasses the ACC’s bootstrap entirely. Always test with the actual launcher to ensure JNDI, DI, and security are all functioning correctly.
Application Client Container and Distributed Systems
In genuinely distributed enterprise systems, the ACC plays an important integration role. Point-of-sale terminals at retail locations can run ACC-managed clients that communicate with a central inventory management EJB backend. Internal financial reporting tools can use ACC fat clients to pull aggregated data from stateless session beans. Systems that use JMS for asynchronous messaging can consume queues from ACC-managed processes.
The defining characteristic of the ACC in distributed systems is that it makes the client-server boundary logical rather than technical. An ACC-based fat client participates in the same enterprise transaction and security model as server-side EJBs — the runtime manages the distribution transparently. This is a fundamentally different model from a client that manually manages REST connections and handles token refresh and retry logic itself.
Wrapping Up
The Application Client Container is a mature, well-specified piece of the Jakarta EE platform that deserves more attention than it typically receives in modern Java education. Whether you’re building a new internal enterprise tool that needs direct EJB access, maintaining a legacy system that runs ACC-based clients, or simply trying to understand the full picture of what Jakarta EE actually provides, knowing how the ACC works — its architecture, its components, and its security model — makes you a more effective enterprise Java developer.
If you’re working with an existing ACC deployment, my recommendation is to start by thoroughly reading the application-client.xml descriptor and tracing the JNDI references. That single file tells you almost everything about how the client connects to the enterprise backend. If you’re evaluating whether to keep an ACC-based system or migrate to REST, factor in your security requirements and the actual cost of replacing JAAS container-managed security before making that call.
Have a specific ACC configuration challenge you’re working through? Drop your question in the comments, and let’s work through it together.
FAQs
1. Is the Application Client Container still part of the Jakarta EE 10 specification?
Yes, the ACC remains part of the Jakarta EE 10 platform specification. It is an optional profile in some lightweight configurations, but full platform-compliant servers like GlassFish and Payara still implement it.
2. Can I use the Application Client Container without deploying an EAR file?
In most Jakarta EE implementations, the client .jar needs to be deployed through a server to make stubs available; however, some servers allow standalone client .jar launch without a full EAR in development configurations.
3. What happens if JAAS authentication fails in the ACC?
A LoginException is thrown before your main() method is ever called, which blocks all JNDI lookups and EJB calls. The application cannot start effectively until authentication succeeds.
4. Which servers support the Application Client Container besides GlassFish?
Any Jakarta EE full-platform-compliant server supports the ACC, including Payara Server, WildFly (JBoss), IBM OpenLiberty, and Apache TomEE — each provides its own equivalent of the appclient launcher tool.
5. How does RMI-IIOP in the ACC compare to gRPC for remote service access?
RMI-IIOP is mature, tightly integrated with the Jakarta EE security and transaction model, but is heavier and less cloud-friendly; gRPC uses HTTP/2, is language-agnostic, and scales better in containerized microservices environments.
Learn about Platform Event Trap
I’m Sunny Mario, the founder and editor at Wellbeing Junctions. With a passion for thoughtful writing and research-based content, I share ideas and insights that inspire curiosity, growth, and a positive outlook on life. Each piece is crafted to inform, uplift, and earn the trust of readers through honesty and quality.