OpenSubsystems

Business Components for Java Applications

Open Core

Quick Start

Documentation
Last modified

$Author: bastafidli $
$Date: 2006/11/07 06:38:11 $
$Revision: 1.9 $
$RCSfile: quickstart.html,v $

Open Core aims to make the development of subsystems and applications faster and smoother. There are many features, which the developer can take advantage of and this document provides a brief summary of the most important ones. Architecture document and Open Core tutorial discuss details of many of the features mentioned here.

How do I start with Open Core?

Prepare the directory structure for your project. We recommend using the following directory structure, which will make your development with Open Core easier:

  • [Your Project Name]
    • external - in subdirectories of this directory you will place any downloaded libraries
    • sources - in subdirectories of this directory you will place any files you develop
      • build - here you will place any files needed to build your project, such as Ant scripts, build property files, etc.
      • code - in subdirectories of this directory you will place any files you have to "code"
        • java - below here you will create your package structure, such as net.sourceforge.[your project] and place there your .java files. For multitiered applications we recommend subpackages data, persist, logic, www
        • shell - here you will place any shell scripts, such as .bat, .cmd, .sh files you will develop
        • webui - below here you will put any files required to generate your web user interface, the directory structure will match the URLs of your web applications
          • [Your subsystem name] - this directory represents subsystem of your application to support modular design
            • css - place here your stylesheets
            • js - place here your JavaScript files
            • jsp - place here your JSP files
      • config - here you will put any configuration files for your application
      • docs - below here you will put your documentation
      • resources - into this directory you will put any non-textual files, such as images, spreadsheets, UML models, etc.
      • tests - subdirectories of this directory should mirror the subdirectories of your code directory and they will contain your JUnit tests, gui mockups and tests, etc.

Download the Open Core binary package and extract it to the [Your Project Name]\external\core directory. Find file template-build.xml and copy this file and all the property files from the same directory to your build directory. Adjust the settings in the property files to match your directory location and preferences. Rename the template build file to build-[your project name].xml. Open the build file and customize the preparelibs and if you have not followed the recommended directory structure above also the preparesouce targets for your project. The common build files supplied with Open Core will take care of the rest, compiling your source files, generating EJB if you desire so, precompiling your web pages, generating the documentation, packaging your application and creating the distribution packages.

How do I create an application or a subsystem?

Assuming you are developing web application or subsystem with web user interface persisting its data into a relational database you need to create one (or more) servlet, controller, database factory and database schema as well as some web pages representing your user interface. If you are developing desktop application or subsystem, instead of servlet you will create thick client and one or more modules. If your application stores data in files instead of relational database you will create data factory instead of database factory and database schema. For all of these, Open Core provides various base classes that make your life easier. You will use regular web.xml View source to integrate your web application components together. You will create configuration file similar to the default oss.properties View source to configure all components the way you want them to behave.

How do I create web user interface?

You can use any template engine or framework you prefer assuming it can integrate with stadard Java based web application. Open Core uses by default JSP pages together with Tiles template engine. Open Core provides several templates, which can be used to contruct web pages with great simplicity by just specifying the template to use and providing the values for the tokens defined by the template. This overview provides all the necessary details with source code and demos.

What should the servlet do?

In general, the servlet executes an action requested by a user from a browser. It determines what action to execute preferably in a redefined getFormToProcess method. Once the action was identified, it parses the request and retrieves the data to process and calls a controller to execute the action with the specified data. Optionally it manages transactions in scope of which is the action executed.

What should the thick client do?

The thick client initializes the subsystems it integrates and constructs the user interface. The thick client usually consists of one or more modules. Each module may construct its own user interface that displays data to the user, accepts user's input and executes requested actions. The thick client or modules use controllers to execute the requested action with the specified data. Optionally they manage transactions in scope of which the action is executed.

How are the transactions managed?

