How to Access the Persistence Layer
From SONIVIS:Wiki
Contents |
Introduction
We currently provide you with a persistence layer based on a MySQL 5.0 database. For accessing that database one may use the interfaces of data access objects (DAOs) in the package de.sonivis.tool.core.datamodel.dao or an implementation of these in the package de.sonivis.tool.core.datamodel.dao.spring.hibernate. There is also a package named de.sonivis.tool.core.datamodel.dao.spring.jpa, an implementation of the Spring framework's data access using the Java Persistence API (JPA). Since the latter is hardly tested we strongly recommend to use the Spring/Hibernate package.
Data Access Objects
As you can see from our data model we have several entities that represent different kinds of data. These entities are
- InfoSpace
- InfoSpaceItem
- Actor
- ContentElement
- Context
- Interaction
- Knowledge
- GraphItem
- Edge
- Graph
- Node
- Property
- InfoSpaceItemProperty
- GraphItemProperty
- InfoSpaceItemType
For each of these entities there is a corresponding class in the package de.sonivis.tool.core.datamodel.hib, also referred to as plain old Java objects (POJOs). These are the data types you will get when you retrieve data from the database via the DAOs. The de.sonivis.tool.core.datamodel.dao.spring.hibernate package provides you with the necessary DAOs named according to the POJOs they retrieve, i.e. ActorDAO.java for Actor objects, EdgeDAO.java for Edge objects, and so on.
Note, though, that InfoSpaceItem.java, GraphItem.java, and Property.java are abstract classes. Therefore, no corresponding DAOs are provided.
Currently, there is no InfoSpaceItemTypeDAO in the de.sonivis.tool.core.datamodel.dao.spring.jpa package.
Retrieved POJOs
You will expect the POJOs you retrieve by accessing the DAOs to be complete and have all their methods work properly. This is currently not exactly the case. You might experience access problems with methods that are supposed to return another POJO, like, i.e. InfoSpaceItemType or the ContentElements of a Context. This is due to the default Hibernate strategy of lazy fetching, in other words, Hibernate tries to access the content of POJOs in fields of other POJOs in the moment they are requested.
But it also depends on the way the DAO methods are implemented: Each one starts, when called, its own session, accesses the persistence layer, and closes that session thereafter. Thus, in the moment of access to a POJO method no session is available to retrieve the expected object and an exception will be thrown. We decided on a non-lazy fetching method for most POJOs that are part of other POJOs. In case of InfoSpace we held on to lazy fetching since accessing the InfoSpace of a POJO would possibly lead to having the whole database extracted.
Basic Access Functionality
For the most common requests on the database the DAOs provide a basic set of access methods. Generally, all classes implement the following methods of the interface IGenericDAO. These represent more or less the equivalents in SQL noted at the end of each line.
| Java | SQL |
Integer count()
| SELECT count(*) FROM T
|
EventList<T> findAll()
| SELECT * FROM T
|
T findBySerial(Long serial)
| SELECT * FROM T WHERE serialID = serial
|
void remove(T)
| DELETE FROM T ...
|
void removeAll(Collection<T>)
| DELETE FROM T ...
|
void save(T)
| INSERT INTO T VALUES ...
|
void saveAll(Collection<T>)
| INSERT INTO T VALUES ...
|
T update(T)
| UPDATE T ...
|
count
To get the amount of all currently persisted entities of a certain type the count() method will suffice. It returns an Integer of the amount which equals 0 if no entities are present. There is also a count() method with a different signature for InfoSpaceItem<code>s.
findAll
To get all entities of a certain type this method will help out. You receive an <code>EventList (visit Glazed Lists Homepage for details) containing all objects that the persistence layer holds. Since you cannot tell the data type of the objects held by the returned EventList you may use the helper method findAllType() which returns the type's class to find out.
findBySerial(Long)
This method allows to retrieve an entity by its database-generated unique identifier. The uniqueness relates to the class as well as to the class hierarchy the class belongs to (Note, not in case of Property).
So, each InfoSpaceItem has a unique serial and you won't find, i.e. an Actor and a ContentElement with the same serial. Therefore, the setter for the serial is private.
Thus, the usefulness of the serial outside the persistence layer is limited. You have to know it in advance to get precisely the entity you expect. On the other hand side, you can persist the same Java object several times leading to clones with different serials.
remove
To delete a persistent entity from the persistence layer use this method. It will not return any information on the state of success of operation but if you encounter exceptions during execution something might have went wrong.
removeAll
If there is need to delete several entities at once that functionality is provided with this method. Alike remove() it returns void.
save
To persist a certain transient object in the persistence layer the save(T) method provided by the correpsonding DAO class is to be used. Note, that this holds for objects that are new to the persistence layer, i.e. transient. Do not try to use this method on an object that was retrieved from the database before, modified then and should be persisted again since this will cause exceptions to be thrown. For this case use the update(T) method described below.
saveAll
To store several transient objects at once one can use this method instead of repeatedly calling save().
update
An object that was retrieved from the database, modified and is to be persisted then should be passed to the update(T) method of the corresponding DAO class. There are good reasons to return the object that was persisted after the operation. Since an ID generation strategy internal to the database is used, the object you receive is not exactly equal to the one you passed as the argument. The returned object will, i.e., provide the generated IDs (serial field) of newly added properties.
Specific Access Functionality
The implementations for DAOs of specific entity classes specify further access methods. In general, these methods provide search on a value of a field of the class. Note though, that there is no necessity to have any meaningful fields in any of the InfoSpaceItem or GraphItem classes since all these could be represented within the properties of the class. For reasons of better handling and faster access we decided to have real fields for certain properties of entities.
Note! All methods that return anEventListcontaining objects of a certain type are accompanied by a no-argument helper method of the same name having Type appended to the method name. The helper methods return the class of the type that is contained in theEventList. I.e.,EventList<ContentElement> findByName(String)andClass<ContentElement> findByNameType()
InfoSpaceItem
All child classes of InfoSpaceItem, i.e. #Actor, #ContentElement, #Context, #Interaction, and #Knowledge, can be searched for the InfoSpace they belong to by calling the method findByInfoSpace(Long) specifying an InfoSpace serial (see #Retrieved POJOs for some details on access to the InfoSpace of an InfoSpaceItem).
Also one can get a collection of entities that share the same InfoSpaceItemType by calling findByInfoSpaceItemType(int) with the appropriate identifier of the InfoSpaceItemType to be looked for.
There is also a special count() method for InfoSpaceItems as mentioned before. Call count(InfoSpaceItemType) to count all entities of the InfoSpaceItem that share the same InfoSpaceItemType. It will return an Integer value >= 0 of the amount of matching entities.
Actor
The Actor entity, as well as the #ContentElement entity, provide the special field:
-
externalId
It is of a Long data type and may (but is not required to) hold the ID the entity had within its source system. It could also contain an individually assigned ID. The method
-
EventList<Actor> findByExternalId(Long)
allows to search for entities matching the value on this field. Note, the return type of findByExternalId(Long) is an EventList. Why so when searching for an ID? Well, the field itself is not required to be unique (not even non-null). Only in conjunction with the InfoSpaceItemType field uniqueness should be taken care of, though it's not enforced yet. To find exactly the entity you are looking for the
-
Actor identifyExternally(Long, InfoSpaceItemType)
will help out and returns the requested object (or null if not existent) identified by its external ID and the InfoSpaceItemType. (Note, the first entity from the internally retrieved list will be picked. If )
Besides these, the DAO implementation provides three more methods for retrieving entities:
-
EventList<Actor> findByName(String) -
EventList<Actor> findRegisteredAfter(Date) -
EventList<Actor> findRegisteredBefore(Date)
The findByName(String) method currently only matches exact name strings. Providing Administrator as argument string will retrieve all currently stored Actor entities with the exactly matching string and will not find names like, i.e., Co-Administrator, administrator, or AdMiNiStRaToR. In SQL this would be something like SELECT * FROM actor WHERE name = 'Administrator'. This might be relaxed in future.
The methods for searching the registered field are inclusive according to the argument. So if you provide a date, i.e., 2007-01-08, 13:55:27, all Actors that registered at exactly 2007-01-08, 13:55:27 will be included.
ContentElement
The ContentElement entities also have the special field
-
externalId
Refer to the #Actor section above for an explanation of the methods connected to it. Further, the following methods are provided:
-
EventList<ContentElement> findByName(String) -
EventList<ContentElement> findCreatedAfter(Date) -
EventList<ContentElement> findCreatedBefore(Date) -
EventList<ContentElement> findCreatedBetween(Date,Date)
As with Actors, the findByName(String) method only retrieves exact matches and the methods searching on the created field are including ContentElements matching the specified date exactly.
Context
The Context DAO implements the following methods:
-
EventList<Context> findSources(Long) -
EventList<Context> findSources(Collection<ContentElement>) -
EventList<Context> findTargets(Long) -
EventList<Context> findTargets(Collection<ContentElement>) -
EventList<Context> findAllRelationships(Long) -
EventList<Context> findAllRelationships(Collection<ContentElement>) -
EventList<Context> findAllUniqueRelationships(Long) -
EventList<Context> findAllUniqueRelationships(Collection<ContentElement>)
The findSources() methods allow you to either specify a ContentElement serial or a collection of ContentElements to retrieve an EventList holding all Contexts with a matching target. The findTargets() do the same with matching sources while findAllRelationships() combine the former two to match the the specified ContentElement(s) against the source as well as the target field. Since two ContentElements may share several Contexts the findAllUniqueRelationships()
retrieves only a single representative for multiple relationships.
Interaction
While a #Context entity represents a relationship between #ContentElements, Interactions represent relations between #Actors. The provided methods are, thus, equivalent:
-
EventList<Interaction> findSources(Long) -
EventList<Interaction> findSources(Collection<Actor>) -
EventList<Interaction> findTargets(Long) -
EventList<Interaction> findTargets(Collection<Actor>) -
EventList<Interaction> findAllRelationships(Long) -
EventList<Interaction> findAllRelationships(Collection<Actor>) -
EventList<Interaction> findAllUniqueRelationships(Long) -
EventList<Interaction> findAllUniqueRelationships(Collection<Actor>)
See #Context for explanations.
Knowledge
The relations between an Actor and a ContentElement are described by Knowledges. The offered DAO methods let you search by either matching Actors or ContentElements:
-
EventList<Knowledge> findByContentElement(Long) -
EventList<Knowledge> findByContentElement(Collection<ContentElement>) -
EventList<Knowledge> findByActor(Long) -
EventList<Knowledge> findByActor(Collection<Actor>)
GraphItem
There are no general methods for searching GraphItems.
Edge
Edges connect two Nodes and may directed or not. To retrieve all directed Edges use findDirected(), to get the undirected use findUndirected(). Uniting both sets leads to the same result as calling findAll().
To get all Edges where a certain Node is part of call findNeighbours(Long) with the Node's serial as argument. For a collection of Edges that point to a certain Node calling findPredecessors(Long) with Node's serial as argument is appropriate whereas findSuccessors(Long) works for Edges where the Node with the specified serial is the source of.
Graph
A GraphDAO implementation provides you with the methods
-
EventList<Graph> findByName(String) -
EventList<Graph> findByInfoSpace(Long).
The argument of findByName(String) must be an exact match of the Graph's name. findByInfoSpace(Long) retrieves a collection of all Graphs that represent the InfoSpace given by the specified serial.
Node
There are no special methods to search for Nodes.
Property
There are two general search methods that apply to child classes of Property:
-
EventList<Property> findByName(String) -
EventList<Property> findByTypeFQN(String)
Both retrieve as collection of items whose name (or fully qualified name, resp.) are exact matches.
GraphItemProperty
A collection of GraphItemPropertys a GraphItem has can be retrieved by calling findByGraphItem(Long) with GraphItem's serial as an argument.
InfoSpaceItemProperty
A collection of InfoSpacePropertys a InfoSpaceItem has can be retrieved by calling findByInfoSpaceItem(Long) with InfoSpaceItem's serial as an argument.
InfoSpaceItemType
You can search for an InfoSpaceItemType by the type's name:
-
EventList<InfoSpaceItemType> findByName(String)
Although that method returns a collection this should usually contain no more than one item.
Direct Access
We decided to use the Spring framework when implementing the access to the persistence layer. It provides a lot of useful functionality on the issues of data access. In the packages implementing the DAOs there is an abstract parent class for all DAO implementations that extends the Spring framework.
Hibernate
The Spring/Hibernate style access to the persistence layer is provided in the de.sonivis.tool.core.datamodel.dao.spring.hibernate package. The abstract parent class of the package is name AbstractGenericDAO.java and extends Spring's HibernateDaoSupport (refer to the API Doc). Using this strategy provides each caller to use the whole functionality therein. One may pose handcrafted SQL statements in standard SQL or the Hibernate Query Languag (HQL) to get the requested data. See the API Doc of HibernateTemplate to check the options.
JPA
The Spring/JPA style access to the persistence layer is provided in the de.sonivis.tool.core.datamodel.dao.spring.jpa package. The abstract parent class of the package is name AbstractGenericDAOImpl.java and extends Spring's JpaDaoSupport (refer to the API Doc). Using this strategy provides each caller to use the whole functionality therein. One may pose handcrafted SQL statements to get the requested data. See the API Doc of JpaTemplate to check the individual options provided within.
Links
- Spring Framework Homepage
- Spring Framework API Doc
- Hibernate Homepage
- Hibernate3 API Javadoc
- MySQL Homepage
- Glazed Lists Homepage

