Objectopia

Archive for the ‘Java etc…’ Category

Hibernate and sets – use at your peril

Posted by Chris Clark on December 6, 2011

For the past 3 weeks I’ve spent hours tuning the performance in one of the applications we use. Unfortunately rather than spend some time and come up with a proper reporting solution I was tasked to fix the existing solution which is to report off our live transactional system. We use EJB3 on JBoss so hibernate it is, which I personally think is an excellent framework for getting your application up and running quickly. Hibernate have always stated that performance isn’t it’s goal so I can’t blame hibernate for anything I’ve found. I tackled the problem in the usual way, add some sql logging and see what’s really happening and look for the usual suspects, lazy loading, code structure etc. Where I saw collections being loaded up separately I added Join fetches and rerun the reports. This worked really well then I noticed that no matter how I wrote the JPQL it always seemed to be running seperate queries for some of the realtionships. That’s when the bulb flashed they were defined as Sets!!

An example of such a thing:

@OneToMany(mappedBy="transaction")
private Set taxComponents = new HashSet(1);

I understand why sets are used but as I’m in control of what gets put in I can safely use:

@OneToMany(mappedBy="transaction")
 private Collection taxComponents = new ArrayList(1);
 

So using set’s is great but it comes at a cost and beware it’s not just fetches but deletes and inserts have a similar issue in that they get deleted one by one and then reinserted to ensure uniqueness, so if you do update the set it also has a performance hit.

The performance of the major report moved from 30 mins to 6 mins, still not lightning fast but a good improvement. I could of course move to native SQL but I didn’t want to have to rewrite a load of code to do that.

Posted in Java etc... | 2 Comments »

Securing your JBoss JMX Invoker Layer

Posted by Jon Court on October 1, 2009

If you use JBoss and have a nicely secured JMX Console and/or Web Console it’s a fairly safe bet that, like me, you haven’t secured the invoker layer; meaning any old monkey can most likely shutdown your container whenever they feel like it.

Recently I implemented an MBean in JBoss to use as a batch trigger from a ControlM implementation and was surprised (probably shouldn’t have been though) that all my carefully crafted security for the JMXConsole and Web Console was ignored with complete impunity by the tool (twiddle.sh) that I used to invoke my MBean. Since then I’ve been through a pile of pain trying to get an RMI call to a JBoss XMBean to require authentication and I thought I’d put some instructions in plain language on how to do it.

I do this for two reasons:

  1. because I bet a lot of developers miss this one; and
  2. because the documentation and other information I find online is limited and confusing.

For demonstration I’m going to use a standard JBoss MBean for setting system properties in a running application container.

A Simple Example of Setting a System Property in JBoss using Twiddle

Using the default JBoss version of twiddle.sh (in the bin directory beneath JBoss home) against the default JNP location of JBoss (localhost:1099) you can execute the following to set a system property in a running container.

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 invoke "jboss:type=Service,name=SystemProperties" set myprop mypropvalue
'null'

To verify that you have been succesful (assuming you didn’t get an exception in the last operation) you can do the following:

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

This example will work from anywhere on your network where you’re not prevented from reaching the JNP URL of the container (prevented by a firewall or IP filter for example) regardless of the JMX Console and Web Console security you’ve put in place (there is plenty of documentation around for securing the JMX Console and Web Console). This is because the JMX Console and Web Console are HTTP based and as such are secured in the normal way you would secure a website on JBoss (i.e. in web-inf.xml and jboss-web.xml) whereas the invoker layer is not HTTP based and as such must use an alternate method of security; the key file in this operation is the jmx-invoker-service.xml file in the JBoss deploy directory.

Securing the Invoker Layer

The invoker layer is the one you are calling through when you query or invoke on an MBean via RMI (i.e. with twiddle.sh – as above). This layer is not subject to the security constraints you will have placed on your HTTP based JMX Console or Web Consoles.