Developer should manually specify the transaction boundaries by requesting the transaction object and then start and commit or rollback the transaction. This pattern and interface is specified by JTA specification. The transaction is requested from DatabaseTransactionFactoryImpl object.

   UserTransaction transaction = null;
               
   try
   {
      transaction = DatabaseTransactionFactoryImpl.getInstance().requestTransaction();
      transaction.begin();

      // TODO: Implement here your functionality that initializes bSuccess flag
      // and executes the action (usually by calling controller) that needs
      // to be performed within transaction

      if (bSuccess)
      {
         transaction.commit();
      }
      else
      {
         transaction.rollback();
      }
   }
   catch (Throwable thr)
   {
      if (transaction != null)
      {
         transaction.rollback();
      }
      throw thr;
   }
               

The other option is to specify transaction attributes on controller methods using XDoclet tags. These transaction attributes will be taken into account only if your application or subsystem is running inside of supported J2EE application server and only if you have configured your application to create and treat the controllers as EJBs instead of POJOs. In this case the transactional behavior is specified by an EJB specification.

   /**
    * {@inheritDoc}
    * 
    * @ejb.interface-method
    * @ejb.transaction type="Required"
    */
   public DataObject create(
      DataObject data
   ) throws OSSException
   {
      User createddata = null;
      
      // TODO: Implement here functionality that creates the data
      // Since we are modifying data we specified transaction type Required
      
      return createddata
   }               

   /**
    * {@inheritDoc}
    * 
    * @ejb.interface-method
    * @ejb.transaction type="Supports"
    */
   public DataObject get(
      int iId
   ) throws OSSException
   {
      DataObject data   = null;
      
      // TODO: Implement here functionality that retrieves the data
      // Since we are just reading data we specified transaction type Supports
      
      return data;
   }
               

Open Core supports several different transaction factories. The one specified in the configuration file View source will be used to manage transactions. If no transaction factory is specified a default one will be used. When running inside of J2EE application server, the default transaction manager is the one provided by the application server. If running using JRE or JDK only, the default transaction manager is SimpleLocalTransactionFactoryImpl.

How is the controller constructed and accessed?

Servlet, thick client, module or another controller request access to a controller from ControllerManager by specifying interface of the controller they want to access. ControllerManager is the only object that should construct controllers. What implementation should controller manager costruct can be specified in the configuration file View source . If no explicit class is specified the controller manager attempts to create a default one.

   RouteCalculationController controller;
      
   controller = (RouteCalculationController)ControllerManager.getInstance(
                                               RouteCalculationController.class);
               

Open Core supports multiple different controller managers. The one specified in the configuration file View source will be used to create controllers. If no controller manager is specified a default one will be used. When running inside of supported J2EE application server, the default controller manager creates controllers as stateless session EJBs. If running using JRE or JDK only, the default controller manager creates controllers as POJOs.

What should the controller do?

Controller is defined by its interface. The interface should specify methods that describe the business services the controller provides without revealing how are they actually implemented.

   public interface RouteCalculationController extends ModifiableDataController
   {
      Route calculateRoute(Location start, Location end);
   }
               

Controller is the place to implement the business logic for your application or subsystem. Here you process data in some way specific to your application, for example in trip planning application controller would be the place to implement or invoke algorithm that computes route from point A to point B. Controller should delegate all data access and modifications of the data in a persistence store to data factories or other controllers, which can be initialized in the constructor method.

How is the data factory constructed and accessed?

Controller requests access to a data factory from DataFactoryManager by specifying interface of the data factory it wants to access. DataFactoryManager is the only object that should construct data factories. What implementation should data factory manager costructs can be specified in the configuration file View source. If no explicit class is specified the data factory manager attempts to create a default one.

   RouteFactory factory;            
               
   routeFactory = (RouteFactory)DataFactoryManager.getInstance(RouteFactory.class);
               

The default strategy Open Core uses is to persist data into relational database accessed using JDBC. Open Core allows you to specify your own data factory manager that can decide to use different default persistence strategy, e.g. accessing the relational database using Hibernate or saving data into flat files.

What should the data factory do?

