agimatec-validation implements all features of JSR-303

In its current release 0.9.5, the bean validation framework agimatec-validation, published as open-source on code.google.com/p/agimatec-validation/ implements all features of the JSR-303 bean-validation specification.

This release now fully supports XML-based constraint definitions and all JSR-303 constraint-annotations.

If you download and test this release, we welcome your feedback. If you think you found a bug, you can post an issue at agimatec-validation/issues.

Bookmark and Share

Painless DOM building with mkup

mkup

Creating DOM nodes from Javascript can be painful. The amount of code needed to create nodes and to reference each other as needed is non-acceptable, and the resulting code is far away from being readable or maintainable.

There are some projects out there that try to solve this issue, but their API feels alien inside a Javascript environment because of their declarative nature. So i decided to try to create my own library. The result is mkup, which you can find as open source project at google code: http://code.google.com/p/mkup/.

You can try out all examples listed here inside your browser using the mkup workbench: http://mkup.googlecode.com/svn/trunk/workbench.html.

Design goals

Mkup was written with some things in mind that make a node builder useful.

  • code should reflect what is being built
  • easy access to the nodes created
  • code should be as short as possible

Target one: code should reflect what is being built

This code:

var mkup = Mkup.mkup($('results'));
mkup
  .div()
  .childSpan('note_this')
  .text('Inside Span')
  .write();

creates the following nodes:

<div>
  <span class="note_this">Inside Span</span>
</div>

As you can see calls to mkup are designed to be chained. This removes clutter when specifying what should be done. Of course, chaining is optional, to make using mkup with loops comfortable:

var mkup = Mkup.mkup($('results'));
mkup.ul().child();
for(var i=0; i<3;i++){
    mkup.li().text('Item #'+i);
}
mkup.write();

creates:

<ul>
  <li>Item #0</li>
  <li>Item #1</li>
  <li>Item #2</li>
</ul>

Target two: easy access to nodes created

After building up the nodes you need, getting a reference to one ore more nodes just created is often needed to -for example- change node contents or add listeners. This can be done using mkup:

var mkup = Mkup.mkup($('results'));
mkup
  .div()
  .childA({href:"#"},"link")
  .text("Trigger some fancy stuff");
var createdNodes = mkup.write();
createdNodes.link.observe("click", function(event){
  Event.stop(event);
  alert("Fancy! Wow!");
});

creates:

<div>
  <a href="#">Trigger some fancy stuff</a>
</div>

Target three: code should be as short as possible

Well judge yourself:

Without mkup:

var div = new Element("div");
var link = new Element("a",{href:"#"});
div.appendChild(link);
link.appendChild(document.createTextNode("Link"));
$('results').appendChild(div);

using mkup:

var mkup = Mkup.mkup($('results'));
mkup.div().childA({href:"#"}).text("Link").write();

How to help

If you are interested in mkup, you can help us to improve it:

  • tell us that you use it – because it’s motivating to know that mkup is useful to someone
  • tell the world that you use it – see above
  • run the test suite in your browser and report bugs here – you can find the test page here
  • add a feature – mkup is a small project, so this is your chance to participate in a open source project without a steep learning curve. Checking out the code using subversion is easy and explained here
Bookmark and Share

Auditing and entity versioning based on triggers and hibernate

