Tuesday 21 August 2012

HttpSessionListener

A HttpSessionListener is used when you want to be notified that a Session has been created or destroyed.  This simple interface only has two methods,

    void sessionCreated(HttpSessionEvent httpSessionEvent);

    void sessionDestroyed(HttpSessionEvent httpSessionEvent);

These methods can easily be used to get or put items on the new session or perhaps set login, logout times in a log or database.

Web.xml

SessionListeners must be wired into the web.xml in the same way that filters are.  The syntax is very simple though,

    <listener>
        <description>sessionListener</description>
        <listener-class>my.package.MyListener</listener-class>
    </listener>


Getting the HttpSession

The HttpSessionEvent can be used to get the HttpSession itself simply with

    HttpSession session = sessionEvent.getSession();

Spring Integration

Normally there are spring beans that you want to use from within a HttpSessionListener.  However, as the listeners are not wired by spring but sorted out by the container you can't just add the listener to the spring context and expect it to work.  To use other spring beans you need to do the following,


            ApplicationContext ctx = WebApplicationContextUtils
                                              .getWebApplicationContext(session.getServletContext());
            MySpringBean mySpringBean = (MySpringBean) ctx.getBean("beanName");


Chaining

Another option is to create all of HttpSessionListeners and wire them up with spring as normal.  Then create a list of these as a spring bean itself.  Now use the code above to get this list of session listeners and loop through them.  These allows a single HttpSessionListener to bridge the gap to a whole load of listeners wired up by spring.


    <util:list id="sessionListenerChain" value-type="javax.servlet.http.HttpSessionListener">
        <ref bean="firstSessionListener" />
        <ref bean="secondSessionListener" />
    </util:list>


Both 'firstSessionListener' and 'secondSessionListener' are fully wired up using spring in the normally way allowing interaction with the other spring beans.  The actually HttpSessionListener wired into the web.xml file can then call for this util:list and loop through the session listeners to call them.

    List<HttpSessionListener> listenerChain = (List<HttpSessionListener>) ctx.getBean("sessionListenerChain");
    for (HttpSessionListener listener : listenerChain)
    {
        listener.sessionCreated(sessionEvent);
    }

Of course similar code can be used in the sessionDestroyed() method.











Wednesday 8 August 2012

JPA Notes


Here are a series of JPA notes that have been useful in the past.

EntityManager Methods

entityManager.persist() - creates a new object and saves it - will throw an EntityExistsException if it exists already - transaction is rolled back.

entityManager.merge() - will either save or update the current object as it is now!  Changes after this won't be saved.  See below - the merge creates a new object which is managed but the object which merge was called on isn't managed

entityManager.getReference() - gets a reference to the object assuming that it exists.  It does a look up against the @Id annotated field in the entity.  The reference will only exist for the duration of the transaction.  Hence get the data into a DTO before the transaction ends.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated (the changes were made to e2, not e)

JPA Callbacks

There are a number of callback methods in JPA which allow interaction at various points before and after the db save.  These are annotation driven and the names make it pretty clear when they are used.

@PrePersist

@PreUpdate

@PreRemove

@PostLoad

@PostPersist

@PostUpdate

@PostRemove


Annotations

JPA is usually annotation driven.  This provides the information locally to the class and is pretty tidy.  Here are some brief explanations about what the different annotations mean.

@Entity
Flags that an entity should be managed by JPA.  Note Entity exists in JPA and Hibernate so get the import statement right.

@Table
Defines the table that this entity maps to
    @Table(name = "MY_TABLE", schema = "MY_SCHEMA") 

@OneToMany
One of these classes links to many of another class

    @OneToMany(mappedBy = "<java_object_name>", targetEntity = <the_many_class.class>, cascade = CascadeType.ALL, fetch = FetchType.LAZY)

mappedBy shows that the other table is the 'owner' of the foreign key and a @ManyToOne would be expected on that table for a bi-direction relationship.  The mappedBy is only necessary for a bi-directional relationship.  The targetEntity is usually not required because the class variable that this annotation applies to will give this information. If there is only a uni-direction relationship then just a

    @OneToMany
    @JoinColumn(name="column_name")

