August 30, 2019
For the most part, customers aren't concerned with the backend deployment as long as it's performant and secure. That's a premise of today's cloud-enabled systems. The location and infrastructure is hidden from the calling clients. And being able to service customers on shared infrastructure -- and shared deployments -- helps businesses scale. However, sometimes a customer will want to deploy your code on their infrastructure. In that case, you need to structure your deployment to cordon off any customer-specific integrations so that you can ship a vendor-neutral product.
This article shows how to use JNDI to discover services in the WildFly app server. The following SysML Block Definition Diagram shows the demo project.
Three artifacts are deployed in the WildFly app server: bekwam-web-services, vendor-specific-ejbs, vendor-specific-artifact. bekwam-web-services is the core application that is hosted on shared infrastructure and can be safely delivered to customers. It is stripped of any customer-specific code. vendor-specific-ejbs contains vendor-specific code, say a web service client. If a customer would like to deploy the core app on their infrastructure, vendor-specific-ejbs is not delivered. vendor-specific-artifact is unintegrated web content deployed alongside -ejbs for convenience.
vendor-specific-artifact can contain a custom form or static HTML like customer-specific terms and conditions wording.
This SysML Sequence Diagram further explains the demo project. bekwam-web-services receives an API request from an external caller. It then uses the snippet of JNDI code presented later to determine whether or not a vendor-specific deployment exists. If it does, then the core product will post a JMS message a special queue. vendor-specific-ejbs has a Message Driven Bean that will listen to the vendor queue.
JNDI is the Java Naming and Directory Interface that supports CDI in today's JavaEE app. These days, JNDI is hidden from the EJB developer through the use of annotations and an internal app server convention. In the distant past, you'd need a JNDI lookup to wire up business logic. These days, you just use an @EJB annotation.
This diagram shows JNDI items in the WildFly app server. For this article, the deployments of interested are listed in the java:global
tree. My vendor-specific-ejbs is cross-displayed under java:jboss/exported since it has a remoted EJB. (That's not important for the proposed JMS solution.) My core product "bekwam-web-services" isn't displayed under Applications because it's an exploded configuration in my IDE and not a WAR.
In WildFly, JNDI contains the deployed artifacts and we can make a JNDI call from within the core product to get a list of these applications. The following JAX-RS web service makes such a call. An Enumeration (w00t! w00t! Java 1.0) is returned and the core product can use a naming convention to determine the items of interest.
@Path("/test-jndi")
@Produces(MediaType.APPLICATION_JSON)
public class JNDITestResource {
private Logger logger = LoggerFactory.getLogger(JNDITestResource.class);
@GET
public List<String> getApps() {
List<String> retval = new ArrayList<>();
try {
InitialContext initialContext = new InitialContext();
NamingEnumeration<NameClassPair> jndiItems = initialContext.list("java:global");
while( jndiItems.hasMore() ) {
NameClassPair pair = jndiItems.next();
retval.add( pair.getName() );
}
} catch(Exception exc) {
logger.error("error calling jndi", exc);
}
return retval;
}
}
The JMS code isn't presented here, but it enqueues a message based on this beforehand check of apps.
This post showed how a simple JNDI call can get a list of the apps deployed to the WildFlyAS. It doesn't give any special insight into the state of a deployed app, but the JMS configuration will sit on messages for an indefinite amount of time if the target app (vendor-specific-ejbs) is brought down during processing. When the app starts up, messages wil be delivered to the EJB.
By Carl Walker
President and Principal Consultant of Bekwam, Inc