The Zonski Framework

Modelling the Database

Let's look at our data now from a storage perspective. Although we have three data entities (nests, markers and turtle sightings) we only need two tables, since nest and turtle sighting data have a one-to-one relationship. Using hibernate we can model these as two beans: a nest bean (including turtle sighting information) and a marker bean.

We don't want to use the same names we used in our service beans so lets append something to the end of these. We're modelling the database here so lets use database terms. Each instance of a bean corresponds to a row of data so lets call them NestRow and MarkerRow. Simple and honest names are always best.

Hibernate uses a stateful session to manage data. This means that as long as the session is open, any changes we make to our beans are reflected in the database (by the time the session is closed anyway). This is the opposite to our service-level beans where the data is disconnected from its source the moment it leaves the service. As such, it makes sense to use mutable beans in our database model - this correctly represents the reality of the situation and allows us to take advantage of hibernate's features.

Hibernate provides nice, Java-friendly relationship linking, which mirrors the foreign key constraints of our database. We simply put Java references (or collections of references) on each bean as needed and configure these via hibernate. In our turtle scenario we have a many-to-one relationship between nests and markers (i.e. a nest has one marker, a marker has many nests). As such, we'll put a MarkerRow reference on our NestRow and a Set of NestRow refererences on our MarkerRow.

Unfortunately hibernate does not seem to support type-safe IDs with any grace. This is odd and somewhat annoying (type-safe IDs are an age-old concept so I find it strange that hibernate has utterly ignored them). We instead need to model these by their primitive types (longs in our case). This is needed only to make hibernate happy, in our code we will always use our type safe IDs. It makes sense to provide a small convenience method on each of our beans to create the type-safe ID as needed.

The only other thing we want to do in our code is provide a convenience method for mapping between our database model beans and our service model beans. This is something that will be done frequently and in several places so it makes sense to localize this into a method. The best place for this is on our database beans (dependencies should always be towards the service layer, this ensures that the server and client are only coupled via the service API). On each of our database beans we will provide a method to convert these to service beans as appropriate.

With all this in mind our MarkerRow bean now looks like this:

public class MarkerRow implements Serializable

{

private Long id;

private String name;

private int metersFromBase;

private String description;

private Set nests;


public MarkerRow()

{

}


public MarkerRow(String name, int metersFromBase, String description)

{

this.name = name;

this.metersFromBase = metersFromBase;

this.description = description;

}


public Long getId()

{

return id;

}


public void setId(Long id)

{

this.id = id;

}


public Marker.Id getMarkerId()

{

return (this.id != null ? new Marker.Id(this.id) : null);

}


// other accessor methods removed to keep things short


public Marker toMarker()

{

return new Marker(getMarkerId(),

this.name,

this.metersFromBase,

this.description);

}

}

I've left out the simple getters and setters for brevity. The only things of note are the getMarkerId() and toMarker() methods that help us convert to beans used by our service layer. The rest of this class is a very standard hibernate bean.

Our NestRow has few surprises as well:

public class NestRow implements Serializable

{

private Long id;

private MarkerRow marker;

private int angleFromMarker;

private int centimetersFromMarker;

private String nestDescription;

private int eggCount;

private boolean turtleSighted;

private String tagCode;

private TurtleSpecies species;

private String turtleDescription;

private Integer shellLength;

private Integer shellWidth;


public NestRow()

{

}


public NestRow(int angleFromMarker,

int centimetersFromMarker,

String description,

int eggCount,

MarkerRow marker)

{

// assign variables to class members

}


public NestRow(int angleFromMarker,

int centimetersFromMarker,

String nestDescription,

int eggCount,

MarkerRow marker,

String tagCode,

TurtleSpecies species,

String turtleDescription,

Integer shellLength,

Integer shellWidth)

{

// assignment of variables removed to keep things short
}


public Long getId()

{

return id;

}


public void setId(Long id)

{

this.id = id;

}


public Nest.Id getNestId()

{

return (this.id != null ? new Nest.Id(this.id) : null);

}


// other accessor methods removed to keep things short


public Nest toNest()

{

TurtleSighting sighting = null;

if (this.turtleSighted)

{

sighting = new TurtleSighting(

this.tagCode,

this.species,

this.turtleDescription,

this.shellLength,

this.shellWidth);

}


return new Nest(

getNestId(),

(this.marker != null ? this.marker.getMarkerId() : null),

this.angleFromMarker,

this.centimetersFromMarker,

this.nestDescription,

this.eggCount,

sighting);

}

}