To make this layer secure the key file you’re interested in is the jmx-invoker-service.xml in the JBoss deploy directory; and the key operation configuration you will need to change is for ‘invoke’.

The default configuration of the invoke operation in this file is:

<server>

	<!-- excluded for brevity -->

	<mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker" xmbean-dd="">
		<xmbean>
			<description>The JMX Detached Invoker Service</description>
			<class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>

			<!-- excluded for brevity -->

			<operation>
				<description>The detached invoker entry point</description>
				<name>invoke</name>
				<parameter>
					<description>The method invocation context</description>
					<name>invocation</name>
					<type>org.jboss.invocation.Invocation</type>
				</parameter>
				<return-type>java.lang.Object</return-type>
				<descriptors>
					<interceptors>

						<!-- Uncomment to require authenticated users -->
						<!-- <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/> -->

						<!-- Interceptor that deals with non-serializable results -->
						<interceptor code="org.jboss.jmx.connector.invoker.SerializableInterceptor" policyClass="StripModelMBeanInfoPolicy"/>

					</interceptors>
				</descriptors>
			</operation>
		</xmbean>
	</mbean>
</server>

So to switch on authentication we do what it says and ‘Uncomment to require authenticated users’:

<server>

	<!-- excluded for brevity -->

	<mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker" xmbean-dd="">
		<xmbean>
			<description>The JMX Detached Invoker Service</description>
			<class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>

			<!-- excluded for brevity -->

			<operation>
				<description>The detached invoker entry point</description>
				<name>invoke</name>
				<parameter>
					<description>The method invocation context</description>
					<name>invocation</name>
					<type>org.jboss.invocation.Invocation</type>
				</parameter>
				<return-type>java.lang.Object</return-type>
				<descriptors>
					<interceptors>

						<!-- Uncomment to require authenticated users -->
						<interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/>

						<!-- Interceptor that deals with non-serializable results -->
						<interceptor code="org.jboss.jmx.connector.invoker.SerializableInterceptor" policyClass="StripModelMBeanInfoPolicy"/>

					</interceptors>
				</descriptors>
			</operation>
		</xmbean>
	</mbean>
</server>

If you haven’t changed the default security realm for your JMX Console (i.e. java:/jaas/jmx-console) you will now have an invoker layer secured with the same credentials as for your JMX Console. To change this add a new security realm to your global login-config.xml in the conf directory of your container and match the name you give it in the securityDomain attribute of the Authentication Interceptor.

I’ve not yet delved too deeply into setting a specific set of roles, at this point I set my invoker user to JBossAdmin which means that user can do pretty much anything exposed to JMX. That’s ok for my purposes tho (feel free to write a response with the details of setting roles for particular JMX functions :-) ).

Invoking on a Secure Invoker Layer

Ok so now that it’s secure how do you invoke an operation on it?

With the default JBoss twiddle.sh utility there are arguments -u (or –user=) for user and -p (–password=) for password.

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 --user=myuser --password=mypassword invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

These arguments work fine except your password is now in clear text and even worse is visible in the process list while it’s executing – in clear text with ‘password=’ conveniently placed for extraction by a simple script!! This seems a bit of an oversight in the tool to me.

To get around this issue in my environment I took the source and modified the main class of twiddle.jar to accept a password from Standard In (patch is below – no promises or guarantees though) which prevents the password showing in your password list and allows you to use standard encryption utilities to decrypt and pipe it into the process without ever making it visible clear text.

You would now invoke as follows:

# this assumes you're in the bin directory of JBoss Home.
mypassword | ./twiddle.sh -s localhost:1099 --user=myuser invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

or better; from an encrypted password file (or better yet a repository) such as follows:

# this assumes you're in the bin directory of JBoss Home and have previously encrypted your password and encryption key into ~/.<username>.key and ~/.<username>.psw.
KEY=`cat ~/.<execution username>.key`
PWD=`cat ~/.<execution username>.psw | crypt $KEY`

