Project

General

Profile

Primary Features and Benefits

The xweld-core module builds on the Spring Framework and provides the foundational classes and building blocks for the rest of the <xweld/> modules. The core library supports:

  • XML messaging integration from disparate data sources
  • A auditable persistence framework based on JPA and Hibernate as well as bulk data loading into distributed data grids from JDBC
  • Component configuration using JPA secured, audited entities based on Spring Profiles and Environments. This eliminates external files typically used for configuration that can compromise security
  • APIs for pluggable grid-cache computing using map/reduce or the executor abstraction (other projects support Coherenece/Infinispan/Hadoop)
  • JVM wide atomic value management and reference data resolution
  • Object and field level validation framework
  • A Cipher manager for encrypting and decripting Strings using JCA

Key Concepts

One of the fundamental requirements of most enterprise applications in general, and financial applications in particular is that application configurations be located in a robust and secure location. Further, when configurations are modified over their lifetime, change logs and audit tails must be maintained to track who changed what and when they changed it. For this reason, <xweld/> applications keep configurations inside an auditable JPA persistent store.

Spring Profiles and Environemnts provide a mechanism to define various runtime deployment contexts, like "production", "development" and "testing" and using active profiles, dymaically switch between them at run time. This ability means that you can put all the deployment configuraitons in one place and then configure each instance to use one or ther other. <xweld/> builds on this functionality and supports storing the profiles in a secure, auditable JPA-backed persistence mechanism.

Since the profiles and their associated properties are resident in the JPA data store so an application can use them, the properties and settings for each environment must first be populated in the database before an applicaiton is started. It's the same way with any Spring based application, but rather than configuring each envinment in XML, the configuraiton is stored using JPA as part of an installation, or setup process. In order to facilitate installing a deployment, xweld provides a SetupTool for maintaining JPA based environments.

Each xweld application consists of at least three things:

  • A Spring configuration file such as META-INF/beans.xml
  • Auditable JPA resident profiles and properties
  • An setup process called by the setup tool that install all the environemtns, settings and properties reuiqed by each deployment of an application

Deploying an application means:

  • run the setup tool for your application
  • deploy the application to each configured environment and set the property -Dspring.profiles.active=XXX, where XXX is one of the environments your setup tool installed into the database

Packages and Classes

xweld-core includes the following packages:

  • com.xweld – miscellaneous constants classes and interfaces used across the framework
  • com.xweld.persistence – persistence classes, bulk loading, auditing and related interfaces
  • com.xweld.observer – the classic observer pattern implemented for JPA objects
  • com.xweld.configuration – configuration classes and interfaces for storing Spring Profiles in a JPA database
  • com.xweld.cache – the API and default implementation for local and distributed caching
  • com.xweld.conversion – conversion classes and interfaces
  • com.xweld.event – foundational event model used as abasis for the Trade lifecycle event model
  • com.xweld.grid – the API and default implementation for integrated cache and grid computing
  • com.xweld.resolver – the API for grid-friendly resolution of identifiers to heavy-weight entities on the distributed grid-cache
  • com.xweld.inject – factory API to JSR-299 CDI for JSE and JEE applications
  • com.xweld.io – input/output (I/O)
  • com.xweld.cryptography – Java Cryptography Extension utilities
  • com.xweld.jms – JMS queues and messages
  • com.xweld.metadata – metadata properties
  • com.xweld.validation – the validation of entities
  • com.xweld.xml – provides the underlying capabilities for handling all XML within the <xweld/> API
  • com.xweld.utilities – provides supporting methods for reflection, command line parsing, string manipulation, file and thread utilities

Sample Application

Below is an example of how easy it is to start building an application:

// create the Spring application context 
GenericXmlApplicationContext context = new GenericXmlApplicationContext("META-INF/beans.xml");

// the rest of your application code goes here ...

And here is a sample beans.xml file:

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.xweld" />

    <bean name="CommonsConfigurationFactoryBean" 
        class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
        <constructor-arg ref="AuditableConfiguration" />
    </bean>

    <bean name="AuditableConfiguration" class="com.xweld.configuration.AuditableConfiguration">
    </bean>
</beans> 

The CommonsConfigurationFactoryBean is used to redirect environment properies to an auditable configuraiton facility, and the AuditableConfiguration bean does the work of actually storing environment properties in the JPA database. That's how easy it is to get started!

Persistence

com.xweld.persistence