Again this is just a standard hibernate class with our getNestId() and toNest() helper methods. We've included all the attributes from both nests and turtle sightings. We've also added a boolean 'turtleSighted' attribute. In the service layer this attribute is implicit by the turtle sighting bean existing or not. In our database layer we have no such bean so this attribute needs to be explicitly modelled. Our toNest() method uses this when building the nest bean to decide whether turtle sighting information should be included or not.

The last thing we need to do is define how these beans are mapped to the database. In our dictionary example we used hibernate mapping files but there is an easier option. The latest version of hibernate makes use of Java 1.5 and supports annotation based mapping. Since we already have a very database centric bean it makes sense to use these and avoid those nasty XML files.

Hibernate annotations are quite easy to use. All we need to do is add a @Entity annotation just above the class definition for each Row object. Hibernate's default mapping for each of our attributes is pretty good and we only need to override this in a coupe of cases:

1. We need to add a @Table(name="(table_name)") annotation to provide custom names so that 'row' is not included in the table name (we could write a custom naming strategy as well, but we'll leave that alone for now).

2. We need to mark our getId() method with @Id and also @GeneratedValue(strategy=GenerationType.AUTO).

3. We need to mark our getXId() methods with @Transient so that hibernate doesn't try to create an extra column for this.

4. We need to mark our relationships appropriately using @ManyToOne, @OneToMany, etc.

As well as these rules any of the normal hibernate annotations should be used as appropriate (see the hibernate annotation documentation for more details). One useful trick is to mark Java enum getter methods with @Enumerated(EnumType.STRING) so that the string of the enum is stored in the database instead of the number.

So following these rules, our MarkerRow is now annotated like this:

import javax.persistence.*;


@Entity

@Table(name="marker")

public class MarkerRow implements Serializable

{

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

public Long getId()

...


@Transient

public Marker.Id getMarkerId()

...


@OneToMany(mappedBy="marker")

public Set getNests()

...
}

All other methods should be left unannotated. The default hibernate mapping will work just fine.

Our NestRow is annotated like so:

import javax.persistence.*;


@Entity

@Table(name="nest")

public class NestRow implements Serializable

{

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

public Long getId()

...


@Transient

public Nest.Id getNestId()

...


@ManyToOne

public MarkerRow getMarker()

...


@Column(name="cm_from_marker")

public int getCentimetersFromMarker()

...


@Enumerated(EnumType.STRING)

public TurtleSpecies getSpecies()

...

}

Everything is as outlined in our rules above with one small extra option. We've told hibernate to use a different name for our 'centimetersFromMarker' attribute to 'cm_from_marker'.

Our hibernate beans are all now mapped and ready for use. The last step is to modify our hibernate session configuration to be annotation based, rather than mapping file based. This is a simple matter of changing our config to look like this:

<bean id="hibernateSessionFactory"

class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.PostgreSQLDialect

</prop>

</props>

</property>

<property name="annotatedClasses">

<list>

<value>com.zonski.examples.turtlewatch.dao.MarkerRow</value>

<value>com.zonski.examples.turtlewatch.dao.NestRow</value>

</list>

</property>


<property name="namingStrategy">

<bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>

</property>

</bean>
The main points of interest are highlighted in bold. We've changed the hibernate session factory class to be one that is annotation aware and we've then used the 'annotatedClasses' property to specify which classes should be used to map to the database (in this case, our two annotated Row beans).

I have also configured this session factory to use the hibernate improved naming strategy. This just maps attribute names to column names in a way that is a little nicer than the default. The default naming strategy will map an attribute such as 'shellLength' to a column called 'shellLength'. This improved strategy will map this to 'shell_length', a form more commonly used with databases.

Our database model is now complete. We just need to create some DAOs so that we can use it.

0 Comments (Post a Comment)

Modelling Service Data

With our screens defined for our Turtle System (see earlier post) we can now define our service data. Clearly there are two main concepts in the system: nests and markers. We also sometimes include turtle sighting information with each nest so it makes sense to model this as a third concept.

The attributes for each of these entities can be derived directly from the screens (e.g. a marker has a name, a distance from base, and a description). Roughly we're going to have something like these (ignoring relationships for now):

public class Nest

{

private int angleFromMarker;

private int centimetersFromMarker;

private String description;

private int eggCount;

}


public class Marker

{

private String name;

private int metersFromBase;

private String description;

}


public class TurtleSighting

{
private String tagCode;

private TurtleSpecies species;

private String description;

private Integer shellLength;

private Integer shellWidth;

}

Note: TurtleSpecies is just an enum, defining the possible turtle species that could be sighted (leatherback, hawksbill and green we're the only turtles at this sight).

One thing I've found very useful to do in the past is to make these transfer objects immutable (i.e. you can't change them after they've been created). This helps with general maintenance in a number of ways (e.g. if you add a property, you will get a compile-time error at each point that the constructor is used). This also avoids a common Swing problem. Since Swing is stateful (unlike web-based interfaces), the data objects are usually held in several stateful models. Modifying a bean may have obscure, far-reaching and possibly undesirable effects.

Making our data objects immutable is a simple case of adding only getter methods and no setters. Our bean data can then only be populated by a constructor.

Another technique that comes in handy is to use type-safe IDs. Each of our data objects will have a primary identifier of some kind. Typically this will be a standard Java long. Rather than expose this long directly however it is useful to create a specific ID object that wrap this long (i.e. a MarkerId for Markers, a NestId for nests).

This is useful on a maintenance level, since it more closely types your service API. The compiler ensures you never use a nest ID in place of a marker ID by accident. Logging is also improved: a toString() method on the ID allows us to include the type of ID when we log it. Instead of a message saying "added 456 to 539" we get the more useful log message "added NestId[456] to MarkerId[539]".

Type-safe IDs are also useful when using collections, such as for indexing in maps. The type-safe ID allows you to put objects of different types in the same map without conflict. If you tried to put a nest object and a marker object in the same map using only longs as the key, then one could easily overwrite the other.

Since most of our data objects are going to have these IDs we'll define a base class in our framework that we can reuse called UniqueId. Complementing this is a base class that our data objects can extends called IdentifiableDataObject. These classes combined reduce the code duplication from using this approach.

Putting all this together we end up with a Marker data object that looks like this:

public class Marker 
extends IdentifiableDataObject<Marker.Id>

{

private String name;

private int metersFromBase;

private String description;


public Marker(Id id, String name, int metersFromBase, String description)

{

super(id);

this.name = name;

this.metersFromBase = metersFromBase;

this.description = description;

}


public String getName()

{

return name;

}


public int getMetersFromBase()

{

return metersFromBase;

}


public String getDescription()

{

return description;

}


//-------------------------------------------------------------------------


public static final class Id extends UniqueId<Long>

{

public Id(Long key)

{

super(key);

}

}

}

As you can see I've made good use of Java generics to give us maximum reuse while still maintaining type-safety. I've also declared our type-safe ID as a static inner class of the Marker data object. This just avoids creating a seperate file, keeping things concise. To use this ID we simply use Marker.Id.

We've now covered everything except relationships. Clearly there is a relationship between markers and nests. A nest is always relative to a marker and each marker can have any number of nests near it. We could model this in a number of different ways but the cleanest (in this case) is to just add a marker ID to the nest data object. The Swing client can download all the nests and all the markers and then match them up as needed for display purposes.

The second relationship is the one between a nest and turtle sighting. This is a straight one-to-one mapping. We could in fact model this as one data bean but it's possible that the turtle was not sighted so it is cleaner and easier to model this as a second bundle of information that may be null if the turtle was not sighted.

Again we have several ways we could model this but the simplest is to just put a reference to the turtle sighting bean on the nest bean. The way this data is used in our screens tells us that the nest is the main focus here and that the turtle sighting information will only ever be used as part of the nest.

So, after all that our relationship information is all in the nest data object, which looks a little something like this:
public class Nest extends IdentifiableDataObject<Nest.Id>

{

private Marker.Id markerId;

private int angleFromMarker;

private int centimetersFromMarker;

private String description;

private int eggCount;

private TurtleSighting turtleSighting;


public Nest(Id id,

Marker.Id markerId,

int angleFromMarker,

int centimetersFromMarker,

String description,

int eggCount,

TurtleSighting turtleSighting)

{

super(id);

this.markerId = markerId;

this.angleFromMarker = angleFromMarker;

this.centimetersFromMarker = centimetersFromMarker;

this.description = description;

this.eggCount = eggCount;

this.turtleSighting = turtleSighting;

}


// getters for each property go here


//-------------------------------------------------------------------------


public static final class Id extends UniqueId

{

public Id(Long key)

{

super(key);

}

}

}

Our turtle sighting data object is now really just a component of the nest and is no different to the other String attributes on there. Because this turtle sighting bean is only ever used in the context of a nest we don't even need to create an ID for it.

That's it. Our beans for transferring data between the service layer and the client are complete and ready to use. Now we can look at the seperate issue of how we'll store this information.

0 Comments (Post a Comment)

The Data Dilemma

In every system there are two forces competing for dominance in the data model: how the data is used, and how the data is stored. These two forces always look beguilingly similar at first, but inevitably there is a point of conflict between the two that requires some special attention. This conflict is, in essence, a mismatch between the practical, business requirements of the users and the maintenance and performance concerns of the developers.

Usually this point of conflict centres around how data is related. Each user interaction focuses on a different goal and so in each case the user often needs to work with different relationships. In one scenario it might be more important to focus on how data X is related to data Y. In another, the user may need data X with data Z but only if data Y has a special status. Of course, at the storage level we model all our relationships to be as normalized as possible and to provide us with optimal performance.

Security also plays a part in this little battle. Our sensitive data must never be exposed to the wrong people. We could leave this up to our presentation of course. We could give all the data to the presentation tier and then simply have it choose whether to show the sensitive stuff or not (email addresses for example).

If our communication between middle tier and presentation tier is open to the public though (across the Internet for example), how can we be sure that it's our client that's receiving the data? What if someone hacks the client (a simple decompiler would do the job) and is able to pull that information out of the data we're sending? Far better that we never expose this information in the first place and keep it all securely hidden behind our impenetrable service layer.

This issue is often overlooked these days, especially in web-based systems. Common practice is to simply hand the storage data objects (typically hibernate beans) to the presentation layer (Actions and JSPs). This makes life very easy for everyone but it does ignore the two main issues raised above. It also has design trade-offs since your security logic is now shared between your middle and presentation tiers.

You can get away with this little cheat thanks to the unique structure of a web-based system: the presentation tier actually runs on the server, building up HTML and then pumping this down to the 'thin' client (i.e. the browser). As a result the presentation-tier is highly trusted. Data is transferred between the middle-tier and presentation-tier in the same JVM; nothing is sent across an open network (apart from the processed HTML).

The presentation tier is in effect doing some of our business logic, it is filtering secure data and 'following' relationships as needed (and going directly to the database to do so, even though the magic of hibernate hides this). This works in web-world and the trade-off between ease and correctness is arguably worth considering. This cheat does not however work when you have a pure remote client, one built in Swing for example.

With a 'thick', remote client, the data needs to be transferred across the wire (usually via some form of serialization) and then rebuilt on the client side. The magical lazy-loading of Hibernate no longer works (since the client can not access the database). Security is also a concern. It is difficult and messy to control what information is loaded before the data is sent down to the client.

I have seen attempts to solve this via a request driven, service API. Here, the client effectively tells the server what data it wants loaded when it calls a service. With this you can re-use your database beans and still have security and load only the relationships you want.

I can't say I'm a fan of this approach however. Any simplicity you win by reusing your database beans is paid back with interest by the complexity of the framework needed for requesting data to be loaded. As well as this you now have a loose API. You have methods on your beans that are sometimes valid and sometimes not, depending on what data you asked for. If a property is null, does this mean the data was not loaded or that it doesn't exist. It doesn't take much to imagine the sort of maintenance woes this will cause.

Unfortunately we are left with only one real option: two, distinct data models. Our database model will model the data exactly as it is stored and our service data model will model the data exactly as it is used. This is in fact a solution fairly common to EJB: the Entity beans define the database model and Data Transfer Objects (DTOs) are used to pass information from Session beans to the client.

Often our DTOs will feel very similar to our database beans and we'll have an itch to try and find some reuse. This is only natural, reuse is a concept drummed into us from the moment we write our first object-oriented program. What's important to keep in mind here is that reuse is for things that are reusable in the same way, not things that look the same. Each of these data models has a different use, a different purpose and that's why they need to be different.

0 Comments (Post a Comment)

Interfacing with Users

There's a thousand schools of thought on the best way to do system analysis and design and in the end the choice is a combination of your personal preference and the project needs. I'm a big fan of prototyping and user interface driven design. In my experience nothing beats a few sketches of how the screens will actually look (apart from the actual system, but it's a little late by then) for finding out just what a user does and doesn't need.

For our turtle tracking system we're going to put a simple little Swing GUI on the front so we can put our framework under a healthy amount of strain. Our focus is still our service and data layer at the moment so we're not going to get too hung up on the Swing design at this point.

Looking at our problem it's pretty obvious that we're going to need some way to add and manage the nests in our system. With each nest we'll need to keep track of the turtle information (if the turtle was sighted) and also link the nest back to a marker (which we'll need to set up somewhere as well).

It makes sense to show a summary of each nest in a standard table and it would be helpful to show both marker and turtle information as part of this summary. A screen a little like this would be a reasonable starting point:



(I normally use paper-based sketches as my starting point. If I need screens in a digital format and it's a simple UI then I'll use Word, like I've done here. For complex, poorly understood UI requirements I'll often mock up the screens in Java using a GUI builder).

When we add or edit a nest we'll use a popup with the details in it. A screen like this should do it:



That's about all we need for nest management. You can see that the turtle sighting information has been built into the nest details. The user can select a drop down to say that the turtle was seen (or not) and is then able to enter the turtle data at the same time that they enter the nest information.

Marker's a reused for multiple nests and are typically set up as a one off job at the beginning of the laying season. It makes sense to separate this into a new set of screens that are managed in a separate dialog. This keeps the main UI focused on the day-to-day activities of nest management - marker set-up is a side issue, rarely used.

Our marker screen is going to look a little like this:



When we add or edit a marker we'll use a popup screen like this one:



We've now got a clear picture of what our system needs to do and with that in mind, we can now turn our hands to a little code.

0 Comments (Post a Comment)

Serious Business

Our Dictionary example was useful for getting the basics going but it's too simple to bring out a lot of real issues that we need to deal with. We need a more complex scenario (with some relational data and some business rules) to really fine-tune our design.

Instead of using the traditional pet store example we're going to be a little more eco-friendly and design a system for use in tracking turtles. We'll base the requirements on a turtle conservation project that I worked on in Costa Rica. Though still quite simple, this is a real-world scenario and should give us enough to play around with.

The project tracks the number of turtles that lay nests on a certain strip of beach. Volunteers patrol the beach each night. When a turtle is found laying eggs the volunteers collect, count and then relocate the eggs to a less noticeable location on the beach. This greatly reduces the chance of poachers finding the nests.

At the beginning of the season wooden markers are set up along the beach (at roughly ten meter intervals) and whenever a nest is relocated we take bearings from the nearest marker so that the nest can be found again later to see how many eggs actually hatched.

If the turtle is spotted early enough in the laying process then volunteers take shell measurements and record any distinguishing markings on the turtle. Each turtle may also be tagged with metal identification tags and this is used to identify the turtle throughout the laying season.

Our system needs to track this information. We're going to keep things simple (your typical conservation project can't afford to pay as much as your more vital services such as banking and insurance). We'll capture information about markers and where they're located and we'll track nest and turtle information.

0 Comments (Post a Comment)

Transacting

So far we've avoided the rather ugly issue of transactions in our dictionary application. We'll have to sort these out sooner or later so we may as well face up to them now. Once again, Spring steps in and makes life a little easier for us (though utopia is still a little way off).

One thing I've always hated is transaction boundaries being done in configuration files. I just don't see how this is configuration. Are we going to start a transaction at a method for one installation and not the other? Will we want to rollback under different circumstances because we're using a linux box instead of a windows one?

The transaction is really an extension of the business logic and is intimately linked with the code and the way it works. Putting this logic out to an XML file might seem 'nice' for our poor, malnourished developers, but in my book it's just plain dangerous.

The problem is you either have to leave the code to put your transaction in the XML file (and forget what you were doing in the code) or finish your code and then put the transaction in later (even your most fastidious developer will forget to do this from time to time). You've knocked the compiler out of the game so don't go looking for help there when the shit hits the fan and your transactions aren't doing what you wanted.

Another problem with popular transaction solutions is the complete and unapologetic lack of support for threads. Since the transaction is magically attached to the thread, starting new threads adds a complexity no one's willing to touch. To make transactions work we've had to sacrifice one of the core tools we developers have in our toolbox. (Simple, stateless, web-based applications rarely need real threads, which is why this has been allowed to happen so easily).

What I'd really like is to be able to instantiate a new transaction object in my code, and then have all the code that needs it use that object. That way I'm forced to open my transaction and it's clear which code is using which transactions. The compiler's still in the loop so it can yell at me when I get things wrong. If I want my transaction to be used across threads, I can just pass it through to the new thread and there's no mystery to it all. Even your most unimaginative developer can follow and debug that.

Unfortunately this approach requires us to clean up when we finish. If we don't commit or rollback the object when we're done, we're in all sorts of trouble. Enforcing this aint easy and there's just too many places where you could forget to do it. Not closing a transaction properly is just as bad as forgetting to put it in the XML file in the first place.(As an aside, Spring does give us some callback classes that can solve this but the cost in type safety and code readability just isn't worth it).

There is a halfway solution however that Spring provides, and that's annotations. It's not quite code, not quite config but enough of each to keep us just happy enough. There's still a whole load of room for configuration errors and threads are still an issue (as far as I can see) but at least the transaction declaration is in the same place as the code. We're debugging one spot instead of two and that alone is a major step forward.

Once we commit ourselves to this approach the actual implementation is really pretty easy. The hard part is staying diligent and always remembering to put transaction declarations on as needed. Well-defined conventions and code reviews are probably the only way we can enforce this to any level.

Let's add some transactions to our dictionary example. First we need to decide where to put them. Transaction boundaries really are the responsibility of the service layer (you either fulfil a service request or you don't, there's no half-way measures). While we could span transactions over several service requests it's best just to keep things simple and have each method use it's own transaction. When we're running remotely each call will go across the wire and we don't want to get into the mess of distributed transactions for 99% of our standard applications.

So adding transactional support to our dictionary service is simply a matter of adding annotations like this:

import org.springframework.transaction.annotation.Transactional;


public interface DictionaryService extends Service

{

@Transactional(readOnly=false)

public void addWord(String word, String definition);


@Transactional(readOnly=true)

public String getDefinition(String word);

}


Simple: our retrieval method gets flagged as read-only and our update method is flagged as a write method. By default, Spring will commit the transaction after the method finnishes or rollback if a Runtime exception is thrown.

The catch is that we have to remember to put a transactional wrapper (what Spring calls an 'interceptor') around our service in the Spring XML file. If we forget to do this, we won't get an error and nothing will look wrong until it's a real problem (at which point it's probably too late). Since I can't work out a better way to do this that doesn't have even worse trade-offs, it's just one of those nasties we'll have to live with.

Our transactional service definition now looks like this:

<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="hibernate-session-factory"/>

</bean>


<bean id="dictionary-service"

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

<property name="transactionManager" ref="txManager"/>

<property name="target" ref="dictionary-service-target"/>

<property name="transactionAttributeSource">

<bean class="org.springframework.transaction

.annotation.AnnotationTransactionAttributeSource"/>

</property>

</bean>


<bean id="dictionary-service-target"

class="com.zonski.examples.dictionary.LocalDictionaryService">

<property name="dictionaryEntryDao" ref="dictionary-entry-dao"/>

</bean>


I've just used a plain hibernate transaction manager here (which is basically the same as using a database connection). We can easily configure this to use more complex transaction managers (the part of transactions that should be configurable) should we hit that need in the future.

0 Comments (Post a Comment)

Using the Dictionary

Our dictionary service is now good to go so let's build a client to use it. Since we're still focusing on the data layer and how it's used these are going to be primitive. We're just going to write two little main-method classes to make calls on the service. The first is the WordAdder, which will add words to the dictionary. The second is the WordFinder, which will pull out definitions for specific words.

The code (and mapping files) for the entire dictionary example can be found in the source tree under the examples module.

For our word adder, I've just borrowed a couple of words from dictionary.com's word of the day. The main method on the WordAdder class opens a session with the provider and then adds three words and their definitions. The code looks like this:

public class WordAdder

{

public static void main(String[] args)

{

String contextName = (args.length > 0

? args[0] : "dictionary/dictionary.xml");

ServiceProviderLocator locator

= new SpringServiceProviderLocator(contextName);

ServiceProvider serviceProvider = locator.locateServiceProvider();

Session session = serviceProvider.openSession();


DictionaryService dictionaryService

= (DictionaryService)session.getService("dictionary-service");

dictionaryService.addWord("aficionado",

"an enthusiastic admirer");

dictionaryService.addWord("machination",

"a crafty scheme intended to accomplish some usually evil end.");

dictionaryService.addWord("germane",

"appropriate or fitting; relevant.");


session.close();

}

}


Our WordFinder uses the same service to find a definition for a word and print it out to the screen:

public class WordFinder

{

public static void main(String[] args)

{

String contextName = (args.length > 0

? args[0] : "dictionary/dictionary.xml");

ServiceProviderLocator locator

= new SpringServiceProviderLocator(contextName);

ServiceProvider serviceProvider = locator.locateServiceProvider();

Session session = serviceProvider.openSession();


DictionaryService dictionaryService

= (DictionaryService)session.getService("dictionary-service");

String word = "machination";

String definition = dictionaryService.getDefinition(word);


if (definition != null)

{

System.out.println("The definition of '" + word

+ "' is '" + definition + "'");

}

else

{

System.out.println("'" + word + "' is not in the dictionary");

}


session.close();

}

}



There's nothing pretty about any of this but it serves the purpose. If you run the WordAdder you'll see the three words turn up in your database. The WordFinder will then retrieve the definition from the database as you would expect.

I've not bothered configuring this to run as a remote server since our focus is purely the data layer in this example. Using our service layer API we can code and test without this added complexity and add this in at a later stage without hassle.

0 Comments (Post a Comment)

Spring and Hibernate

Spring uses a nice and (hopefully) familiar DAO (Data Access Object) approach for its interaction with Hibernate. The basic approach is to write a technology indepent DAO interface with methods that define the ways we want to access the database. After that we provide a hibernate specific implementation of this interface. This extends Spring's HibernateDaoSupport, allowing us to use the base methods in this class to make the common data access tasks very simple.

We've allready defined our service interface (see previous post) to allow only two operations: adding words and retrieving definitions. Based on this we can define our DAO interface as follows:

public interface DictionaryEntryDao
{

public void createDictionaryEntry(DictionaryEntry entry);


public DictionaryEntry getDictionaryEntry(String word);

}


Keep in mind that we're just getting things working at this stage. Once we have our approach nailed we'll look at generalising things and putting in support classes and interfaces to reduce the code duplication that will undoubtably occur if we used this simple approach for a large number of DAOs.

For this basic, little DAO the use of Spring and Hibernate make our DAO implementation super simple:

public class HibernateDictionaryEntryDao extends HibernateDaoSupport

implements DictionaryEntryDao

{

public void createDictionaryEntry(DictionaryEntry entry)

{

getHibernateTemplate().save(entry);

}


public DictionaryEntry getDictionaryEntry(String word)

{

return (DictionaryEntry)getHibernateTemplate().get(DictionaryEntry.class, word);

}

}


That's really our data layer done (added with our bean and mapping from file from the last post). Granted this is a trivial example but even so we've gotten out of there without getting our hands dirty at all. Now we can implement our service interface to make use of all this:

public class LocalDictionaryService implements DictionaryService

{

private DictionaryEntryDao dictionaryEntryDao;


public void setDictionaryEntryDao(DictionaryEntryDao dictionaryEntryDao)

{

this.dictionaryEntryDao = dictionaryEntryDao;

}


public void addWord(String word, String definition)

{

DictionaryEntry entry = new DictionaryEntry(word, definition);

this.dictionaryEntryDao.createDictionaryEntry(entry);

}


public String getDefinition(String word)

{

DictionaryEntry entry = this.dictionaryEntryDao.getDictionaryEntry(word);

return (entry != null ? entry.getDefinition() : null);

}

}


Our service implementation really just delegates to our DAO in this trivial example. This area would be more interesting were we to add some business rules in (filtering out swear words for example).

The only thing of note is that this guy is passed the DAO to use via a setter (what Spring, somewhat cryptically, calls 'dependency injenction'). This allows our service to be configured to use a different DAO implementation should we need it to (which is useful for changing data storage strategies and for unit testing).

That's it for the code, now we just need to wire everything together using a Spring XML application context file:

<beans>


<bean id="service-provider"

class="com.zonski.service.local.LocalServiceProvider"/>


<bean id="dictionary-service"

class="com.zonski.examples.dictionary.LocalDictionaryService">

<property name="dictionaryEntryDao" ref="dictionary-entry-dao"/>

</bean>


<bean id="data-source"

class="org.apache.commons.dbcp.BasicDataSource"

destroy-method="close">

<property name="driverClassName" value="org.postgresql.Driver"/>

<property name="url" value="jdbc:postgresql://localhost/devdb"/>

<property name="username" value="dba"/>

<property name="password" value="sql"/>

</bean>


<bean id="hibernate-session-factory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource" ref="data-source"/>

<property name="mappingResources">

<list>

<value>dictionary/dictionaryEntry.hbm.xml</value>

</list>

</property>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.PostgreSQLDialect

</prop>

</props>

</property>

</bean>


<bean id="dictionary-entry-dao"

class="com.zonski.examples.dictionary.HibernateDictionaryEntryDao">

<property name="sessionFactory" ref="hibernate-session-factory"/>

</bean>


</beans>


This is our same context file from earlier but with a few additions for our new database stuff. We've added a data source and a hibernate session factory, this is standard Spring stuff. We've then added our dictionary entry dao and wired this up to use our hibernate session factory. Finally, we've added a property to our dictionary service that links it to the dictionary entry dao.

For a bigger job we'd definitely want to seperate out some of this into a seperate file (in particular the database connection details). Also, there's some tricks Spring has for simplifying the XML files when we have a lot of similar beans. This will do for now though.

0 Comments (Post a Comment)