PWD | ./twiddle.sh -s localhost:1099 --user=myuser invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

to encrypt your password to be used as above you might do:

echo "<password>" | crypt > ~/.<execution username>.psw

which will request an encryption key which you would save as follows (for this example anyway):

cat "<encryption key>" > ~/.<execution username>.key

These files would, of course, be accessable only from your execution user.

Securing the JMX Console

For reference the key files you’re interested in here are:

  • conf/login-config.xml
  • deploy/jmx-console.war/META-INF/web.xml
  • deploy/jmx-console.war/META-INF/jboss-web.xml

Securing the JMX Web Console

For reference the key files you’re interested in here are:

  • conf/login-config.xml
  • deploy/management/web-console.war/META-INF/web.xml
  • deploy/management/web-console.war/META-INF/jboss-web.xml

Stack

These instructions will apply broadly but for reference purposes the stack I have is:

  • JBoss 4.2.3.GA
  • Java jdk1.6.0_13
  • Windows XP or Solaris 10

References

http://www.jboss.org/community/wiki/Twiddle

http://www.jboss.org/community/wiki/jbossserver-aquicktour

https://jira.jboss.org/jira/secure/attachment/12313982/jboss-securejmx.pdf (PDF Document)

Regards,
Jon

:)

Patch For Twiddle to Take Password from StdIn (no promises or guarantees)


Index: src/main/org/jboss/console/twiddle/Twiddle.java
===================================================================
--- src/main/org/jboss/console/twiddle/Twiddle.java    (revision 94201)
+++ src/main/org/jboss/console/twiddle/Twiddle.java    (working copy)
@@ -24,8 +24,10 @@
 import gnu.getopt.Getopt;
 import gnu.getopt.LongOpt;

+import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -41,7 +43,6 @@
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
-
 import org.jboss.console.twiddle.command.Command;
 import org.jboss.console.twiddle.command.CommandContext;
 import org.jboss.console.twiddle.command.CommandException;
@@ -148,7 +149,7 @@
 }
 };
 }
-
+
 public Command createCommand(final String name)
 throws NoSuchCommandException, Exception
 {
@@ -383,7 +384,7 @@

 out.println("A JMX client to 'twiddle' with a remote JBoss server.");
 out.println();
-      out.println("usage: " + PROGRAM_NAME + " [options] <command> [command_arguments]");
+      out.println("usage: [echo <password> | ] " + PROGRAM_NAME + " [options] <command> [command_arguments]");
 out.println();
 out.println("options:");
 out.println("    -h, --help                Show this help message");
@@ -397,6 +398,10 @@
 out.println("    -u, --user=<name>         Specify the username for authentication");
 out.println("    -p, --password=<name>     Specify the password for authentication");
 out.println("    -q, --quiet               Be somewhat more quiet");
+      out.println();
+      out.println("A password should be passed in by echoing it and piping it to the command. If you");
+      out.println("use the -p (--password) option your password may be visible in clear text in a ");
+      out.println("process listing such as `ps -ef`.");
 out.flush();
 }

@@ -421,6 +426,28 @@
 Getopt getopt = new Getopt(PROGRAM_NAME, args, sopts, lopts);
 int code;

+        /* Get standard in if it's there - assume it's a password. This is to allow a password to be passed and
+         * prevent it showing in a process listing (e.g. ps -ef in Unix). The -p argument will be ignored if
+         * the password is passed through Standard In.
+         */
+        boolean passwordRetrievedFromStdIn = false;
+        if (System.in.available() > 0) {
+            InputStreamReader inp = new InputStreamReader(System.in);
+            BufferedReader br = new BufferedReader(inp);
+            String stdin = br.readLine();
+
+            if (stdin != null &amp;&amp; stdin.trim().length() > 0) {
+                String password = stdin.trim();
+                SecurityAssociation.setCredential(password);
+
+                passwordRetrievedFromStdIn = true;
+
+                if (log.isDebugEnabled()) {
+                    log.debug("Password retrieved from standard in. Ignoring -p argument.");
+                }
+            }
+        }
+
 PROCESS_ARGUMENTS:

 while ((code = getopt.getopt()) != -1)
