JNDI support for Eclipse Jetty web server including dependency injection, lifecycle management, JNDI resource binding, and database-backed security services
—
Comprehensive JNDI naming and resource binding capabilities supporting environment entries, resources, links, and transactions with full webapp context integration and scope management.
Core abstract base class for all JNDI-related entities with scope management and ENC (Environment Naming Context) binding capabilities.
abstract class NamingEntry {
// Constants
static final String __contextName = "__";
// Protected constructor - use concrete subclasses
protected NamingEntry(Object scope, String jndiName, Object objectToBind) throws NamingException;
// Bind to java:comp/env namespace
void bindToENC(String localName) throws NamingException;
// Unbind from java:comp/env namespace
void unbindENC();
// Complete release and cleanup
void release();
// Query methods
String getJndiName();
String getJndiNameInScope();
String getNamingEntryNameInScope();
}Comprehensive utility class providing static methods for JNDI operations, NamingEntry management, and context manipulation with scope awareness.
class NamingEntryUtil {
// Link name in webapp's java:comp/env to global JNDI name
static boolean bindToENC(Object scope, String asName, String mappedName) throws NamingException;
// Find NamingEntry in specific scope
static NamingEntry lookupNamingEntry(Object scope, String jndiName) throws NamingException;
// Lookup object in scope
static Object lookup(Object scope, String jndiName) throws NamingException;
// Get all NamingEntries of specific type in scope
static <T> List<? extends T> lookupNamingEntries(Object scope, Class<T> clazz) throws NamingException;
// Name creation utilities
static Name makeNamingEntryName(NameParser parser, NamingEntry namingEntry) throws NamingException;
static Name makeNamingEntryName(NameParser parser, String jndiName) throws NamingException;
// Scope management
static Name getNameForScope(Object scope);
static Context getContextForScope(Object scope) throws NamingException;
static void destroyContextForScope(Object scope) throws NamingException;
}Usage Example:
// Bind a local ENC name to a global JNDI name
boolean bound = NamingEntryUtil.bindToENC(webappContext, "jdbc/LocalDB", "java:/comp/env/jdbc/GlobalDB");
// Lookup resources by type
List<? extends Resource> resources = NamingEntryUtil.lookupNamingEntries(webappContext, Resource.class);
// Get context for scope operations
Context scopeContext = NamingEntryUtil.getContextForScope(webappContext);Environment entries for binding configuration values and simple objects to JNDI with web.xml override capabilities.
class EnvEntry extends NamingEntry {
// Constructors with scope
EnvEntry(Object scope, String jndiName, Object objToBind, boolean overrideWebXml) throws NamingException;
// Global constructors
EnvEntry(String jndiName, Object objToBind, boolean overrideWebXml) throws NamingException;
EnvEntry(String jndiName, Object objToBind) throws NamingException;
// Check if this entry overrides web.xml settings
boolean isOverrideWebXml();
}Usage Example:
// Create environment entries with different scopes
EnvEntry maxConnections = new EnvEntry(webapp, "maxConnections", 100, true);
EnvEntry debugMode = new EnvEntry("debugMode", false);
// Environment entry automatically available in JNDI
InitialContext ctx = new InitialContext();
Integer maxConn = (Integer) ctx.lookup("java:comp/env/maxConnections");
Boolean debug = (Boolean) ctx.lookup("java:comp/env/debugMode");Resource binding for complex objects like DataSources, JMS resources, and other enterprise resources with automatic JNDI registration.
class Resource extends NamingEntry {
// Scoped resource binding
Resource(Object scope, String jndiName, Object objToBind) throws NamingException;
// Global resource binding
Resource(String jndiName, Object objToBind) throws NamingException;
}Usage Example:
// Bind various types of resources
DataSource dataSource = createDataSource();
Resource dsResource = new Resource(webapp, "jdbc/MyDB", dataSource);
ConnectionFactory jmsFactory = createJMSConnectionFactory();
Resource jmsResource = new Resource("jms/MyConnectionFactory", jmsFactory);
// Resources automatically available via JNDI lookup
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MyDB");
ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:comp/env/jms/MyConnectionFactory");Create links between JNDI names for aliasing and indirection, supporting complex naming hierarchies and resource sharing patterns.
class Link extends NamingEntry {
// Scoped link creation
Link(Object scope, String jndiName, String link) throws NamingException;
// Global link creation
Link(String jndiName, String link) throws NamingException;
// Get target link destination
String getLink();
// Override - Links cannot be bound to ENC directly
void bindToENC(String localName) throws NamingException; // Throws UnsupportedOperationException
}Usage Example:
// Create links for resource aliasing
Link dbLink = new Link(webapp, "jdbc/PrimaryDB", "jdbc/ProductionDatabase");
Link testDbLink = new Link("jdbc/TestDB", "jdbc/DevelopmentDatabase");
// Links provide indirection
InitialContext ctx = new InitialContext();
DataSource primary = (DataSource) ctx.lookup("java:comp/env/jdbc/PrimaryDB");
// Actually resolves to jdbc/ProductionDatabaseJTA UserTransaction implementation with ENC binding support for transaction management in enterprise applications.
class Transaction extends NamingEntry {
// Constants
static final String USER_TRANSACTION = "UserTransaction";
// Protected constructor for direct use
protected Transaction(String scope, Object entry) throws NamingException;
// Reference-based constructor
Transaction(String scope, Reference userTransactionRef) throws NamingException;
// Static utility for binding UserTransaction to ENC
static void bindTransactionToENC(String scope) throws NamingException;
// Override to allow additional UserTransaction bindings
void bindToENC(String localName) throws NamingException;
// Custom unbind behavior
void unbindENC();
}Usage Example:
// Bind UserTransaction for webapp
Transaction.bindTransactionToENC(webapp.toString());
// Access transaction in application code
InitialContext ctx = new InitialContext();
UserTransaction utx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
// Use JTA transactions
utx.begin();
try {
// Transactional operations
performDatabaseOperations();
utx.commit();
} catch (Exception e) {
utx.rollback();
throw e;
}Proper cleanup and shutdown support for DataSource resources, especially important for connection pools and embedded databases.
class DataSourceCloser implements Destroyable {
// Basic constructor
DataSourceCloser(DataSource datasource);
// Constructor with shutdown SQL
DataSourceCloser(DataSource datasource, String shutdownSQL);
// Implement Destroyable interface
void destroy();
}Usage Example:
// Set up DataSource with proper cleanup
DataSource dataSource = createAtomikosDataSource();
DataSourceCloser closer = new DataSourceCloser(dataSource, "SHUTDOWN");
// Register for cleanup (typically with webapp lifecycle)
webapp.addBean(closer);
// Automatic cleanup on webapp shutdown
// closer.destroy() will be called, executing shutdown SQL if provided// Set up comprehensive JNDI environment for webapp
WebAppContext webapp = new WebAppContext();
// Database resources
DataSource primaryDB = createPrimaryDataSource();
DataSource replicaDB = createReplicaDataSource();
Resource primary = new Resource(webapp, "jdbc/PrimaryDB", primaryDB);
Resource replica = new Resource(webapp, "jdbc/ReplicaDB", replicaDB);
// Environment configuration
EnvEntry maxConnections = new EnvEntry(webapp, "maxConnections", 50, true);
EnvEntry timeout = new EnvEntry(webapp, "timeout", 30000, false);
// Create convenient aliases
Link mainDB = new Link(webapp, "jdbc/MainDB", "jdbc/PrimaryDB");
Link backupDB = new Link(webapp, "jdbc/BackupDB", "jdbc/ReplicaDB");
// JMS resources
ConnectionFactory jmsFactory = createJMSConnectionFactory();
Resource jms = new Resource(webapp, "jms/ConnectionFactory", jmsFactory);
// Transaction support
Transaction.bindTransactionToENC(webapp.toString());
// Cleanup management
DataSourceCloser primaryCloser = new DataSourceCloser(primaryDB);
DataSourceCloser replicaCloser = new DataSourceCloser(replicaDB, "SHUTDOWN IMMEDIATELY");
webapp.addBean(primaryCloser);
webapp.addBean(replicaCloser);// Discover all resources bound in a webapp context
List<? extends Resource> resources = NamingEntryUtil.lookupNamingEntries(webapp, Resource.class);
List<? extends EnvEntry> envEntries = NamingEntryUtil.lookupNamingEntries(webapp, EnvEntry.class);
List<? extends Link> links = NamingEntryUtil.lookupNamingEntries(webapp, Link.class);
// Process each type of resource
for (Resource resource : resources) {
System.out.println("Resource: " + resource.getJndiName());
Object boundObject = NamingEntryUtil.lookup(webapp, resource.getJndiName());
System.out.println("Type: " + boundObject.getClass());
}
for (EnvEntry entry : envEntries) {
System.out.println("EnvEntry: " + entry.getJndiName() +
" (overrides web.xml: " + entry.isOverrideWebXml() + ")");
}
for (Link link : links) {
System.out.println("Link: " + link.getJndiName() + " -> " + link.getLink());
}// Different scoping strategies for resources
// 1. Global scope resources (available to all webapps)
Resource globalDB = new Resource("jdbc/GlobalDB", globalDataSource);
EnvEntry globalConfig = new EnvEntry("globalSetting", "production");
// 2. Webapp-scoped resources (available only to specific webapp)
Resource webappDB = new Resource(webapp, "jdbc/WebappDB", webappDataSource);
EnvEntry webappConfig = new EnvEntry(webapp, "webappSetting", "enabled", true);
// 3. Context management
Context globalContext = NamingEntryUtil.getContextForScope(null);
Context webappContext = NamingEntryUtil.getContextForScope(webapp);
// 4. Cleanup on webapp shutdown
webapp.addEventListener(new LifeCycle.Listener() {
@Override
public void lifeCycleStopping(LifeCycle event) {
try {
NamingEntryUtil.destroyContextForScope(webapp);
} catch (NamingException e) {
LOG.warn("Error destroying JNDI context", e);
}
}
});try {
// Resource binding with error handling
Resource resource = new Resource(webapp, "jdbc/MyDB", dataSource);
// Verify binding worked
Object lookup = NamingEntryUtil.lookup(webapp, "jdbc/MyDB");
if (lookup == null) {
throw new IllegalStateException("Resource binding failed");
}
} catch (NamingException e) {
LOG.error("JNDI binding failed for jdbc/MyDB", e);
// Fallback strategy or re-throw
}// Proper resource lifecycle with cleanup
DataSource dataSource = null;
Resource resource = null;
try {
dataSource = createDataSource();
resource = new Resource(webapp, "jdbc/MyDB", dataSource);
// Use resource...
} finally {
// Cleanup in reverse order
if (resource != null) {
try {
resource.release();
} catch (Exception e) {
LOG.warn("Error releasing JNDI resource", e);
}
}
if (dataSource instanceof Closeable) {
try {
((Closeable) dataSource).close();
} catch (Exception e) {
LOG.warn("Error closing DataSource", e);
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-eclipse-jetty--jetty-plus