BC4J and Distributed deployment (in particular of JHeadstart Applications)

3

Thusfar we have been lucky – or careless – to not have had to consider distributed application deployment. However, web-applications running in the DMZ accessed by internet users directly through HTTP (no SSL/HTTPS), as we encounter more and more often at our projects (as opposed to ‘intranet style applications’ within the firewall) are typically not encourages (!) to directly access backoffice databases or other resources. We will face an increasing requirement to implement a Web-tier in an application server in the DMZ that access an application server within the (second) fire-wall; the latter may access the database and other enterprise resources.

Fortunately, applications developed using BC4J – including those built with JHeadstart – are in theory easy to ‘distribute’: the application (web-tier) interfaces with the model. The model’s business services are wrappers around BC4J Business Objects (Application Modules and View Objects). BC4J can be deployed in several modes, one of which is EJB Session Bean (remote web-tier). In that deployment model, the Model wrappers that are accessed by the web-tier application communicate with the Application Module Client (ApplicationModuleHome) to get hold of an Application Module instance. From there on, accessing the ViewObjects is no different from accessing VOs in local-mode.

// Setup JNDI environment for looking up
// the appmodule
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,JboContext.JBO_CONTEXT_FACTORY);
env.put(JboContext.DEPLOY_PLATFORM, JboContext.PLATFORM_EJB_IAS);
env.put(JboContext.HOST_NAME, applicationServerHost);
env.put(JboContext.SECURITY_PRINCIPAL, iasUserName);
env.put(JboContext.SECURITY_CREDENTIALS, iasUserPasswd);
env.put(JboContext.APPLICATION_PATH, applicationName);
Context ctx = new InitialContext(env);

// Lookup appmodule home
ApplicationModuleHome amHome = (ApplicationModuleHome)ctx.lookup(amDefName);
// Create an appmodule instance
am = amHome.create();
// Connect to the database using the datasource
am.getTransaction().connectToDataSource(null, dataSourceName, false);

It is important that the local (client) code accessing the Bc4j objects only call on interfaces, rather than the classes that implement them. Thus your code can stay tier-independent.

JHeadstart provides the wrappers to the BC4J objects through the JhsApplicationModuleImpl and DataObjectHandlerImpl. In addition there is the code that deals with Connection (ApplicationModule) pooling and hands out ApplicationModule instances. It seems that we must ensure that these classes:
oracle.jheadstart.model.bc4j.DataObjectHandlerImpl, oracle.jheadstart.model.bc4j.DataObjectImpl oracle.jheadstart.model.bc4j.ApplicationModuleProvider only access BC4J (Jbo) interfaces (not classes). In addition, class ApplicationModuleProvider must contain code, similar to the code above, to retrieve local instances for remote Application Modules – or can that be setup through the BC4J Configuration?

A check to see whether the JHeadstart code lives up to these requirements: no jbo-(server) classes may be imported, only jbo-interfaces. Where it does not, it will have to be modified. From a post on OTN:

Steven: In the current JHeadstart version, there is one place where we are using a BC4J implementation class instead of the corresponding interface class, because we need access to a method not available through the interface. This might cause you problems when deploying as a session bean.

From the JHeadstart Developer’s Guide (2-66):

Implementation of DataObjectHandler Interface
The DataObjectHandler interface is implemented by class oracle.jheadstart.model.bc4j.handler.DataObjectHandlerImpl. If you look at the source code of this class, you will notice that the implementation of most methods is delegated to oracle.jheadstart.model.bc4j.JhsApplicationModuleImpl. The communication between these two classes is handled through interface oracle.jheadstart.model.bc4j.JhsApplicationModule.

You might wonder why we have chosen this implementation. Why not simply put all logic directly in DataObjectHandlerImpl? The reason is related to flexibility of deployment. BC4J allows you to deploy application modules as an EJB Session Bean. A reason to choose this deployment option is when you have distributed requirements where the business logic layer might be located on a remote server. Now, if we would have put all logic in the DataObjectHandlerImpl class, we would have generated many more remote method calls. By delegating it to JhsApplicationModuleImpl, the BC4Jspecific method calls are all executed on the remote server, and only the result is sent back over the network.