@@ -531,8 +558,13 @@
 SecurityAssociation.setPrincipal(new SimplePrincipal(username));
 break;
 case 'p':
-                 String password = getopt.getOptarg();
-                 SecurityAssociation.setCredential(password);
+                  if (!passwordRetrievedFromStdIn) {
+                     String password = getopt.getOptarg();
+                     SecurityAssociation.setCredential(password);
+
+                     log.warn("Password retrieved from -p argument. Your password may be visible in cleartext in a process listing during execution. " +
+                             "Consider using Standard In to enter the password instead (i.e. echo \"password\" | twiddle ...)");
+                  }
 break;

 // Enable quiet operations

 light="true"

Posted in Java etc... | Tagged: , , , , , , , , , , , , , , | 5 Comments »

EJB 3.0 Interceptors

Posted by Chris Clark on July 21, 2009

I wanted to carry out some processing when an entity was committed to the db, I could of used the lifecycle annotation @PostPersist in the bean itself but that that would go against leaky abstraction (see post Non-anaemic models). Anywho it was pretty simple to get this working all that I had to use were a couple of annotations.

The first @EntityListerners which accepts an array of classes that will become your event handlers:

@EntityListeners(ErrorListener.class)
public class SystemError implements Serializable {

The next is to annotate the methods in your listener class that will handle the various events. The annotations that can be used are:

    @PrePersist Executed before the entity manager persist operation is actually executed or cascaded. This call is synchronous with the persist operation.
    @PreRemove Executed before the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.
    @PostPersist Executed after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed.
    @PostRemove Executed after the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.
    @PreUpdate Executed before the database UPDATE operation.
    @PostUpdate Executed after the database UPDATE operation.
    @PostLoad Eexecuted after an entity has been loaded into the current persistence context or an entity has been refreshed.

Note that if you are using EJB dependency injection it won’t work in your listener as it’s not managed by your container buy you can use jndi: -

Context ctx = new InitialContext();
XXXService service = (XXXService) ctx.lookup("EARNAME/XXXServiceBean/local");

Posted in Java etc... | Tagged: , , , | Leave a Comment »

Joda with JPA

Posted by Chris Clark on July 10, 2009

I have to work with a few legacy databases that are used by several different apps (apparently the database is a perfect integration point), and I want to use the Joda api in my persistence. In this example the date is actually stored as a string, genius! I’m going to use LocalDate as the string doesn’t store the time element. If you are lucky enough and the database is actually storing date time check this post out Joda With DateTime

To start with a create a simple helper class that converts String to LocalDate and LocatDate to String

public static LocalDate createLocalDateForString(String dateString){
  DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");
  return StringUtils.isEmpty(value) ? null :  fmt.parseDateTime(dateString).toLocalDate();	
}
    