The <xweld/> persistence framework encapsulates the patterns and practices of using JPA/Hibernate persistence inside an application. The package provides an abstraction above the JPA entity manager that is both thread-safe and supports JTA and RESOURCE_LOCAL transaction management in J2SE and J2EE contexts.

com.xweld.persistence class diagram

An instance of an IPersistenceManager is obtained using dependency injection like this:

@Inject
IPersistenceManager pm;

The system property com.xweld.persistence.jta can be set to true or false (the default) to specify that JTA-style transaction management should be used; if false, JPA style is used. An additional property com.xweld.persistence.transactions.force can be set to true (the default) to force the persistence manager to wrap reads, or get operations inside a transaction. If set to false, this behaviour is disabled. This setting is useful in those cases where some JPA data sources require a transaction around reads or selects involving complex objects.

The JPA entity manager is not thread-safe by definition. For this reason, the persistence API supports a thin wrapper around the JPA entity manager that can be used in multi-threaded J2SE or JTA managed environments. You should use one instance of an IPersistenceManager per thread, and call the close method when the thread terminates to correctly release the underlying JPA resources. Within one thread all references to an IPersistenceManager and all calls to getManager() use or return the same underlying JPA EntityManager.

The ITransaction interface wraps the implementation of either a JTA or JPA transaction to hide the differences between these two APIs in the java.persistence API; and unlike JPA, the persistence API provides developers with a single transaction model regardless of the underlying implementation.

The IDataAccessObject interface defines the Data Access or 'DAO' methods available on a persistent object. A DAO is used to separate the business logic of the application from the persistent representation of an object.

The IScrollableResults interface defines the methods available to a cursor over large result sets returned by the IPersistenceManager.

Using the IPersistenceManager API

Given a class Foo defined as:

@Entity
Class Foo 
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long              id;
}

The object may be persisted:

class MyClass
{
  @Inject
  IPersistenceManager p;

  public static main(String [] args)
  {
    Foo foo = new Foo();
    p.begin();
    p.persist(foo);
    p.commit();
  }
}

At run time, the location of the JPA persistence.xml file must be specified. This is accomplished using the property:

-Dcom.xweld.persistence.location=<JPA persistence xml file>

The default value for the property is “persistence.xml” on the classpath.

Enabling JTA Transactions Using IPersistenceManager

JTA is the Java community standard that allows distributed transactions to be performed across multiple XA resources. A regular transaction will only handle one resource. A JTA transaction will coordinate recovery across multiple resources. Three things are needed:

  • A JTA transaction manager needs to be present
  • The resources used by the persistence layers need to be XA resources
  • The PersistenceManager needs to be configured to use JTA

Some web servers come with JTA transaction managers while others do not. WebLogic comes with one while Tomcat does not. With Tomcat, an external JTA transaction manager needs to be added, such as Bitronix. An external JTA transaction manager would also be needed to provide JTA support to Java SE applications that require them. This external JTA transaction manager would need to be added to the application's maven pom file. If this transaction manager properly supports the JTA specification then <xweld/> PersistenceManager will work with it.

IPersistenceManager insulates the programmer from calling the transaction manager directly to begin/end transactions. When in JTA mode, the begin, commit and rollback apply to JTA transactions.