To be able to deploy a BC4J Application Module as an EJB Session Bean, without changing the code that accesses the application module and its view objects from outside objects, you need to stick to two rules:
• You should only code against the BC4J interfaces, located in the oracle.jbo package
• Method arguments and return types must be serializable
The first rule is the reason we have introduced the JhsApplicationModule interface. The second rule is the reason why some of the handler methods use a collection implementation class like HashMap, rather than a collection interface like Map which is not serializable. Now, if you feel a bit lost here because you are not familiar with EJB’s or the serializable interface, don’t worry.

Useful Resources

Post on OTN Forum with example code and basic instructions for getting distrib uted BC4J up an running. From this post, it really seems very doable!!

Simplifying J2EE and EJB Development with BC4J, Steve Muench (2002) – article on the ways in which BC4J implements various J2EE Design Patterns. This paper also discusses deployment as EJB Session Bean; specifically: What Kinds of EJB Session Beans Can You Build with BC4J?. Of interest to us:

An enhanced EJB Session Bean called an “AppModule Session Bean” that provides full remote access to the BC4J design pattern components and features, including the implementation of a clever “Value Messenger” pattern that considerably reduces typical EJB client network traffic.

From the JDeveloper 10g On Line Help:
About the Multi-Tiered Business Components Architecture Maintaining Tier Independence:

The business components framework is organized around interfaces in the oracle.jbo package, such as oracle.jbo.ApplicationModule, oracle.jbo.ViewObject, and oracle.jbo.Row. By coding your client to these interfaces, rather than the classes that implement them, your code can stay tier-independent. If, for example, you choose to deploy your business components as an EJB, you can use the same client code you used for testing when your business components were deployed locally, because the interfaces are always accessible in the client tier. The business components framework handles all issues of cross-tier communication for you.

The interfaces in oracle.jbo are implemented by classes in the package oracle.jbo.server. For example, oracle.jbo.ApplicationModule is implemented by oracle.jbo.server.ApplicationModuleImpl. You should not directly call methods on these implementation classes, because if you deploy remotely, these classes will not be available on the client tier. Invoking the classes would prevent you from ever deploying your application remotely. Instead, you should call methods on the interfaces.

Similarly, when you create your own application module and view object classes, you should not call methods on their implementation classes. Instead, you should export methods to create custom interfaces that contain them. These interfaces extend oracle.jbo.ApplicationModule or oracle.jbo.ViewObject and are also always accessible in the client tier. When you downcast a business component, always downcast to your interface, never to your implementation class.

About ADF Business Components Deployment

When business components are deployed as an EJB session bean, the business components run in a separate tier (middle-tier) from the client programs. For example, the EJB session bean runs on an EJB server such as Oracle Application Server.

At deployment time, the application module must be enabled for client data binding. In JDeveloper, you can make the application module available to the client (remoteable) when creating a deployment profile with the Create Business Components EJB Deployment Profile Wizard, Step 2 of 2: AppModules . Making the application module remoteable means creating an EJB remote interface and/or client-side proxies for application module methods which must be deployed to the client platform

Sample Client Code for an EJB Client Deployed to OC4J

Rather than using the Business Components Browser, you can also choose to test your Business Components project with the following two client code samples for connecting to an AppModule deployed as an EJB session bean to an OC4J instance:

About Developing Applications Using BC4J Entity Facades

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

3 Comments

  1. We are planning to develop a web application using ADF/JSF, EJB3.0, JPA, TopLink, Oracle AS using JDeveloper 10g. I am new to these tools and technologies. How to develop end-to-end application? What are the patterns required. HOw will be the architecture.

  2. Hi Steve,

    public class JhsApplicationModuleImpl extends ApplicationModuleImpl
      implements JhsApplicationModule, MessageConstants
    

    Is there concrete experience, a roadmap, guidelines etc. for morphing a local deployment based app into a distributed deployed one? I gather that most of our work will have to be done in the JHeadstart classes… Unfortunately we cannot move to ADF at this point.