    public static String createStringForLocalDate(LocalDate date){
    	return date.toString("yyyyMMdd"); 
    }

Next is to create your own user type. This is done by implementing org.hibernate.usertype.UserType. The main methods I’m implement are

public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
			throws HibernateException, SQLException {
		LocalDate result = null;
		String dateAsString = rs.getString(names[0]);
		if(!rs.wasNull()){
			result = StringUtils.isNotEmpty(dateAsString) ? DateHelper.createLocalDateForString(dateAsString) : null;
		}
		return result;
	}

public void nullSafeSet(PreparedStatement statement, Object value, int index)
			throws HibernateException, SQLException {
		if(value == null){
			statement.setNull(index, SQL_TYPES[0]);
		}else{
			String dateAsString = DateHelper.createStringForLocalDate((LocalDate)value);
			statement.setString(index, dateAsString);
		}
}

All that is left is to add the annotation to each of your entity properties that you want to use as LocalDate.

@org.hibernate.annotations.Type(type = "xxx.LocalDateUserType")

Posted in Java etc... | Tagged: , , , | 2 Comments »

Please ! Stop using floating point numbers for financial data

Posted by Chris Burnley on July 3, 2009

Again and again I see developers using doubles for storing financial data (e.g. monetary figures, interest rates etc.). This always causes some sort of rounding issue down the line.

try this in your IDE:

double total = 0;
for (int i =0; i <  10; i++){
  total += 0.1;
}
System.out.println(total);

If you expect the answer to be 1 or 1.0, then you’re wrong !

Question: are you writing a game ? Answer: no; then use an effing BigDecimal!

Grrr…

Posted in Grrrr..., Java etc... | 2 Comments »

Using Hibernate Search in SEAM 2.0 Application

Posted by Chris Clark on July 1, 2009

I implemented hibernate search recently in a SEAM project I was working on. I wanted to use the excellent suggestion tag from the excedel library and I wanted to use an index rather than hitting the database for each of the searches. I also wanted to use wildcard searches and for each keystroke this would be far to expensive. To implement it I completed the following steps: -

In my persistence.xml I added the following to the properties of my persistence-unit:-

<property name="hibernate.search.default.indexBase" value="PATH TO YOUR INDEX DIRECTORY"/>
<property name="hibernate.ejb.post-insert" value="org.hibernate.search.event.FullTextIndexEventListener"/>
<property name="hibernate.ejb.post-update" value="org.hibernate.search.event.FullTextIndexEventListener"/>
<property name="hibernate.ejb.post-delete" value="org.hibernate.search.event.FullTextIndexEventListener"/>

The path of your index base can be anywhere you want as long as the application has permission to write to it.

To used hibernate search you need to identify and highlight all of the classes that you want to search, you also need to identify each of the properties that you want indexed and the indexing strategy, you can find out what the various types are here Hibernate Search

@Indexed(index="index_direcory")
public class SomeClass

@Field(index=Index.TOKENIZED, analyzer = @Analyzer(impl = LowerCaseAnalyser.class))
@Column(name = "inv_name", length = 200, nullable = true)
private String name;

Inject an instance of FullTextEntityManager into your code. I used a stateless session bean that was used throughout the application

@In
private FullTextEntityManger entityManager;

I used a three different query types, RegEx, Prefix and WildCard.

RegexQuery(new Term(fieldName,".*[^-'\\w]" + searchString.toLowerCase() + "(\\s|$)"));
PrefixQuery(new Term(fieldName,searchString.toLowerCase()));
WildcardQuery(new Term(fieldName,'*'+searchString.toLowerCase()+'*'));

The regex one was used to search for firstname surname i.e. Jo Bloggs. The prefix query was used to search for Jo* i.e. Joanne, Jo Bloggs. The wildcard one, the most expensive one, was used to search for *Jo* i.e. Jones, BillyJoBloggs. The fieldname is the obviously the name of the field, so in:-

@Field(index=Index.TOKENIZED, analyzer = @Analyzer(impl = LowerCaseAnalyser.class))
private String name;  

FiledName would = name

All that is left to do it actually query the index and this is done by:

entityManager.createFullTextQuery(query,SomeClass.class).getResultList();

This has been in production for a some time now and it’s been stable and performed well. There has only been one instance to date of the index getting screwed up but I catered for that and enable the index to be rebuilt. I also had to provide this as any update to the indexed fields via direct sql wouldn’t be updated.

Posted in Java etc... | Tagged: , , , | Leave a Comment »

Calling Stored Procedures in JPA

Posted by Chris Clark on June 26, 2009

Recently I had to call a stored procedure using JPA and to my surprise I soon found out that it’s not directly supported. So how do you call a stored procedure? My stack is

Db = Sybase
AppServer = JBoss 4.2.3
Java = 1.6
Persistance = EJB3 implemented by Hibernate
Hibernate = 3.4.0.GA

So the first thing I do is to create a named native query on my entity which looks something like this:

@NamedNativeQuery(name="StoredProc_Call",
                  query="stored_proc_name(:param1, :param2, :param3)",
                  hints={
                      @QueryHint(name = "org.hibernate.callable",value = "true"), 
                      @QueryHint(name = "org.hibernate.readOnly",value = "true")
                  },
                  resultSetMapping="scalar", resultClass=Result.class)

@SqlResultSetMapping(name="scalar",columns=@ColumnResult(name="result")

Because I’m using hibernate as my EJB3 implementation, the default for JBoss, I can use it to call the stored proc for me using the hints attribute which takes in an array of queryhint objects.

Because native scalar results aren’t supported by EJB3 you also have to set the resultClass and the resultSetMapping.

@SqlResultSetMapping(name="scalar",columns=@ColumnResult(name="result")

All that is required now is to create the native query, set the required parameters and call it.

Query query = entityManager.createNamedQuery("StoredProc_Call");

Posted in Java etc... | 4 Comments »

Non-anaemic models and service oriented architectures

Posted by Chris Burnley on May 20, 2009

The term “anaemic domain model” is used to describe an entity layer that contains very little business logic. Typically in this architecture, the business logic is contained in services and/or delegates. There are several problems with this approach:

  • Business logic quickly gets scattered and duplicated across the system
  • It is difficult to maintain because it is hard to determine which class needs to be changed
  • It is difficult to test because the service/delegate usually has many dependencies
  • It is not particularly object oriented (e.g. polymorphism, which can reduce a lot of complexity by reducing ‘type-logic’, is rare)

The trend these days is towards Domain Driven Design (DDD), and is a strategy against anaemic domain models. In this architecture, services are used as an ‘anti-corruption-layer’ to translate requests from the external domain to the internal domain of the system. The majority of the logic is contained within the domain model (this includes persistent and non-persistent objects).

When developing a non-anaemic model (e.g. DDD), it is tempting to call services directly to perform logic (to perhaps an external system, or send a message), to hide complexity from the client:

class Account {
    Balance getBalance() {
        for(Transaction t : getTransactionService().getTransactions(…)){
            //… sum them up
        }
    }

    TransactionService getTransactionService() {
        // lookup service
    }
}

I think this not good design for a number of reasons:

  • The risk of Leaky Abstraction (e.g. having to declare checked Exceptions to methods)
  • Generally speaking, the domain model doesn’t have enough information about the nature of the method call to perform well. The service would be better suited to know how the model will be used (e.g. in a loop).
  • It is harder to test the business logic because you’ve got to mock out too many dependencies.
  • I believe that entities should be deterministic, the behaviour must be determinable given the state of the system/database.
  • Potentially introduces circular dependencies between service->model->service->model etc. which causes problems for maintainability, testing and debugging.

So how do we have a nice, clean, rich domain model ? One way is to pass an implementation of an interface to the domain (e.g. a delegate to a service) so the domain can perform its logic:

class Account {
    Balance getBalance(TransactionRepository repos) {
        // … get the transactions, sum them up
    }
}
// Getting the balance on a single account
Account account =...;
account.getBalance(singleAccountTransactionRepository);
// Getting the balance on many accounts
List<Account> accounts = ...;
for(Account account : accounts){
          account.getBalance(allAccountTransactionRepository);
}

The idea here is that you substitute the most appropriate implementation to get the best performance for the particular use case.

There is a subtle difference between the two, but the second IMO is a cleaner, more-flexible solution.

Posted in Java etc... | 1 Comment »

Re: A general approach to exceptions in Java

Posted by Chris Burnley on March 23, 2009

My previous post about exceptions in Java begs the question: Where do so called “business exceptions” fit in with all of this?

Business Exceptions are Checked Exceptions

Following on from my reasoning, the user is something that you have no control over. Therefore you expect these types of exceptions to occur. Making them checked exceptions forces you to handle them in some way.

A classic example of these errors are validation errors. These should be checked exceptions because usually you’d need to force the user to fix the entered data before the form can be submitted.

Dealing with Checked Exceptions

The problem of checked exceptions is: how do you handle them ? You’ve got to catch them somewhere (or rethrow), how do you know what to do with them ? This is usually a requirements question; this should be a hint to you to go back to the business and get some clarification on the requirements.

Posted in Java etc... | Leave a Comment »

Persistent Strategies

Posted by Chris Burnley on March 22, 2009

I’ve just finished working on a cash management system. The core of what the system does is listen to messages produced by various sources and record a transaction (i.e. a debit and a credit) between two accounts.

For example, the system will listen to trade messages produced by our trading system and charge a trade fee to the client. This involves debiting the client and crediting the Fee house account.

This seems innocent enough, but to create a transaction you must have a reference to each of these accounts.

The client’s account is easy enough to find as all the required information is supplied in the trade message. But what about the house account ? How does the system find an instance of the house Account ?

One could do something like this, store the account number in a constant somewhere:

Account account = accountService.getAccount(FEE_HOUSE_ACCOUNT_NUMBER);

// create Transaction with client and house account

This is pretty bad IMO because there is duplication and “hard coding” ( even if it is in a properties file) of what house account numbers there are.

If you didn’t want to store the account number in code (or in a properties file which is almost as bad) you could add it to the static data for that transaction type:

@Entity
class TransactionType {
    String name;
    Account creditAccount; // this could be null to indicate that the account is based on the message
    Account debitAccount; // this could be null to indicate that the account is based on the message
    //...
}

then you would just find the TransactionType and the get the credit or debit account.

This would work, but it is very specific, since sometimes we may want to find the debit / credit account in a different way (e.g. “find the loan account associated with the client’s cash account”).

Enter the Persistent Strategy.

Basically, the idea is that rather than store links directly to Accounts in your static data, store a Strategy to obtain the right Account.

@Entity
public class TransactionType {</code>

    private String type;

    @ManyToOne
    private AccountAllocationStrategy toAccountStrategy;

    @ManyToOne
    private AccountAllocationStrategy fromAccountStrategy;
}

@Entity
@Inheritance
public abstract class AccountAllocationStrategy {
    public abstract Account getAccount(Transaction transaction);
}

What we’ve done is added a strategy for find the from / to account and we can have specific implementations:

@Entity
public class FixedAccountAllocation extends AccountAllocationStrategy {

    @ManyToOne
    private Account account;

    public Account getAccount(Transaction transaction) {
        return account;
    }
}

@Entity
public class InvestorAccountAllocation extends AccountAllocationStrategy {

    @Override
    public Account getAccount(Transaction transaction) {
        return transaction.getInvestorAccount();
    }
}

(there are a few more implementations I’ve left out for brevity).

You could achieve a similar effect by using a code of some sort (e.g. an enum) to denote the strategy and look up the strategy instance via Spring, but I like this better since it is more transparent and doesn’t require involving other frameworks. The major problem with the Spring approach is you’ve still got to specify the account numbers somewhere in your Spring context file which is duplication (once in the Spring file, once in the database) which, we all know, is bad :)

It might seem like abusing entities or the domain model but it is a really powerful pattern. Think of these entities as your rule domain. JPA makes mapping entities really easy and the number of strategies are finite so you can be quite creative in your mapping and inheritance hierarchies. You can also fully cache the strategy entities so performance will not be an issue.

We use this pattern in a few places in the system and it has made the code much cleaner and maintainable.

Posted in Java etc... | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.