@ManyToOne
The reverse of the annotation above.  This will allow a bidirection link from the many class back to the one class.
    @ManyToOne(targetEntity = <the_one_class.class>, fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "MY_COLUMN")

@ManyToMany
A join that uses a join table. Bi-directional is still possible using the mappedBy as above.  The owning class (Employee in this case) would have this code.

    @ManyToMany
    @JoinTable(name=EMPLOYEE_TO_PROJECT, joinColumns=@JoinColumn(name="EMPLOYEE_ID"), inverseJoinColumns=@JoinColumn(name="PROJECT_ID"))
    private List<ProjectEntity> projects;

The inverted side of this annotation (Project) would have the following,

    @ManyToMany(mappedBy = "projects")
    private List<EmployeeEntity> employees;

@OneToOne
A link between tables on a 1 : 1 basis.  For the table that has the column foreign key use

    @OneToOne
    @JoinColumn(name = "EMPLOYEE_ID")
    private Person person;

on the non-hosting table (ie without the join column) use

    @OneToOne(mappedBy = "person")
    private Employee employee;
 
@Embeddable
A set of 'columns' which can be in a reusable java class but exist in the underlying table.  Address might be an example of this.

@Embedded
An object which is used in this @Entity but is itself @Embeddable.

@MappedSuperClass
Allows class heirarchy in the Java and maps the contents of this class onto the table of the subclass.  EG map a column which exists on every table in a class annotated with @MappedSuperClass and then subclasses will 'inherit' this column into their table. There is still only one table though.  See @Inheritance for table inheritance. If all columns have an OBJECT_ID, CREATED_DATE then these could go in a class with the @MappedSuperClass and all classes could extend this.

@Inheritance
When a class with @Entity extends another class with @Entity then the @Inheritance rules can be set using this annotation.  The 'strategy' can be JOINED (there are two tables which are 'joined' using the sql request), SINGLE_TABLE (there is a single table a bit like Embedded) or TABLE_PER_CLASS (every table has a complete copy of all the data from the whole hierarchy but every table has that)

@OrderBy
Used on a list to order the elements directly out of the database.  The syntax is @OrderBy("<variable name> ASC").  The variable name is the variable in the objects which make up the list so for example List<Person> personList would have a variable from the Person class.

@PersistenceContext

Using the @PersistenceContext allows spring to wire in the JPA EntityManager to be used within the domain structure.

Create a BaseRepository that includes

    public class BaseRepository
    {

        @PersistenceContext
        private EntityManager entityManager;


        /**
         * Gets the entityManager value.
         * 
         * @return the entityManager
         */
        protected EntityManager getEntityManager()
        {
            return this.entityManager;
        }
    }


Spring will then populate this with the entity manager provided the spring configuration has the following line


    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


A getEntityManager() can be used in the SubClasses to get the entity manager instance.

Query Examples

Get a list of objects from a table,


    public List<MyEntity> getMyEntities()
    {
        final Query query = getEntityManager().createQuery("from MyEntity");
        return query.getResultList();
    }



Get a specific object using a primary key,


    final MyEntity myEntity = getEntityManager().find(MyEntity.class, id);



Use a query with parameters, where name is a provided value and type is an enumeration,


    final Query query = getEntityManager().createQuery("from MyEntity where name = :name and type = :type");
    query.setParameter("name", name);
    query.setParameter("type", MyEntityType.TYPE);
    return query.getResultList();


Creating a query that has a @OneToMany relationship needs a little bit more work.  Here the Company has a list of Products.  It is the products that need to be searched but the companies that need to be returned.  The SELECT only returns the CompanyEntity alias and because this is a @OneToMany the IN(c.products) is used.

    Query query = getEntityManager().createQuery("SELECT c FROM CompanyEntity AS c, IN(c.products) AS p WHERE p.name like :name");
    query.setParameter("name", name);
    return query.getResultList();