Data factory is defined by its interface. The interface should specify methods that describe the data access and modification operation the data factory provides without revealing how are they actually implemented or what persistence mechanism is used.

   public interface RouteFactory extends ModifiableDataFactory,
   {
      Route get(String strRouteName);
      
      Route save(Route modifiedRoute);
   }
               

Data factory is the place to implement access to the persistence store of your choice. Open Core's default persistence mechanism is relational database accessed using JDBC. Following this pattern the database factory implementation should contain all data access and modification logic that is independent from the actual relational database used. The database dependent logic should be delegated to a database schema. Open Core provides DatabaseOperation derived classes to make the access to database easier.

   public Set getRoutesFrom(
      final Location start
   ) throws OSSException
   {
      DatabaseReadOperation dbop = new DatabaseReadMultipleOperation(
         this, m_schema.getSelectRoutesStartingWith(}))
      {
         protected Object performOperation(
            DatabaseFactoryImpl dbfactory,
            Connection          cntConnection,
            PreparedStatement   pstmQuery
         ) throws OSSException,
                  SQLException
         {
            pstmQuery.setString(1, start.getName);
            pstmQuery.setInt(2, CallContext.getInstance().getCurrentDomainId());
            return DatabaseUtils.loadMultipleDataToSet(dbfactory, pstmQuery, true);
         }         
      };
      return (Set)dbop.executeRead();
   }
               

How are the database connection managed?

Database factory can request database connection from the DatabaseConnectionFactoryImpl and return the connection once it no longer needs it. Any connections obtained using this method are automatically associated with the current transaction, if it was started as described earlier.

   Connection cntConnection = null;

   try
   {
      cntConnection = DatabaseConnectionFactoryImpl.getInstance().requestConnection(bAutoCommit);
      
      // TODO: Implement here database access using the connection above
   }
   finally
   {
      DatabaseConnectionFactoryImpl.getInstance().returnConnection(cntConnection);
   }
               

Rather then requesting connection directly we suggest to implement the database access code using one of the DatabaseOperation derived classes as demonstrated above. All the database access code can be then placed into one of the performOperation methods that will receive initialized connection. This connection will be also automatically returned to the pool once the operation is completed (and therefore minimize risk of resource leaks).

How is the database schema constructed and accessed?

Database factory requests access to a database schema from the DatabaseSchemaManager by specifying the generic database schema implementation class it wants to access. DatabaseSchemaManager is the only object that should construct database schemas. What implementation should database schema manager costructs can be specified in the configuration file View source . If no explicit class is specified the database schema manager attempts to create a database schema suitable for the currently used supported database, e.g. if the application or subsystem is accessing MySQL database, the database schema manager will attempt to construct database schema implementing functionality specific to MySQL. If no such class exists because your application or subsystem doesn't require any MySQL specific functionality the database schema manager will construct the generic database schema class for your subsystem.

   RouteDatabaseSchema schema;
      
   schema = ((RouteDatabaseSchema)DatabaseSchemaManager.getInstance(RouteDatabaseSchema.class));
               

Open Core allows you to specify your own database schema manager, which can decide to use different creation strategy.

What should the database schema do?

Database schema allows you to separate tasks related to database management from your application's or subsystem's data access logic. It also allows you to write data access logic that is specific or that utilizes built-in functionality of some particular DBMS. Database schema also specifies dependencies on database objects of related subsystems to ensure that everything is initialized in proper order. This is the place where you would code creation of database tables and indexes. Here you would place queries, which utilize some specific tricks to ensure better performance on some specific DBMS, such as Oracle hints.

How do I put an application together?

Open Core utilizes standard web.xml View source file to configure and construct your web application. There is no need to learn yet another configuration file format. In the web.xml you would specify what database schemas your application requires and what web modules it consists of. This is also the place where you configure the servlets and custom tag libraries used by your web user interface. Of course, if you are creating desktop application, you do not need the web.xml file and the application is created by instantiation of individual classes at appropriate locations within your ThickClient derived classes.

Next: Tutorial