Auditing, History of database modifications with Hibernate – Envers Solution !

Posted by Martin Cabrera on October 27, 2010

hibernate-logo

Envers is one of the Hibernate’s project sponsored by Redhat. Works with Hibernate and Hibernate Entity Manager.

Aims to enable easy auditing of persistent classes. For each audited entity you must annotate your persistent clases with @Audited, a table will be created, which will hold the history of changes made to the entity.

The idea is very similar to CVS or Subersion. Each transaction with updates, deletes or inserts made in the database with hibernate generate a new revision number. One transaction is one revision.

Envers provide a simple way to retrive your data of a revision using: revision number, date, queries with min and max function between others.

You can use Envers wherever Hibernate works: standalone, inside JBoss AS, with JBoss Seam or Spring.

It’s very easy …

@Entity
@Audited
public class Usuario {
public enum Rol{
EMPRESA, ADMINISTRADOR,MESA_ENTRADA;
}
private Long id;
private String usuario;
private String contrasenia;
private Rol rol;
@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Entity @Audited
public class User {
	private Long id;

        @Id @GeneratedValue
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }

        // other fields and methods
        ...
}

Envers configuration

When configuring your Hibernate (persistence.xml if you are using JPA, hibernate.cfg.xml or other if you are using Hibernate directly), add the following event listeners:

<persistence-unit ...>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>...</class>
<properties>
   <property name="hibernate.dialect" ... />
   <!-- other hibernate properties -->

   <property name="hibernate.ejb.event.post-insert"
             value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />
   <property name="hibernate.ejb.event.post-update"
             value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />
   <property name="hibernate.ejb.event.post-delete"
             value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />
   <property name="hibernate.ejb.event.pre-collection-update"
             value="org.hibernate.envers.event.AuditEventListener" />
   <property name="hibernate.ejb.event.pre-collection-remove"
             value="org.hibernate.envers.event.AuditEventListener" />
   <property name="hibernate.ejb.event.post-collection-recreate"
             value="org.hibernate.envers.event.AuditEventListener" />
</properties>
</persistence-unit>

Then, annotate your persistent class with @Audited (like the User example)

And that’s it!

Queries

Find audited data

You can access the audit (history) of an entity using the AuditReader interface, which you can obtain when having an open EntityManager.

AuditReader reader = AuditReaderFactory.get(entityManager); 
User oldUser = reader.find(User.class, userId, revision)

Search a revision number

the whole documentation is in the Web site:  http://docs.jboss.org/envers/docs/index.html#queries

To ilustrate one example I show the way to search the max number revision of one Entity audited.

Number revision = (Number) reader.createQuery().forRevisionsOfEntity(User.class, false, true)
.addProjection(AuditEntity.revisionNumber().max())
.add(AuditEntity.id().eq(userId))
.getSingleResult();

We use Envers in a few projects. Works fine and very quickly, we recomended … no dubt ! Envers

Web site: www.jboss.org/envers

Envers documentation: http://docs.jboss.org/envers/docs/index.html

JPA @OneToMany – I want a foreign key. I don’t want a Join table

Posted by Ariel Ludueña on October 18, 2010

Suppose you have this two entities: PhoneList and Phone.

PhoneList have a @OneToMany to Phone. (I need only a unidirectional relationship)

Something like:

