JPA Entity
Now that we have the client side set up, let's prepare the server side, starting with the JPA entity that will store the data. For this example, I'm going to use just two fields: "key" (primary key) and "value." For those of you relational folks new to GAE/JPA, there is no "table" per se: you declare a JPA "entity," which is a Java class annotated to be persistent. Then, to "insert" a "row," you create a class instance and "persist" it. GAE/J will associate all the class instances together as if they were rows in a table.
Create the below Java class DataItem.java in package com.acme.data (or change as necessary).
package com.acme.data;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity public class DataItem {
@Id String key;
String value;
public DataItem(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
As you can see, this is ridiculously simple. All you had to do to make persistent was to add the @Entity annotation for the class and an @Id to mark "key" as the primary key. You do need to add getters/setters however: making the fields public and directly manipulating them will NOT work! Eclipse can automatically generate getters/setters for you - use Right Click->Source on the Java source.
EntityManagerFactory
Next, we need to create a POJO to do create/read/update/delete on the JPA entity we just declared. The basic steps are as follows:
- Get an EntityManagerFactory instance
- Create an EntityManager
- Get an EntityTransaction (if doing transactional work)
- Do your thing
The first step (get EntityManagerFactory) you want to do through a singleton because the operation is VERY expensive (10-20 seconds is pretty typical). The way AMF works is that it has servlets running on the server listening for requests from Flex RemoteObject (see web.xml in Part II). It is VERY important that you define the scope for these servlets as "application," meaning the servlets start once and will continue to run till the next update (see services-config.xml in Part II). If you set the scope as "session" (or worse, "request"), the servlets will keep restarting, creating EntityManagerFactory afresh, severely reducing the responsiveness.
Create a Java class EMF.java in package com.acme.data with the below code.
package com.acme.data;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class EMF {
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("transactions-optional");
public static EntityManagerFactory get() {
return emf;
}
private EMF() {
}
}
POJO Interface
The final step is to create POJO that GraniteDS will use to access the JPA entities. It's the methods in this POJO that your RemoteObject uses (see createData, readValue, updateValue, and deleteData in the Data.mxml RemoteObject tag in Part II).
package com.acme.data;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
public class Data {
public void createData(String key, String value) {
EntityManager em = EMF.get().createEntityManager();
EntityTransaction tx = em.getTransaction();
DataItem dataItem = new DataItem(key, value);
try {
tx.begin();
em.persist(dataItem);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
em.close();
}
}
public String readValue(String key) {
EntityManager em = EMF.get().createEntityManager();
return em.find(DataItem.class, key).getValue();
}
public void updateValue(String key, String value) {
EntityManager em = EMF.get().createEntityManager();
EntityTransaction tx = em.getTransaction();
DataItem dataItem = em.find(DataItem.class, key);
dataItem.setValue(value);
try {
tx.begin();
em.merge(dataItem);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
em.close();
}
}
public void deleteData(String key) {
EntityManager em = EMF.get().createEntityManager();
EntityTransaction tx = em.getTransaction();
DataItem dataItem = em.find(DataItem.class, key);
try {
tx.begin();
em.remove(dataItem);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
em.close();
}
}
}
There's really nothing to this code, it's quite self-explanatory. I've simplified it to the extent possible, and as you get familiar with the process, you can explore other APIs (like em.createQuery).
BUILD/PUBLISH
The final step is to build and publish to GAE. To build the release version of the Flex app, select the project name in the Eclipse left pane and Right Click->Export->Flex Builder->Release Build. Point "Export to folder" to your war/ directory.
Next, create a GAE app (if you haven't already) and deploy your code by clicking the little GAE logo on the top left in Eclipse (or click on the project name in the left pane and Right Click->Google->Deploy to App Engine). If you don't have GAE Java access (see Part I), this operation will fail with a somewhat cryptic message.
That's it. Open your app with http://yourapp.appspot.com/Data.html and see the magic. If there's no magic, may be I missed something, so please post back here so I can fix it. If there IS magic, please do post comments/opinions. Happy coding!