When using JTA the IPersistenceManager’s begin method should only be called at the beginning of the JTA transaction and the commit/rollback method called at the end of the transaction. Begin and commit/rollback should not be called for the individual PersistenceManager instances.

  IPersistenceManager mgr = PersistenceManagerFactory.newInstance().getManager();
  try 
  {
    mgr.begin(); // begins a JTA transaction
    ....
    application code  
    ....
    workflow code
   ....
    mgr.commit(); // commits the JTA transaction, all changes made by       
                  //application code and workflow are saved.
  catch 
  {
    mgr.rollback(); // rolls out the JTA transaction, all changes made by
                    // application code are rolled back.
  }

After configuring the application to use JTA it is important to test it to make sure that the code is really running in a JTA transaction. Something might have been missed in the configuration and the code could actually be running non-JTA. One way to test is to put in some code to generate an error and observe if all the updates from different PersistenceManager instances get rolled back.

XA Support for JTA

The database and JDBC drivers need to provide XA support. This means that they are aware of and will cooperate with a JTA transaction manager. An Oracle database server provides this support out of the box. The driver specified needs to be one that supports XA, such as 'oracle.jdbc.xa.client.OracleXADataSource' instead of 'oracle.jdbc.driver.OracleDriver'. SQL Server does not provide this support out of the box and requires some special setup. Steps required include enabling XA transactions in the MS DTC service. Refer to SQL Server for details.

Configuring the IPersistenceManager to use JTA

Each persistence instance needs to be configured to use JTA. The configuration is different for application code such as jBPM or Activiti workflow, and some research may be necessary to enable JTA in your application. Several examples are discussed below:

First you need to create one JDBC data source and have all persistence layers refer to this. In WebLogic data sources can be set up in the Administration Console. With Bitronix, data sources are defined in the property file pointed to by its 'bitronix.tm.resource.configuration' setting. Other transaction managers may have different ways of defining the data source.

The IPersistenceManager will require JTA mode to be set using the com.xweld.persistence.jta property:

 -Dcom.xweld.persistence.jta=true

When this is set, calling IPersistenceManager to begin, commit or rollback a transaction will cause these commands to apply to a JTA transaction instead of the normal local transactions.

Second, the persistence.xml file must be modified. Transaction-type needs to be set to "JTA" instead of "RESOURCE_LOCAL" and the datasource needs to be included. Example:

<persistence-unit name="com.xweld" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/sqlsrv1</jta-data-source>

Third, the jpa.properties file must be modified to point to the specified datasource. The transaction factory will have to change to point to the JTA transaction factory. Depending on the JTA transaction manager, the transaction manager_lookup_class may also have to change. Here is an example using Tomcat and Bitronix:

hibernate.dialect=org.hibernate.dialect.SQLServerDialect
# Datasource
hibernate.connection.datasource=jdbc/sqlsrv1
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.BTMTransactionManagerLookup
hibernate.current_session_context_class=jta
hibernate.connection.release_mode=after_statement
hibernate.jndi.class=bitronix.tm.jndi.BitronixInitialContextFactory

Audited Entity Support

The IPersistenceManager encapsulates the support for retrieving entity audit information. The audit support provided by the default implementation of IPersistenceManager is based on Hibernate. There are two levels of support. For those projects that don't need user level auditing, the core module provides basic revision and lifecyle management for each annotated entity.. The xweld-security module implements runtime configurable revision and lifecycle auditing that logs the current user as part of the audit log. You can use one or the other but not both in the same project. You can also plug in your own classes if you wish, but the default ones should suffice for most purposes.

To configure your runtime application to use the core auditing support, add the following values to your persistnce.xml file:

  <class>com.xweld.persistence.DefaultRevisionEntity</class>
  <properties>
    <property name="hibernate.ejb.event.post-insert" value="com.xweld.persistence.AuditListener" />
    <property name="hibernate.ejb.event.post-update" value="com.xweld.persistence.AuditListener" />
    <property name="hibernate.ejb.event.post-delete" value="com.xweld.persistence.AuditListener" />
    </properties>

To configure your runtime application to use the user/security module auditing support, add the following values to your command line arguments:

-Dcom.xweld.persistence.revision.type=com.xweld.authorization.UserBasedRevisionEntry
-Dcom.xweld.persistence.lifecycle.type=com.xweld.authorization.UserBasedLifeCycleEntry

The base classes com.xweld.persistence.RevisionEntry and com.xweld.persistence.LifeCycleEntry implement the core audit support, but you are free to extend them and supply your own classes using the above property definitions also.

Bulk Loading From External Data Sources

The persistence package supports the bulk reading of data stored in external data sources such as CSV files or JDBC databases into arbitrary POJOs returned in a scrollable results set. Conversion from the field representation in the external source into the representation required by the fields in the POJO is supported by using an <source>ITransformer</score>, which defines the method's signature used to convert between two types. The ConversionManager implements this interface, so typically that implementation is used, but you're free to define your own transformation mechanism also. There are two data reader implementations provided, one that reads data from any JDBC data source and one that reader from CSV files.

com.xweld.persistence data reader class diagram

Using the framework is easy. The only constraints on your POJO is that it must have a default, no-arg constructor. The configuration for the reader defines a map of fields in the source to fields in the POJO and other data soude specific configuration information. For example suppose you have a POJO called Order, defined as follows:

public class Order
{
  private long   id;
  private String name;
  private long   productId;
  public Order() {}
}

To read Order objects from a JDBC data source here is how you would use the factory:


DataReaderProperties readerProperties = // get the properties from my higher level configuration
// 
// get the reader configured for my POJO 
IDataReader<Order, Long> reader = readerProperties.getReader(Order.class);

// now read pne Order with key 10
reader.connect(ConversionManager.get());
Order result = reader.fetch(10L);

// now read Orders defined by a list of keys 
List<Long> keys = new ArrayList<Long>(); 
keys.add(10L); 
keys.add(15L); 
keys.add(99L);

IScrollableResults<Order> results = reader.fetch(keys);

// read al the Orders
results = reader.fetchAll();

reader.discconect();

// that's it!

So, how do we configure a POJO type and a specific data source? In your setup tool, something like this:

DataReaderProperties configuration = new DataReaderProperties("test");

// associate the JDBC reader with the pojo type, in this case "Order" 

configuration.addAssociation(Order.class, JDBCDataReader.class);

Map<String, String> parameters = new HashMap<String, String>();
parameters.put(JDBCDataReader.JDBC_URL, "jdbc:hsqldb:tmp");
parameters.put(JDBCDataReader.JDBC_DRIVER_NAME, "org.hsqldb.jdbcDriver");
parameters.put(JDBCDataReader.JDBC_USER_NAME, "sa");
parameters.put(JDBCDataReader.JDBC_PASSWORD, "");
parameters.put(JDBCDataReader.JDBC_FETCH,
        "select * from orders where id = @" + JDBCDataReader.JDBC_KEY + "@");

parameters.put(JDBCDataReader.JDBC_FETCH_LIST,
        "select * from orders where id in @" + JDBCDataReader.JDBC_KEY_LIST
            + "@");
parameters.put(JDBCDataReader.JDBC_FETCH_ALL, "select * from orders");

// set the values that map JDBC column names to the fields in our POJO
parameters.put("ID", "id");
parameters.put("NAME", "name");
parameters.put("PRODUCTID", "productId");

configuration.setParameters(Order.class, parameters);

Bulk Writing From External Data Sources Into A Cache

Instances of IDataReaders may be used to load data frome xternal sources into an ICache. This mechnism defines the abstraction that applications typically use when loading data into grid memory.

com.xweld.persistence data writer class diagram

For example suppose you have a POJO called Trade, defined as follows:

public class Trade
{
  private String name;
  private String id;
  private String currency;
  private String payCurrency;
  private double payNotional;
  public Trade()
  {
  }
}

To read Trade objects from a data source and populate the result in an ICache:

DataWriterProperties properties = // get the properties from the higher level configuration
IDataWriter<String, Trade> writer = properties.getWriter(Trade.class);

writer.open(cache, reader);
writer.writeAll();

Domains

Domains are logically related collections of codes, all belonging to the same type. For example, a domain of currencies could be defined as the set USD, CAD, EUR. In this example, each of these is a domain code within the currency domain. The DomainManager is a singleton that manages access to the set of configured domains.

com.xweld.persistence.domain class diagram

A domain is any named set of DomainCodes that logically all belong to the same family or type. A DomainCode is a name, numeric value and a description. The names within a domain must be unique. For example, a domain of “PricingSources” could have values of “Bloomberg”, “Reuters” and “Internal”, each with their own description and numeric code.

Domains are much like enumerations, except that they are initialized from the database at runtime. For example, the PricingSources domain class is defined as:

    @Entity
    public class PricingSources extends Domain
    {
      public PricingSources()
      {
         super();
      }
    }

In our application runtime tool, we can initialize the values of this domain as follows:

  IPersistenceManager p = PersistenceManagerFactory.newInstance().getManager();
  DomainManager d = DomainManager.getInstance();
  PricingSource pricingSources = d.get(PricingSources.class.getSimpleName());

  if (pricingSources == null)
  {
    pricingSources = d.create(PricingSources.class);
    pricingSources.add("Bloomberg", 1, "The Bloomberg Pricing Source");
    pricingSources.add("Reuters", 2, "Reuters Feed");
    pricingSources.add("Internal", 3, "An Internal Pricing Source");
    p.persist(pricingSources);
  } else
  {
    pricingSources.add("Bloomberg", 1, "The Bloomberg Pricing Source");
    pricingSources.add("Reuters", 2, "Reuters Feed");
    pricingSources.add("Internal", 3, "An Internal Pricing Source");
    p.merge(pricingSources);
  }

To use the domain, we can now access it by name using the name of the domain, in this case “PricingSources”. The Domain base class has methods to get all the named values in a domain and the integer codes.

Observers and Observable JPA Objects

com.xweld.observable

The observable package provides an implementation of the classic 'Observer' design pattern for JPA based entities.

com.xweld.observer class diagram

After each Observable entity is updated, all Observers of that entity are notified using the IObserver update method. The Observer is notified of the type of update by the UpdateType parameter. The Observable object that was updated is also passed to the Observer. Classes that extend Observable that also override the protected methods postUpdate, postPersist and postRemove methods must call the super class implementation to ensure updates are properly propagated to all Observers.

Cache and Grid API

com.xweld.cache
com.xweld.grid
com.xweld.resolver

The cache and grid packages define a set of interfaces for distributed caching and grid computing. By coding to these interfaces, providers of grid-cache technology, such as Infinispan, Hazelcast, Hadoop, and Coherence can be implemented behind this API to make the grid-cache provider run time configurable. A default implementation is provided for testing and development purposes based on thread-safe maps and a java.concurrent ExecutorService. Other maven projects xweld-gridache-coherence and xweld-gridcache-infinispan, support Coherence and Infinispan respectively using the same abstraction model.

com.xweld.cache class diagram

IExecutorService is an simple extension of a familiar ExecutorService from the java.util.concurrent package. The API may be implemented by a simple thread pool (the default) or a fully clustered distributed grid. The grid model defined here marries a distributed cache with concurrent tasks, which supports accessing a common pool of memory between parallel callable tasks.

Implementations of IExecutorService are created by the ExecutorServiceFactory. The specific implementation returned from the factory may be controlled at runtime by setting the system property "com.xweld.grid.executor.service" to have a value of the implementing class canonical name.

The API allows a quick and simple implementation of tasks that take input from cache nodes, execute certain computations and return results to the caller. Users may specify which keys to use as input for specified ICallable and submit that callable for execution on the IExecutorService. An implementation runtime would locate the appropriate keys, migrate the callable to a target execution node(s) and finally return a list of results for each executed ICallable. Of course, users can omit specifying input keys in which case the IExecutorService would execute the callable on all keys for a specified cache.

The ICallable interface defines a task that can be executed on a local multi-threaded environment or in a cluster/grid of remote JVMs.

The main interfaces for simple distributed task execution are ICallable and IExecutorService. ICallable is essentially a version of the existing Callable from java.util.concurrent package except that ICallable can be executed in local or remote JVMs and they receive input from the cache provided.

The classes are diagramed below:

com.xweld.grid class diagram

Below is the infamous PI approximation example, converted to use the <xweld/> grid-cache API:

class CircleTest implements ICallable<Integer>
{
  /** The serialVersionUID */
  private static final long serialVersionUID = 3496135215525904755L;
  private final int         loopCount;
  public CircleTest(int loopCount)
  {
    this.loopCount = loopCount;
  }
  @Override
  public Integer call() throws Exception
  {
    int insideCircleCount = 0;
    for (int i = 0; i < loopCount; i++)
    {
      double x = Math.random();
      double y = Math.random();
      if (insideCircle(x, y))
      {
        insideCircleCount++;
      }
    }
    return insideCircleCount;
  }
  private boolean insideCircle(double x, double y)
  {
    return Math.pow(x - 0.5, 2) + Math.pow(y - 0.5, 2) <= Math.pow(0.5, 2);
  }
  @Override
  public void setEnvironment(ICache<?, ?> cache, Set<?> inputKeys)
  {
  }
}

 CacheManagerFactory factory = CacheManagerFactory.getInstance();

 ICacheManager manager = factory.getManager();
 ICache<String, String> cache = manager.create("test");

 ExecutorServiceFactory serviceFactory = ExecutorServiceFactory
        .getInstance();

 IExecutorService service = serviceFactory.getService(cache);

 int numPoints = 10000;
 int numServers = 100;
 int numberPerWorker = numPoints / numServers;

 long start = System.currentTimeMillis();
 CircleTest ct = new CircleTest(numberPerWorker);
 List<CircleTest> tasks = new ArrayList<CircleTest>();
 for (int i = 0; i < numServers; i++)
 {
   tasks.add(ct);
 }
 List<IFuture<Integer>> results = service.submit(tasks);
 int countCircle = 0;
 for (IFuture<Integer> f : results)
 {
   countCircle += f.get();
 }
 double appxPi = 4.0 * countCircle / numPoints;
 System.out.println("Distributed PI appx is " + appxPi + " completed in " 
        + (System.currentTimeMillis() - start) + " ms");

The Resolver API

Another key concept supported by the grid-cache is that entities in the cache need to be spatially located on the grid 'close' to where they are used by the calculations they are involved in. Typically, lightweight objects are read in bulk into the cache and rather than have their entity references resolved in a manner such as those supported by JPA or Hibernate, entity references need to be resolved at the time they are needed and local to the node where they are used. For this reason, the resolver API exists to support this retrieval model.

com.xweld.resolver class diagram

The attribute Resolve is used in a entity that can be resolved to its fully hydrated counterpart as follows:

public class Product
{
  @Resolve(target = Issuer.class)
  private final String issuerId;
  @Resolve(target = Desk.class, additionalFields = { "currency" })
  private String       deskId      = "NA";
  private String       currency    = "USD";
  public Product() {}
   /**
   * @return the issuerId
   */
  public String getIssuerId()
  {
    return issuerId;
  }
}

The Product entity has an issuer identifier that can be resolved to an instance of Issuer.class when required. The @Resolve attribute is used to specifiy this. The folowing code can be used to resolve an entity reference at run time:

// these would be set up in the Setup phase
ResolverProperties properties = new ResolverProperties();
properties.associate(Issuer.class, IssuerResolver.class);

// at run time we can use the Resolver to obtain the Issuer instance
// referenced by the issuer id
Product p = new Product();
Resolver resolver = new Resolver(properties);
Issuer issuer = resolver.resolve(p, Issuer.class, Calendar.getInstance());

The resolver framework also supports resolution of entities where multiple keys are needed. The optional additionalFields parameter of the Resolve annotation can be used to specify, in addition to the field the annotation is on, additional fields that will be passed to the implementation of IResolver. In the example of resolving Desk above, the fields deskId and currency are used as the foreign keys to desks.

The resolver framework also has the notion that entities are resolved at a specific point in time. You can think of the time parameter as a version. Typically, it is the valuation or 'as of' date. For example, if the resolver was coughing up trades, the calendar could be used to specify a view of a trade object at a historical point in time.

The application developer needs to define a class that implements the IResolver interface and register it with the system as described above. The IResolver will be called at runtime with a map of key/value pairs that given the field names from the entity and their values. The Desk resolver resolve method would have the signature:

 @Override
  public Desk resolve(ResolverTypeProperties properties,
      Map<String, Object> keys, Calendar relativeTo) throws ResolverException
  {
    // use the key/values in the map from the Product instance to resolve the desk at the specified 'as of' time
  }

I/O Framework

com.xweld.io

The <xweld/> I/O framework defines two main configurable constructs, namely Readers and Writers. The API for each of these is defined by the interfaces IReader and IWriter respectively. Readers and Writers are parameterized types, and the parameters define the types of the input and the output. There are two helpful abstract base implementations for Readers and Writers in the com.xweld.io package, as well as several instances for common uses, such as multi-threaded reader that can read files from the file system as Strings and convert them to either XML Documents or deliver them to a listener as String output. The DirectoryReader class is used in many implementations as the basis for quickly developing highly performant file processors.

Together, the Reader and Writer I/O framework defines the basic building blocks for consuming and producing event-driven output in <xweld/> applications.

I/O Reader Framework

The IReader framework implements an API to an event-driven library of input processors. Each IReader has an IReadListener which is called each time there is input to be processed. Implementers of IReadListener must always ensure that their listener is thread safe.

com.xweld.io.reader class diagram

Readers are configurable. A base configuration for a generic Reader is provided by the ReaderConfiguration class. The DirectoryReaderConfiguration class extends this to define the configurable parameters required by the DirectoryReader, such as the location of the input on the file system, the number of threads to use for parallel processing, etc.

I/O Writer Framework

The complement to the Reader framework is the Writer class hierarchy, which provides the mechanism by which an event-driven application can generate output represented by different output types or classes, and to different destinations such as SMTP servers, the file system, a database or JMS for example. There are several prebuilt writers to handle the aforementioned output scenarios, and the framework itself is flexible enough to generate output to virtually any type of destination in any format.

com.xweld.io.writer class diagram

The JMSDirectoryWriter class takes JMS TextMessages as input and writes out the payload of the text message as a file in a directory on the file system. The SmtpWriter accepts Strings as input and constructs an email message according to the configurable properties specified and sends it to a given SMTP Server.

JMS I/O Framework

com.xweld.jms

The JMS package contains the JMS extensions to the I/O framework discussed above. They encapsulate the patterns by which <xweld/> applications typically connect to JMS topics and queues.

com.xweld.jms class diagram

The <xweld/> JMS readers and writers support dynamic reconnection to JMS sources at runtime. Following the patterns established by the I/O framework, JMS topic and queue readers or writers are all configurable entities. The various settings supported for each reader or writer are encapsulated in the corresponding Configuration sub-class.

Encryption Utilities

com.xweld.cryptography

The cryptography package defines the CipherManager, a singleton class that can be used to encrypt and dycrypt strings using passphrases and a number of configurable algorithms. Supported alorithms are:

  • PBEWithMD5AndDES
  • PBEWithMD5AndTripleDES

The property com.xweld.cryptography.algorithm may be used to specifiy which algorithm should be used at runtime, and the property com.xweld.cryptography.passphrase is used to specify the secret passphrase. The I/O package, whenever it stores passwords, uses the CipherManager to
encode and decode passwords.

Example:

String input = "Now is the time for all good men to use the Java Cryptography Extension";

System.out.println("Using algorithm " + 
          System.getProperty("com.xweld.cryptography.algorithm"));
String encrypted = CipherManager.getInstance().encrypt(input);
System.out.println(encrypted);

String decrypted = CipherManager.getInstance().decrypt(encrypted);
System.out.println(decrypted);

Note

In order for your application to use this package, you will need to download and install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for your JRE. You will also need to expand your security policy file to include javax.crypto grants, similar to the following:

grant {
  permission javax.crypto.CryptoAllPermission;
  permission javax.crypto.CryptoPermission *, *;
};

in order to make all the algorithms available to your code. Once you have sucessfully installed and configured the JCE package, the key size for all algorithms will have unlimited key size restriction. The CipherManager will log, upon first initialization, the list of installed algorithms and the currently configured MaxAllowedKeyLength.

Conversion

com.xweld.conversion

The conversion package defines the API for converting objects between types. The conversion API is not intented as a replacement or even an enabling technology for user presentation or i8n support in applications. It is intended to be used for system level type conversion when serializing to/from XML or JSON, or when converting types between their JPA persistent representation and their runtime representation.

com.xweld.conversion clss diagram

The ConversionManager singleton is used to convert between types of objects at runtime, based on the set of IConverter implementations defined at runtime in the ConversionManager's configuration. Additional converters may be added by creating instances of IConverter, or the Converter abstract helper base class may be extended to support new converter types. There are built-in converters to support conversion between:

  • Strings, Dates, Calendars, XmlGregorianCalendars
  • Longs and Strings
  • Properties and HashMaps
  • Money, Strings and SmallMoney
  • BigDecimals and Strings

The code fragment below demonstrates conversion between Dates and Strings and back again:

// using injection
@Inject
ConversionManager m;

// using the conversion manager class outside a container
ConversionManager m = ConversionManager.get():

String string = m.convert(new Date(), String.class);
Date date = m.convert(string, Date.class);

A custom conversion is defined by implementing the IConverter interface and registering the implementing type with the ConversionManager configuration. To make life a little easier there is an abstract class that may be used as a convenience-based class for the custom converter.
For example, the A FooBar converter is defined as:

public class FooBarConverter extends Converter<Foo, Bar>

The converter is registered with the Conversion Manager via its configuration as follows:

public class FooBarConverter extends Converter<Foo, Bar> { ... }

 IPersistenceManager p = PersistenceManagerFactory.getInstance().getManager();
  ConversionManagerConfiguration c =
      ConfigurationManager.getInstance().getInstance(
      ConversionManagerConfiguration.class.getSimpleName(),
      ConversionManagerConfiguration.class);
  c.addConverter(FooBarConverter.class);
  p.merge(c);

Class Metadata

com.xweld.metadata

The metadata package provides an API to retrieve the metadata of classes or objects (types or instances) at runtime. The attributes of a class or object are returned as Property or PropertyValue objects.

com.xweld.metadata.JPG

The example below shows the use of the two mechanisms:

class MyType
{
  private String value = "some value";
  public String getValue() { return value; }
  public void setValue(String val) { this.value = val }
}

InstanceMetaDataByReflection<TestIt> m1 = 
  new InstanceMetaDataByReflection<TestIt>(new MyType());
TypeMetaDataByReflection<TestIt> m2 = 
  new TypeMetaDataByReflection<TestIt>(MyType.class);

Map<String, PropertyValue<Class<?>>> map = m1.getPropertyValues();
Map<String, Property<Class<?>>> map2 = m2.getProperties();

The property values for the instance of MyType are returned in the first case and the Property names and types are returned in the second case. The class must contain public setters/getter methods for each field to be considered a Property.

Validation

com.xweld.validation

The validation package defines an extremely lightweight API for validating classes and fields at runtime. The package is easy to use because it requires very little configuration or setup.

com.xweld.validation class diagram

The xweld-core module supports Type- (Class) and Field-level validation via attributes using a very simple mechanism. Attributes are used to associate an implementation of the IValidator interface with either a class or a field. The design motivation for <xweld/> validation is that it is extremely lightweight, easy to use, and does not require external configuration files or associated metadata with validation logic. The validation framework separates and encapsulates the business logic of validation from domain classes and their associated representation.

There are two attributes:

@TypeValidator
@FieldValidator

An example is as follows:

Given a class Foo that contains one String element called name, we can define:

@TypeValidator(type=FooValidator.class)
Class Foo
{
  FieldValidator(type=StringValidator.class)
  private String name;
  String getName();
}

We define the two validators by implementing IValidator for type Foo and type String as follows:

FooValidator extends Validator
{
  public FooValidator () {} // every Validator must have a default constructor
  @Override
  public boolean isValid(Object object, StringBuilder reason)
  {
    Foo entity = (Foo) object;
    if (StringUtils.IsEmpty(entity.getName()))
    {
       reason.append("The name cannot be empty.");
       return false;
    }
    return true;
  }
}

And similarly we can define the field level validator:

StringValidator extends Validator
{
  public StringValidator() {}
  @Override
  public boolean isValid(Object object, StringBuilder reason)
  {
    String entity = (String) object;
    if (StringUtils.IsEmpty(entity.getName())
    {
     reason.append("The name cannot be empty.");
      return false;
    }
    return true;
  }
}

In order to validate a class we use the static validate method, which will return a list of validation results set up by your validation classes as follows:

    Foo foo = new Foo();
    List<ValidationResult> reasons = new ArrayList<ValidationResult>();
    Validate.isValid(foo, reasons);

    Iterator<ValidationResult> iterator = reasons.iterator();
    while (iterator.hasNext())
    {
      ValidationResult result = iterator.next();
      System.out.println(result.toString());
    }

Parsing XML Documents

com.xweld.xml

This package contains the definition of a configurable XML document parser that, through configuration, can parse or shred an XML document into Property lists.

com.xweld.xml parser class diagram

Contact Us

For more information, please contact us at .

Copyright

Copyright © 1999-2014 Free North Alliance Inc. All Rights Reserved.

The contents of this web site, including all images, text, graphics and software, are the sole property of Free North Alliance Inc. and its agents. Unauthorized use or transmission is strictly forbidden by international copyright law.

com.xweld.conversion.JPG View - com.xweld.conversion clss diagram (52.5 KB) John Free, 12 December 2012 03:38 PM

com.xweld.jms.JPG View - com.xweld.jms class diagram (63.9 KB) John Free, 12 December 2012 03:40 PM

com.xweld.persistence.datareader.jpg View - com.xweld.persistence data reader class diagram (85.4 KB) John Free, 12 December 2012 03:44 PM

com.xweld.persistence.datawriter.jpg View - com.xweld.persistence data writer class diagram (43.4 KB) John Free, 12 December 2012 03:44 PM

com.xweld.validation.JPG View - com.xweld.validation class diagram (58.8 KB) John Free, 12 December 2012 04:44 PM

com.xweld.persistence.domain.JPG View - com.xweld.persistence.domain class diagram (41.4 KB) John Free, 12 December 2012 04:57 PM

com.xweld.observer.JPG View - com.xweld.observer class diagram (37.8 KB) John Free, 12 December 2012 04:59 PM

com.xweld.io.writer.JPG View - com.xweld.io.writer class diagram (78.8 KB) John Free, 12 December 2012 05:02 PM

com.xweld.io.reader.JPG View - com.xweld.io.reader class diagram (130 KB) John Free, 12 December 2012 05:04 PM

com.xweld.metadata.JPG View - com.xweld.metadata.JPG (58.4 KB) John Free, 18 December 2012 04:17 PM

com.xweld.cache.JPG View - com.xweld.cache class diagram (60.3 KB) John Free, 18 December 2012 05:16 PM

com.xweld.grid.JPG View - com.xweld.grid class diagram (50.1 KB) John Free, 18 December 2012 05:19 PM

com.xweld.xml.JPG View - com.xweld.xml parser class diagram (103 KB) John Free, 18 December 2012 05:37 PM

com.xweld.persistence.JPG View - com.xweld.persistence class diagram (128 KB) John Free, 19 December 2012 08:54 AM

com.xweld.resolver.JPG View - com.xweld.resolver class diagram (58.3 KB) John Free, 20 December 2012 01:48 PM