@OneToMany(cascade=CascadeType.ALmappedBy=”phoneList”)
public List<Phone> getPhones() {
return phones;
@OneToMany(cascade=CascadeType.ALL)
public List<Phone> getPhones() {
   return phones;
}

The phone entity doesn’t have nothing special.

If you deploy those entities your JPA provider will create 3 tables. One table for each entity and also a “JoinTable”. But, why? This kind of relationship can be done by 2 tables only and I don’t want a third table. I want a PHONE table with an FK column to PHONELIST table.

How can I do that?

Two options:

  1. Make your relationship bidirectional
  2. Add an @JoinColumn in the @OneToMany attribute

Option number 1 – Make your relationship bidirectional

The problem is that “I don’t need a bidirectional relationship”! … Ok, but, suppose that you are more interested in solve this and move forward to a “real issue”.

To make this relationship bidirectional, you must add in the Phone entity the reference to the PhoneList entity with the @ManyToOne annotation. Something like:

@Entity
public class Phone {

private Long id;
private String phoneNumber;
private PhoneList phoneList;

@ManyToOne
public PhoneList getPhoneList() {
   return phoneList;
}
...

Also you have to add to the relationship @OneToMany in the PhoneList entity the mapped by attribute. Something like this:

@Entity
public class PhoneList {

	private Long id;
	private String name;
	private String description;
	private List<Phone> phones;

	@Id @GeneratedValue
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@OneToMany(cascade=CascadeType.ALL, mappedBy="phoneList")
	public List<Phone> getPhones() {
		return phones;
	}

Option number 2 – Add @JoinColumn in the @OneToMany attribute

If you don’t want to have a bidirectional relationship, you have to use @JoinColumn like this:

@Entity
public class PhoneList {

	private Long id;
	private String name;
	private String description;
	private List phones;

	@Id @GeneratedValue
	public Long getId() {
	  return id;
	}

	public void setId(Long id) {
          this.id = id;
	}

	@OneToMany(cascade=CascadeType.ALL)
	@JoinColumn(name="phone_list_id", referencedColumnName="id")
        public List getPhones() {
	  return phones;
	}

and the Phone entity remain without references

@Entity
public class Phone {

private Long id;
private String phoneNumber;

...

Fondation Forge and Moove-it play it real

Posted by Gabriela Isnardi on October 18, 2010

fondation-forge-logo

We are proud to announce we have 2 new members in our team. Damian and Nicolas are part of Fondation Forge programs for teenagers. These two bright young programmers are joining our staff after working as interns in our premises.

Our new geek natives...

Please welcome them!

Moove-it and Forge have been working together for 2 years. Among other things Forge provides an opportunity for teenagers to get their first job, and Moove-it supports its values and contributes to make them possible.

The FORGE FOUNDATION is a Swiss established non-profit foundation dedicated to developing and implementing youth work and life skills training programs in nations throughout Latin America.  The foundation began operations in 2006 and now has three training program centers: two in Argentina (Buenos Aires and Pilar) and one in Montevideo, Uruguay

web page of FF: www.fondationforge.org

forge_todos

All you should know about web development

Posted by Juan Pablo on October 15, 2010

I want to share with you a compilation of topics you should know if you are planning on developing a successful web application. This list is just a collection of the best suggestions I read from this discussion on Stack Overflow. All credit goes to all the people who contributed on that thread, I’m just picking the best topics from there.

All the practices mentioned fall into the following categories: Security, Performance, Interface, SEO, Maintenance and Productivity.

Security

This is my favorite topic, if you ask me what is my best advice about security this is it: Never trust user input (that means cookies too!)

Other advices mentioned were…

Performance

Techniques on making our site lighter and faster.

  • Optimize images – don’t use a 20 KB image for a repeating background
  • Learn how to gzip/deflate content
  • Combine/concatenate multiple stylesheets or multiple script files to reduce number of browser connections and improve gzip ability to compress duplications between files
  • Take a look at the Yahoo Exceptional Performance site, lots of great guidelines including improving front-end performance and their YSlow tool. Google page speed is another tool for performance profiling. Both require Firebug installed.
  • Use CSS Image Sprites for small related images like toolbars (see the “minimize http requests” point)
  • Busy web sites should consider splitting components across domains.
  • Static content (ie, images, CSS, JavaScript, and generally content that doesn’t need access to cookies) should go in a separate domain that does not use cookies, because all cookies for a domain and it’s subdomains are sent with every request to the domain and its subdomains. One good option here is to use a Content Delivery Network (CDN).
  • Utilize Google Closure Compiler for JavaScript and other minification tools

Interface

  • Be aware that browsers implement standards inconsistently and make sure your site works reasonably well across all major browsers. At a minimum test against a recent Gecko engine (Firefox), a Webkit engine (Safari, Chrome, and some mobile browsers), your supported IE browsers (take advantage of the Application Compatibility VPC Images), and Opera. Also consider how browsers render your site in different operating systems.
  • Staging: How to deploy updates without affecting your users.
  • Don’t display unfriendly errors directly to the user
  • Don’t put users’ email addresses in plain text as they will get spammed.
  • Build well-considered limits into your site
  • Learn how to do progressive enhancement
  • Always redirect after a POST.

SEO

  • Consider URLs, a URL design with REST in mind could make exposing APIs easier in the future. Definitely much easier to get your URLs right the first time then to change them in the future and deal with the SEO consequences.
  • Avoid links that say “click here”.
  • Use “search engine friendly” URL’s, i.e. use example.com/pages/45-article-title instead of example.com/index.php?page=45
  • Have an XML sitemap
  • Use <link rel=”canonical” … /> when you have multiple URLs that point to the same content
  • Use Google Webmaster Tools and Yahoo Site Explorer
  • Install Google Analytics right at the start
  • Know how robots.txt and search engine spiders work
  • Redirect requests (using 301 Moved Permanently) asking for www.example.com to example.com (or the other way round) to prevent splitting the google ranking between both sites
  • Know that there can be bad behaving spiders out there

Manteinance and Productivity

  • Understand you’ll spend 20% of the time coding and 80% of it maintaining
  • Set up a good error reporting solution
  • Have some system for people to contact you with suggestions and criticism.
  • Document how the application works for future support staff and people performing maintenance
  • Make frequent backups! (And make sure those backups are functional)
  • Don’t forget to do your Unit Testing.
  • Get it looking correct in Firefox first, then Internet Explorer.
  • Code from the beginning with maintainability in mind

I hope you learn something new from this list the same way I did.

Thanks to all the people from Stack Overflow community that contributed in such a rich discussion of web development practices.

We will focus on some of those topics in upcoming posts.

Rails security

Posted by Pablo Ifran on October 14, 2010

When you are working with svn (pulling your project from the svn to the web server) and you want to deploy a system into production with apache (mod_rails), you must filter the svn folders (to prevent that other users view your svn files).

To do that task, you must add the following lines to the apache configuration.


<DirectoryMatch "^/.*/\.svn/">
  ErrorDocument 403 /404.html
  Order allow,deny
  Deny from all
  Satisfy All
</DirectoryMatch>