layout | title | repository_name |
---|---|---|
guide |
tapestry-jdo |
tapestry-jdo |
Tested with Tapestry 5.2.x and 5.3.x
- Introduction
- Configuration
- Add dependency on Tapestry-JDO
- Add your JDO implementation
- Configure build to instrument your JDO classes:
- Add your persistence store driver :
- Contribute the PersistenceManagerFactory name to your AppModule:
- Usage
- Inject PersistenceManager into your pages:
- Auto-Commit in your pages
- Configure service transactional behavior
- Use JDO object as page contex
The Tynamo Tapestry-JDO module allows you to work with a JDO3 (http://www.oracle.com/technetwork/java/index-jsp-135919.html) backed persistence layer, similarly to the way you would work w/ a JPA or Hibernate based persistence layer. JDO's main appeal is in its extensive support for ORM into relational databases (e.g. MySQL) as well as non-relational data stores (e.g. MongoDB through Datanucleus MongoDB Support, Google AppEngine JDO API, etc)
In order to have a working configuration, the following are required:
- A dependency on org.tynamo:tapestry-jdo
- A JDO implementation (we use datanucleus in our examples, but others such as Apache JDO should work as well). The implementations typically have some way of integrating the JDO Enhancement process into the build; although not absolutely necessary (e.g. you could probably do that manually after you run your build and before packaging your app), it would probably be a good idea
- A properly configured jdoconfig.xml or persistence.xml
Just adding this dependency will bring transitive dependency on jdo3.
Maven dependency for tapestry-jdo
<!-- tynamo jdo related dependencies -->
<dependency>
<groupId>org.tynamo</groupId>
<artifactId>tapestry-jdo</artifactId>
<version>0.0.2</version>
</dependency>
Add your own dependencies for your JDO implementation if you're using something different:
JDO Implementation Dependencies
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-core</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-api-jdo</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-rdbms</artifactId>
<version>3.1.2</version>
</dependency>
JDO Enhancer Configuration in Maven
<build>
<plugins>
<!--
This plug-in "enhances" your domain model objects (i.e. makes them
persistent for datanucleus)
-->
<plugin>
<groupId>org.datanucleus</groupId>
<artifactId>maven-datanucleus-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<metadataDirectory>target/classes</metadataDirectory>
<metadataIncludes>**/entities/*.class</metadataIncludes>
<verbose>true</verbose>
<enhancerName>ASM</enhancerName>
<api>JDO</api>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-core</artifactId>
<version>3.1.2</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>transaction-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-api-jdo</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-rdbms</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-enhancer</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>
</plugin>
....
</plugins>
</build>
JDBC Driver Dependency
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
Setup your JDO configuration (jdoconfig.xml):
jdoconfig.xml
<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="/web/20150223233548/http://java.sun.com/xml/ns/jdo/jdoconfig"
xmlns:xsi="/web/20150223233548/http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="/web/20150223233548/http://java.sun.com/xml/ns/jdo/jdoconfig">
<!--property name="javax.jdo.option.NontransactionalWrite" value="true"/-->
<persistence-manager-factory name="testapp-pm">
<property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
<property name="javax.jdo.option.RetainValues" value="true"/>
<property name="javax.jdo.option.ConnectionDriverName" value="org.h2.Driver" />
<property name="javax.jdo.option.ConnectionURL" value="jdbc:h2:~/.h2/test-jdo-database" />
<property name="javax.jdo.option.ConnectionUserName" value="" />
<property name="javax.jdo.option.ConnectionPassword" value="" />
<property name="datanucleus.autoCreateSchema" value="true" />
<property name="datanucleus.validateTables" value="false" />
<property name="datanucleus.validateConstraints" value="false" />
</persistence-manager-factory>
</jdoconfig>
Contribute Persistence Manager Factory name
public static void contributeApplicationDefaults(
MappedConfiguration<String, String> configuration) {
configuration.add(JDOSymbols.PMF_NAME, "testapp-pm");
}
Injecting JDO Persistence Manager
import javax.jdo.PersistenceManager
public class Page1 {
@Inject private PersistenceManager pm;
public List<TestEntity> getEntities() {
return (List<TestEntity>) pm.newQuery(TestEntity.class).execute();
}
}
@CommitAfter in pages
import javax.jdo.PersistenceManager;
import org.tynamo.jdo.annotations.CommitAfter;
public class Page2 {
@Inject private PersistenceManager pm
@CommitAfter
public void onActionFromAddEntity() {
TestEntity te = new TestEntity();
te.setValue(new Date().getTime()+"");
pm.makePersistent(te);
}
}
Service transactions
8.3. To add transactional behavior to your own services, instrument them in the module and use @CommitAfter in the interface definition, e.g.
//.. create and annotate a service ...
public interface TestService {
@CommitAfter void addTestEntity();
@CommitAfter void removeTestEntity(long id);
}
//... in AppModule....
@Match("*Service")
public static void adviseTransactions(JDOTransactionAdvisor advisor, MethodAdviceReceiver receiver) {
advisor.addTransactionCommitAdvice(receiver);
}
Classes that use a simple primary key (e.g. Long, String, etc) can be used as an acitvation/passivation context directly
Activate/Passivate
public class Page3 {
@Property
private User user;
@SuppressWarnings("unchecked")
User onPassivate() {
List<User> users = (List<User>) pm.newQuery(User.class).execute();
if (users.isEmpty()) {
return null;
}
return users.get(0);
}
void onActivate(User user) {
this.user = user;
}
}