If you are looking for a framework for auditing the versions and changes of your hibernate objects, you might probably be satisfied with Envers (http://www.jboss.org/envers/), a solution based on hibernate.

In this blog entry I want to give you an impression of an alternative solution by agimatec, that is slightly different. It is the solution we are using in our products for more than two years and with which we are satisfied. It would be interesting to hear your options on this.

The concept

Database:

We generate history tables for each table for which we need auditing. We generate database triggers (oracle or postgres) to automatically insert data in the history tables when entities are stored/deleted.

We do not store duplicate data, which means that our history tables contain only OLD data. All current data is ONLY stored in the application’s tables (usually mapped by hibernate/Ejb3).

Configuration:

We have a XML configuration, that contains the table names for which we want to enable our history solution. This configuration lets you specify:

  • name of history table (or a default name will be used)
  • which columns to exclude from history (default is that all columns are historised)
  • optionally you can turn off history for insert and/or update, change trigger names etc.

The XML configuration controls the tables and triggers generated by freemarker templates.

Features:

It is not only important to version the changes, but also to store, the timestamp of a change and some context information about the change (e.g. who is the actor, which application, from which sessionID etc.). Any context information can be associated with a version record by storing a contextID in the history table’s rows.

This is also a way to separate changes from user-specific data, which might be a judical requirement. An extended Hibernate event handler stores the contextID into the database session by calling a stored procedure, so that the history triggers and access the contextID to store it together with the history data.

Each history table has additional columns:

  • HIST_TIME (timestamp of change)
  • HIST_CONTEXTID (ID of context providing additional information)
  • HIST_TYPE (to distinguish INSERT, UPDATE and DELETION)

A simple java API exists to query historical data. It returns the same classes as you use for your hibernate entities, but it materializes the objects itself. Hibernate does not know anything about the history tables or mappings.

The benefits

There are some differences between the solution provided by Envers and agimatec:

  • Envers needs a global _revision table, agimatec’s history rows are identified by the primary key and a version number (@Version) incremented from 1 for each entity/no global _revision
  • You can change data with any SQL tool.Historisation does not rely on hibernate as the only API to change the database.
  • Whenever you increment a row’s version, the history triggers will automatically write historical data. By this way, you can use migration scripts that can control whether history data will be stored.
  • Envers stores current data in history tables, which makes it a bit easier to query the data, but with means redundancy (and potential data inconsistencies).
  • Both framework are integrated with Hibernate by extending the Hibernate Events (to provide context information).

Examples

History configuration

<historyConfig>
<tableConfig>
<tableName>booking</tableName>
</tableConfig>
<tableConfig>
<tableName>customer</tableName>
<historyTable>h_cust</historyTable>
<insertTrigger>TR_I_cust</insertTrigger>
<updateTrigger>TR_U_cust</updateTrigger>
</tableConfig>

Generated tables

CREATE TABLE H_JOURNAL (
ID INTEGER NOT NULL,
HIST_TABLE VARCHAR(50) NOT NULL,
HIST_TIME TIMESTAMP NOT NULL,
HIST_CONTEXTID VARCHAR(40),
CONSTRAINT H_JOURNAL_PK PRIMARY KEY (ID, HIST_TABLE)
);

CREATE TABLE H_booking (
VERSION INTEGER NOT NULL,
booking_id INTEGER NOT NULL,
price NUMBER,
HIST_TIME TIMESTAMP NOT NULL,
HIST_CONTEXTID VARCHAR(40),
HIST_TYPE CHAR(1) NOT NULL,
CONSTRAINT H_booking_PK PRIMARY KEY (VERSION, booking_id)
);
CREATE TABLE H_cust (
VERSION INTEGER NOT NULL,
cust_id INTEGER NOT NULL,
first_name VARCHAR2(40),
last_name VARCHAR2(40),
HIST_TIME TIMESTAMP NOT NULL,
HIST_CONTEXTID VARCHAR(40),
HIST_TYPE CHAR(1) NOT NULL,
CONSTRAINT H_cust_PK PRIMARY KEY (VERSION, card_id)
);

Generated triggers

CREATE OR REPLACE TRIGGER TR_I_cust
AFTER INSERT ON customer
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
setTATime();
INSERT INTO H_JOURNAL (ID, HIST_TIME, HIST_CONTEXTID, HIST_TABLE)
select :NEW.card_id, h.ts, h_session.getContextId, 'customer' from h_tatime h;
END;
/


CREATE OR REPLACE TRIGGER TR_U_cust
AFTER DELETE OR UPDATE
ON customer
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF(DELETING) THEN
setTATime();
INSERT INTO H_cust (
cust_id,
version,
first_name,
last_name,
HIST_TIME, HIST_CONTEXTID, HIST_TYPE)
select
:OLD.cust_id,
:OLD.version,
:OLD.first_name,
:OLD.last_name,
h.ts, h_session.getContextId, 'D' from h_tatime h;
ELSIF (UPDATING AND :OLD.VERSION != :NEW.VERSION) THEN
setTATime();
INSERT INTO H_cust (
cust_id,
version,
first_name,
last_name,
HIST_TIME, HIST_CONTEXTID, HIST_TYPE)
select
:OLD.cust_id,
:OLD.version,
:OLD.first_name,
:OLD.last_name,
h.ts, h_session.getContextId, 'U' from h_tatime h;
END IF;
END;
/

Java API

The implementation of class HibernateHistoryReader was rather complex, because of the need to resolve the relationships through the current tables and the history tables. All changes done inside a single transaction are joined together by using a timestamp in HIST_TIME that is unique inside the running database transaction.

Here is interface HistoryReader:

interface HistoryReader {

void open(EntityManager entityManager);
void close();


List<EntityRevision> getRevisions(Class entityClass, Object primaryKey, Timeframe timeframe);
EntityRevision getRevision(Class entityClass, Object primaryKey, int version);

Map<Object, List<EntityRevision>> getChildrenRevisions(Class parentEntityClass,EntityRevision parentRevision,String relationship);

<E> HistoryEntity<E> loadEntity(Class<E> entityClass, Object primaryKey,Timestamp time);
<E> List<HistoryEntity<E>> loadChildren(Class parentEntityClass, String relationship,
Object parentPrimaryKey, Timestamp time);

}

Where class HistoryEntity contains the entity instance for a given point of time and some additional information, such as the contextID and the foreignKey values to load some to-one-references.

If you are interested in more details contact us.

Bookmark and Share

Java code of the week…

private void log(String message) {
  Logger log = Logger.getLogger(this.getClass());
  if(log.isDebugEnabled()) {
    if(Thread.currentThread() != null) {
      log.debug(Thread.currentThread().getName()  + ": " +  message);
    } else {
      log.debug(message);
    }
  }
}
Bookmark and Share

Influencing AJAX-GUIs With Metadata

This article explains how to create metadata that we use for scaffolding flexible AJAX GUIs . I keep the text as short as possible by providing a step-by-step cookbook based on code examples.

What you should know:

  • Metadata for scaffoling your GUI (described here). … more
Bookmark and Share

Generate Your UI Using Metadata

The team is small but tasks are legion. Business changes and you have to keep up. And you are doing ajax. You have to keep up.

This is the situation we are in. And here is how we ease the pain: we are generating the user interface.

… more

Bookmark and Share

Dependency Management in Maven done right

whatDespair, anger, perplexity, pain – I think we all know this moments when dealing with large Maven projects. I have seen a lot of posts in the lasts months who use some of this words. After years with Maven we learned how to deal with it. Not the pain, I mean to deal with Maven. I want to share a way to avoid some pitfalls or give you some advices if you are in trouble.

Maven is a good tool to handle your dependencies. You shouldn’t copy the necessary artifacts by hand in your lib folder. It is the beginning of the end for your project. Transitive dependencies could ease the management of your dependencies and Maven is the right tool for this. But sometimes it is to much magic behind the scenes. There could be a lot of transitive dependencies and there could be conflicts. Even more if your projects gets larger and uses more and more open source frameworks. We had problems with two actions:

  • Change the version of a dependency
  • Update the version of Maven

… more

Bookmark and Share

Client-Side Inter Portlet Communication Done Right

gearsUsing portlets, you are able to develop tiny little applications that are suitable for a small subset of the actual functionality your customer wants. By combining them, they make it possible to create powerful but still modular applications that meet exactly the use cases your customer needs help with.

In theory.

In practice, you will be faced with a problem that is obviously a blind spot of the portlet definition (at least, the “old” JSR-186): how to communicate between portlets. The ability to mix-and-match portlets is key to a truly pluggable application formed of portlets.

To solve the communication problem, we have developed a solution much like the one developed by the folks at liferay, but a bit more tuned and optimized for a fully pluggable solution.

… more

Bookmark and Share

I love Oracle!

I execute this SQL with an Oracle 10g database with the latest JDBC driver (Oracle Thin 10.2.0.4).

Can you guess the difference between

select * from dual d where  d.dummy <= ‘X’ /* {} */

and

select * from dual d where  d.dummy <= ‘X’

?

Just a comment? -

Well, the surprise is, that the driver throws

java.lang.NullPointerException  at oracle.jdbc.driver.T4C8Oall.getNumRows(T4C8Oall.java:876)

in the first case that contains the comment and executes the statement correctly in the second case.

Thanks, Oracle!

Bookmark and Share

Javascript Unit Tests with the YUI TestManager

stepsTesting your Javascript is very important. Especially when the amount of code is growing and growing.

The easiest method are unit tests. We have tried several JS unit test frameworks. Including JSUnit, Scriptaculous Unit Test Runner and YUI test. With a lot of YUI components like the YUI Loader and many YUI widgets we refactored our unit tests to use YUI Test. We like the Yahoo User Interface because of its documentation and also of its code quality.

YUI Test is not bundled with YUI. You can use it with YUI but we also use other frameworks like Prototype and DWR. To learn more about YUI Test you can watch the presentation of Nicholas C. Zakas.

Ok, this is great, now I can test my Javascript. But wait, what is if I have a lot of Javascript. I can group my tests in test cases and test cases in test suites. This is supported. But while the amount of Javascript is growing one file for all tests isn’t enough. We have a lot of different modules. Each consists of a lot of test cases. Sure, you can copy them all together in a file which is several thousand lines long. But every test run takes then a lot of time, debugging is more complex and it is more complicated to manage this file.

… more

Bookmark and Share