Gracelets - JPA Extension SourceForge.net Logo
You may want to use a JPA persistence solution but do not want to be forced to use an EJB container to do so. It is now possible to use the JPA Extension to allow one to have entities easily deployed into a JPA persistence session. This persistence session will be an http-session scoped persistence session (scope can be specified) tied to a variable context factory that will produce the session for the scoped variable 'storage'.

Obviously, in order to use this optional extension you would need to add the 'javax.persistence' classes/jar and the implementation of your choice in the general class path or at least the WEB-INF/lib directory so that they can be detected and loaded.

Also, you need to define a file called persistence.properties and place it in the WEB-INF/classes folder. If it is found and provides the correct information as shown below, it will initialize the JPA implementation and load the entities defined in your WEB-INF/classes folder. An example persistence.properties file could be the following:

WEB-INF/classes/persistence.properties
provider.class = org.hibernate.ejb.HibernatePersistence

connection.driver = com.mysql.jdbc.Driver
connection.url = jdbc:mysql://localhost:3306/someDatabase
connection.username = username
connection.password = password

hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.cache.use_query_cache=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider

gracelets.name=myDB
gracelets.scope=conversation
The 'provider.class' and 'connect.' settings are required to initiate the correct JPA implementation. Here we are using hibernates JPA implementation. You can then specify implementation specific settings as shown above as well. Similiar to the hibernate extension, you can specify the scope and name of the entity manager/persistence session. The above config overrides the session scope default and makes the persistence session conversation scope, which means that for each conversation a new session will be opened. Also it overrides the default name for the persistence session (which is "storage") and makes it 'myDB' here.

With this option you can use gracelets inside a standard web server like tomcat and still have easy access to any JPA persistence implementation. Obviously this is simply another option, and you can still use the normal EJB/JPA persistence together with gracelets in a J2EE/JEE environment.

The following is an example of the different method calls you can make on the wrapper object the controls the JPA entity manager:

Toggle Line Numbers
1  
2             // get a list of users 
3             def users = myDB.getResults("SELECT u FROM User u") 
4              
5             // lookup, edit and save a user record 
6             def user = myDB.getSingleResult("SELECT u FROM User u WHERE u.id = :id", id: 1) 
7             user.password = 'newpass' 
8             myDB.merge(user) 
9              
10             // loop through each user, print the usernames and remove ones meeting a certain condition 
11             myDB.eachRow("SELECT u FROM User u") { user -> 
12             print "Username: $user.username" 
13             if (user.username == 'stupidusername') myDB.remove(user) 
14             } 
15              
16             // Create a new user and persist it, you can also call myDB.persist() to force only new save's 
17             def newUser = new User() 
18             newUser.username = 'user' 
19             newUser.password = 'pass' 
20             myDB.persist(newUser) 
21              
22             // Update user records that meet a certain condition 
23             myDB.execute("UPDATE User u SET u.active = false WHERE u.id = :id", id: 2) 
24              
25             // Create a data model to be used with a JSF UIData component 
26             DataModel("userModel") { myDB.model("SELECT u FROM User u") } 
27              
28             // Get native results 
29             def nr = myDB.getNativeResults("select * from some_table") 
30              
31             // Since native results are returned as a List<Object[]> you can 
32             // translate them into a List<Map<String,Object>> by simply using this 
33             // utility method: 
34             def tr = myDB.translate(nr, "fieldName1", "fieldName2", ...) 
35              
36             // Execute a native update 
37             myDB.executeNative("delete from some_table where some_field = ?", someCriteria) 
38              
39             // It can be used as an entity converter 
40             h.selectOneMenu(converter: { myDB }) { 
41             j.selectItems(value: SelectItems("userList") {  
42             myDB.getResultMap("SELECT u FROM User u ORDER BY username", "getUsername") 
43             }) 
44             } 
45              
46             // You can get a navigational, sortable and criteriable data model 
47             DataModel("navUserModel") { myDB.managedQuery("u", "User u", "u.active = true", "").model } 
48