Most applications involve creating, storing, and searching data in some form; in other words: use a database. This is often called CRUD, for Create, Read, Update, and Delete. Databases are integral parts of almost all computing systems. Well, I have a confession to make: I've been a professional software engineer for close to ten years now and I don't know anything about databases. Sure, I can write a simple SELECT call, but if you ask me to do an double outer join with foreign keys or convert my schema to 18th normal form, I'll simply get lost and give up. I don't know databases. In fact, I hate databases. I'm a client guy. To me, a database is simply a box to store stuff. I don't know how they work and I don't want to know. However, the sad fact of client software today is that as every application gets bigger, it eventually needs a database. From the largest billing system to something as simple as an address book, almost every application needs a database. But this doesn't change the fact that I still hate them. So what are we client developers to do? Here's a idea: why don't we steal some of the server guys' best technology to make our lives easier?
Building on the new features in Java SE 5 (a.k.a. Tiger), the Java Enterprise Edition Enterprise Java Beans 3 spec (hereafter known by the blessedly shorter "EJB3") introduced a new way of communicating with databases called the Java Persistence API (JPA). Though primarily designed for use in big, server-based applications, I will show you how to use JPA to easily load, save, and search for data objects in a simple address book application. In a follow-up article, I will cover advanced object mapping, inheritance, and fetching. Most importantly, you will be able to do all of the database tasks without needing to know SQL, JDBC, or any other traditional database technologies. Let's hear it for the client side!
What Are Java EE Persistence, Hibernate, and Hypersonic?
Before we get into our application, let's take a moment to go over our tools: the Java Persistence API, Hibernate, and Hypersonic.
EJB 3 introduced a new technology spec called the Java Persistence API, which defines a persistence framework. Persistence is a way of automatically mapping normal Java objects to an SQL database. In other words, it loads, searches, and saves your data model objects. Rather than writing cumbersome SQL insert, update, and select commands, the framework will take care of the boilerplate code through some kind of automation. The Java Persistence spec codifies the various persistence frameworks into a single API. This means you can write your application to the spec and know that it will work across several implementations, now and in the future.
Hibernate is an open source implementation of the Java Persistence spec. Though it preceded JPA, and in fact influenced the final design, it has been retrofitted to implement the full spec (along with some extensions that I won't cover here). Hibernate is one of several implementations available, but I have chosen this one because it is complete, mature, and freely available. Much like JDBC, if you stick to the spec and don't use any of Hibernate's extensions, you will be able to switch implementations as your needs change in the future.
HSQLDB, formerly "Hypersonic," is an open source SQL database that stores everything in a couple of files on disk. It has the advantages of being very small, easy to configure, and written entirely in Java. These features make it ideal to embed directly inside of your application: no database server required. Again, in this article we will stick to the database specs and not use any Hypersonic-specific features. This means you could upgrade to a full database server in the future if necessary.
Building Your First Persistable Object
In this article, we will build a simple address book application. The heart of any application is its data model. It is these objects that we want to create, save, and search. For an address book, I want to store people, so I have created the Person object below:
package addressbook;
import javax.persistence.*;
@Entity
public class Person {
@Id @GeneratedValue
public Long id;
public String first;
public String middle;
public String last;
}
As you can see, this is a very simple class. It has three String fields for the first, middle, and last names, along with a Long for the ID. It looks like any normal Java object. In fact, the term most often used with persistence frameworks is POJO, or
"Plain Old Java Object." The only things out of the ordinary for this object are the @Entity and @Id parts. Any symbol in Java code beginning with @ is known as an annotation. The use of annotations is a new language feature introduced in Java SE 5.0 that allows you to add metadata to your objects. Annotations mark parts of your objects so that other systems can do something special with them. In this article we will mark certain fields and classes with persistence annotations so that the Persistence framework will know how to save them.
In the code above, the Person class is marked with the @Entity annotation, which means that it is an EJB entity. Being marked as an entity has a lot of ramifications, but for our purposes it just means that this object can be persisted. Any object you want to stuff in the database must be marked with the @Entity annotation. The @Id annotation says that the id field will be used as the unique identifier for this object. Databases use a special table column called a primary key to distinguish between rows. The @Id annotation marks the id field as the primary key for this object. The @GeneratedValue annotation tells the Persistence framework to generate IDs for us, which is fine, because we don't care what they are as long as they are unique. The @Id annotation has many optional parameters that let you further specify how your primary key works, such as selecting a particular column name or using multiple fields. For our needs, the default behavior is fine.
You may notice that the other fields--first, middle, and last--don't have any annotations. That is because they are using the default annotations that say that the field is persistable as an SQL VARCHAR. As you explore the Java Persistence framework you will discover the JSR expert group did a very good job of defining defaults. This means that you only need to use non-default values when you want to do something out of the ordinary. This design choice, part of the overhaul in Java EE 5, makes persistence very easy to use for non-server developers.
Setting Up Your Project
Combining JPA, Hibernate, and Hypersonic requires a lot of .jars. If you want to build your own workspace, you must first go to the Hibernate website and download the Hibernate Core, Hibernate Annotations, and Hibernate Entity Manager .zip files. Be sure you download version 3.2cr2 or newer of the Hibernate Core file, because older versions won't work with annotations. Unpack them and put all of the .jars into your classpath (I typically put them in a lib subdirectory).
There are a lot of .jars and not all of them are needed, depending on what you are doing, so I recommend using them all during development and then removing the ones you don't need when you get to deployment. The only one you should need in your compile-time classpath is ejb3-persistence.jar. The rest are for runtime use. Hibernate contains a lib/README.txt file with more details on the library requirements. You will also need the HSQLDB database in the form of the hsqldb.jar file.
A quick note on library versions: the Hibernate Persistence implementation has been undergoing changes as the EJB 3 spec moves towards final ratification. Because of these changes, some versions of the Hibernate Core .jars don't work with some versions of the Annotations and Entity Manager .jars. When writing this series of articles, I found a few occasional NoSuchMethodErrors, indicating a version mismatch. I recommend downloading all versions of the modules that were released on the same day. For this article I used the versions released on March 27th, 2006. These are Hibernate Core v 3.2.0.cr1, Annotations v 3.1beta9, and Entity Manager v 3.1beta7. Until the changes settle down, I recommend staying with these versions. I have found them to work flawlessly.
Now that you have a persistable object, the big question is: how do you persist it? This is where the EntityManager comes in. Each implementation of the Persistence API will have its own ways of connecting to a database and managing the objects, but as long as you don't use any implementation-specific extensions, you can stick to the official interfaces. The EntityManager keeps track of your objects and allows you to save, load, and search them at will. Like many Java APIs, Persistence uses a factory pattern, so that's where we will start. Here is a typical test application:
package addressbook;
import javax.persistence.*;
public class Main {
EntityManagerFactory factory;
EntityManager manager;
public void init() {
factory = Persistence.createEntityManagerFactory("sample");
manager = factory.createEntityManager();
}
To use persistence, you must first create an EntityManagerFactory using the static Persistence.createEntityManagerFactory() method. Notice the string "sample" passed to the method. This is the persistence unit you will be using, which must match the configuration in the persistence.xml file that we will get to later. Once you have a factory, you can get an EntityManager with the createEntityManager() method. In general, you should have one factory per application and one manager per user, usually handed out and managed by your application container. This is because the factory is thread-safe and the manager is not. However, these constraints were designed with web server applications in mind. For a desktop app where there is only person using it you can simply save the references and use them as you need. Just remember that the EntityManager isn't thread-safe, so be sure to do all of your persistence on the same thread or use multiple EntityManagers.
Once you have finished your persistence operations you can shut down the manager and factory with their respective close methods.
private void shutdown() {
manager.close();
factory.close();
}
public static void main(String[] args) {
// TODO code application logic here
Main main = new Main();
main.init();
try {
// do some persistence stuff
} catch (RuntimeException ex) {
ex.printStackTrace();
} finally {
main.shutdown();
}
}
}
Above, you can see the main() method which creates a Main object, initializes the persistence system, does some work, and then calls shutdown() in a finally block. This simple Main class encapsulates the typical lifecycle of an application that uses persistence.
Now that the persistence system is set up, we can finally persist some objects! You just need to create a transaction, create your objects, and then save them.
private void create() {
System.out.println("creating two people");
EntityTransaction tx = manager.getTransaction();
tx.begin();
try {
Person person = new Person();
person.first = "Joshua";
person.middle = "Michael";
person.last = "Marinacci";
manager.persist(person);
Person sister = new Person();
sister.first = "Rachel";
sister.middle = "Suzanne";
sister.last = "Hill";
manager.persist(sister);
tx.commit();
} catch (Exception ex) {
tx.rollback();
}
System.out.println("created two people");
}
Transactions are pretty much required with persistence because you are talking to a database underneath. You will usually create a transaction with manager.getTransaction(), call tx.begin(), and then do all of your work. The code above calls manager.persist() to save the new objects, but this could easily be calls to load, search, or update objects as well. Once finished you must call tx.commit() to make the changes permanent. Notice that the calls are wrapped in try/catch blocks. This is so you can rollback the transaction if anything goes wrong, leaving your database in a consistent state.
Database Configuration
There is one final piece of the puzzle before you can start saving objects. The entire persistence stack is configured with a persistence.xml file. This file lists the classes you want to persist, the database connection, and any properties that are specific to the Persistence implementation (Hibernate, in this case). Once you are set up, this XML file will be the only thing you need to modify if you change or move your database. This feature underlies the power of the Java Persistence API and makes the transition from developer database to big Oracle server quite easy. Here's what the persistence.xml file looks like:
In the file above, the first thing you should notice is the name attribute of the persistence-unit element. It doesn't matter what this name is, as long as it matches the string passed into the Persistence.createEntityManagerFactory() method. Again, this API was designed to support advanced uses like multiple persistence stores and databases. Since this is uncommon for desktop apps, I recommend just using one name and never changing it. The persistence.xml file must be in the META-INF directory of your application .jar. If you are using NetBeans, you can put it in a META-INF directory of your src directory and let NetBeans copy it to the right place during compilation.
Finally we are ready to crank up the database and start saving objects. Hypersonic is contained in a single .jar, hsqldb.jar, and you can start it with all of the default settings right from the command line.
java -classpath lib/hsqldb.jar org.hsqldb.Server
This will start an instance of Hypersonic on its default port with the database stored in the test.* files placed in the current working directory. Using the defaults is convenient for testing because you can remove the data by just deleting the created test.* files when you are done.
If you compile and run the Main class, and have the database started in another window, then you should get a lot of output from Hibernate followed by the two lines:
creating two people
created two people
Congratulations! You've just persisted your first objects. After you get the initial setup done, you'll discover how easy it is to store and retrieve your objects. You'll never need to write SQL again.
Executing a Query
Now that we can save our objects it would be nice to load them back up. You can do this with a simplified SQL-ish syntax called EJB3-QL. It lets you perform simple queries into the persistence store, much like SQL, except that instead of returning ResultSets, it will return Lists of your data objects. Below is a simple search function.
private void search() {
EntityTransaction tx = manager.getTransaction();
tx.begin();
System.out.println("searching for people");
Query query = manager.createQuery("select p from Person p");
List<Person> results = (List<Person>)query.getResultList();
for(Person p : results) {
System.out.println("got a person: " + p.first + " " + p.last);
}
System.out.println("done searching for people");
tx.commit();
}
The query itself is generated by the manager.createQuery("select p from Person p") call. This is the simplest possible query. It will return all instances of the Person class. You could fully qualify the Person class as addressbook.Person, but this isn't necessary because the Persistence engine will use the unqualified classname by default. Once you have created a query, you can execute it with query.getResultList(). The code above places the query inside of a transaction, just like the create() method did earlier in this article.
The EJB3-QL language is case-insensitive except for the Java class and method names, so select is equivalent to SeLeCt. It supports most of the usual SQL select features, such as where clauses. For example, if I wanted to search for just Persons with the first name of Joshua I could use the query: select p from Person p where p.first='Joshua'. The EJB3-QL language is powerful enough to perform most of the complicated things you could do with real SQL, like inner and outer joins, but I find that to be unnecessary for most client applications. I prefer to do simple where searches and then do any extra refinement in Java code.
Starting the Database from Within Your Application
Now that the program can load and save objects, it would be nice to have the database bundled with the application. We can't expect our users to manually start Hypersonic in another window. Fortunately Hypersonic was designed to run in-process, so this is quite easy.
Before you create the EntityManager you must start Hypersonic by obtaining a database Connection object like this:
public static void main(String[] args) throws Exception {
// start hypersonic
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Connection c = DriverManager.getConnection(
"jdbc:hsqldb:file:test", "sa", "");
// start persistence
Main main = new Main();
main.init();
// rest of the program....
Then, just before your program ends, you must shut down Hypersonic with an SQL SHUTDOWN command like this:
Also, since you have now changed the database configuration, you'll need to update your persistence.xml file, specifically changing the connection URL property from this:
With those few changes, the database will start up inside of your application, save all data to the test.* files, and shut down when your application ends. Hypersonic is a simple and compact way to store all of your application in a real database without your users ever knowing.
Conclusion
The Java Persistence API was designed as a simple way to load and save your data objects without using any SQL at all. Since it was also designed to be implementation independent, you can change your database or persistence provider as your needs change and not worry about anything breaking. Though Java Persistence was originally designed for server tasks, it performs beautifully in client applications, letting client-side developers spend less time on storage and more time on what they are good at: building killer GUIs.
Join me in a few weeks a follow-up article in which we explore advanced persistence features like constraints, customized properties, subclasses, and managing entire graphs of objects at once.
Do you see a role for the Java Persistence API in your desktop development?
Showing messages 1 through 46 of 46.
dynamic standalone data file
2007-09-13 21:03:20 barbagus
[Reply | View]
Does anybody knows how to implement this exemple but with a runtime defined filename for the database storage. As the file name is set "staticly" in the persistence.xml and for I'm a total newbee in persistence.
Well actually I'm quite a newbee in Java too, and the idee would be for an application to store the client data base in the .myapp directory in the user's home. (or equivalent under windows)
Very usefull article !
Thanks
underlying connection?
2007-01-25 17:25:26 zarar
[Reply | View]
How do you get the underlying connection from an EntityManager? Also, what if you want to use stored procedures? The StoredProcedureCall doesn't seem to be included with toplink-essentials.jar. Do you know how to call a stored procedure using Java Persistence API?
Transaction Not Active
2006-07-29 00:16:03 lbois
[Reply | View]
Great article...
I worked with Derby on Netbeans
I include the code in a Junit test to run outside the container (from my IDE)
But with Hibernate, i get an exception, when commit()
IllegalStateException : Transaction is not Active
I refined the project with TopLink Essentials (Netbeans / Derby):
I have not the error, like for Hibernate, all seems ok.
But then when i do a SQL query against derby, i do not find any records in my table Person.
Any idea?
Transaction Not Active
2007-05-09 07:50:04 mich_barsinai
[Reply | View]
Make sure you call
tx.begin();
Before calling
tx.commit();
first is an invalid name
2006-07-03 11:07:35 gcaro
[Reply | View]
When running the example with derby and eclipse it rejects the creation of the table because of the name 'first', it´s invalid.
I changed 'first' for pape (is spanish) and it works OK
By the way, nice example.
Getting this working on Derby with Netbeans
2006-07-18 00:01:19 rickcarson
[Reply | View]
Hi Joshua. Interesting article.
I noted that an earlier poster tried this in Derby and couldn't get first to work. I also got this working in Derby but it took a bit of jumping through hoops so I'm going to detail the steps I took in case it helps someone else. :D
But before I do - it may be worth noting that rather than changing Person.java as I and the previous poster did, the 'zen' of EE 5 is to probably change the column it maps to via the Annotation (though there is a certain elegance to letting the db pick up and run with a default column name as well...)
So here's what I did:
Type in classes as per example.
Fiddle the persistence.xml
I put the Toplink essentials jar in my classpath.
Got a strange exception.
Suspected something was wrong with my persistence.xml. Moved it out of my project directory entirely.
Still got same error.
Read the article more carefully. Ahha! It has to go in the META-INF directory. *blushes*.
Run it again, this time I get a bunch of output about how it is going to do the mapping... looking good so far... and I get a whopping big error which boils down to:
Configuration error. Class [org.apache.derby.jdbc.ClientDriver] not found.
Oops. Try to find this class on my system. No dice.
Go and download the Derby zip from the apache site. Unpack the zip and slap the jars which start with Derby (as prime suspects) on my classpath.
Great, we have fluffy dice.
Oh wait, what is this? Derby is not running? Umm... fire up Netbeans and run it through the runtime console (not sure if this is cheating).
Fantastic, now it complains about FIRST in the SQL statement. No problem, fix the class... and we are good to go, tables and data show up in the Netbeans inspector.
*phew*
NB: much fiddling with the persistence.xml ommitted for the sake of brevity.
For reference, here is the persistence.xml file I ended up using:
(oh darn, there is no preview... this is gonna look bad)
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="sample" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<class>addressbook.Person</class>
<properties>
<property name="toplink.jdbc.user" value="****"/>
<property name="toplink.jdbc.password" value="****"/>
<property name="toplink.jdbc.url" value="jdbc:derby://localhost:1527/sample"/>
<property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Getting this working on Derby with Netbeans
2006-07-18 08:11:52 joshy
[Reply | View]
This is great Rick. Thank's for posting this. I've requoted the config below in a pre tag:
No Persistence provider for EntityManager named sample
2006-06-13 17:18:15 szermierz
[Reply | View]
I have a problem running the example :
Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named sample
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:41)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:27)
at addressbook.Main.init(Main.java:35)
at addressbook.Main.main(Main.java:89)
Any advice anyone?
No Persistence provider for EntityManager named sample
2007-12-19 06:22:35 ingle_sharad
[Reply | View]
add this tag <provider>org.hibernate.ejb.HibernatePersistence</provider> in your persistence.xml .Finally copy persistence.xml in META-INF folder. It will work .
No Persistence provider for EntityManager named sample
2007-03-26 09:04:03 kishorepr
[Reply | View]
I had a similar problem while I was running in a stand-alone application. I resolved it by ensuring that the classpath is set correctly and persistence.xml file must be placed in the META-INF folder ONLY. One more check is to ensure that the provider tag in the persistence.xml file is accurate. I had used oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.
No Persistence provider for EntityManager named sample
2007-02-17 07:38:49 javamouse
[Reply | View]
I too have this problem - but only on my mac. On my PC... no issues.
Any resolution?
No Persistence provider for EntityManager named sample
2006-06-30 19:42:28 gcaro
[Reply | View]
Are you working with Eclipse ? I use it,I needed to build the META-INF/persistence.xml on the src directory, when I compile, Eclipse copies it to bin/, and suddenly, it works!
I hope it helps
No Persistence provider for EntityManager named sample
2006-06-13 18:35:32 joshy
[Reply | View]
Hmm. Could you tell me what is in your lib directory?
No Persistence provider for EntityManager named sample
2006-06-13 19:53:58 szermierz
[Reply | View]
No Persistence provider for EntityManager named sample
2007-12-19 06:10:52 ingle_sharad
[Reply | View]
Add this tag <provider>org.hibernate.ejb.HibernatePersistence</provider> in your persistence.xml .Finally copy persistence.xml in META-INF folder. It will work .
No Persistence provider for EntityManager named sample
2006-06-14 21:13:02 joshy
[Reply | View]
That all looks right. Could you download the full project zip here with all of the jars included and tell me if you can run that. Then we'll know if there's something missing. Thanks.
I'd use liteweight solution
2006-05-29 01:17:39 herkules
[Reply | View]
on the client side, I'd try to avoid all that hibernate/rdbms hassle at all cost and head for zero-effort solutions like db4o. Not only is it by far easier to use and to maintain, it also is quite a lot faster.
Not trying to nit pick but I've been jumping on folks on my team that catch exception or catch runtime exception.
</P>
The only 'exception' I make, :-)
is for main() to just do a throws there if you don't plan on doing anything with it.
In Effective Java and my Checkstyle rules they all tell me this is a bad thing. Am I missing something?
Well, yes and no. Realistically what can the application do at this point if persistence fails? Whether it's a DB/persistence exception or something general like a null pointer exception the app will pretty much do the same thing. I think it's probably best to throw a new exception (wrapping the old one) that the app can handle in some what that makes sense to the user. If the app really can do something different depending on the error then it can still check the wrapped exception. If not it can print a message to the user explaining what happened.
Fantastic - but what about eclipse ?
2006-05-26 11:52:51 luggypm
[Reply | View]
Great article and has encouraged me to look at hibernate again. But where does the persistence.xml file go in an eclipse project and how to you get hibernate to see it ?
Fantastic - but what about eclipse ?
2006-05-26 19:47:16 joshy
[Reply | View]
It needs to go in the META-INF directory of your application jar. You can use whatever mechanism Eclipse provides to get it there. (ant scripts?).
Well, if it supported the JPA then I would say 'go right ahead'. But, what this article is about is using the Sun api for handling persistence and not worrying about the implementation (hibernate/jdo or whatever). The idea here is to use an abstraction so that you are not tied to a specific vendor's implementation.
I like Prevayler as well, but if you want to store 200MB of data without using 200MB of memory then Prevayler is not your solution. Also, while Prevayler can be very fast indeed, it typically requires you to use actual code to craft every query or update you intend to do. There's no SQL to formulate a filtering of a complicated multiple object relationship.
Relational databases have their place just as Prevayler does.
Great article!
2006-05-25 08:25:29 evickroy
[Reply | View]
Thanks for the article Josh. It's great news that we'll finally get all of the pieces aligned to make CRUD development easier for the desktop. I wonder if someday the JTA and Persistance API might migrate to Java SE so that EE isn't required for this? It would seem to make sense.
I'm looking forward to the next one.
Thanks again
Erik
Great article!
2006-05-25 13:16:04 joshy
[Reply | View]
EE isn't actually required. The designed the Persistence API so that a persistence engine can run outside of an EJB container. You do need some required API and impl jars though. As this becomes more popular I'm hoping that Hibernate will slim down their implementation. There seems to be a lot of extraneous jars that are only mildly used. Another possibility is to switch to JavaDB/Derby and the new persistence impl that comes with Glassfish (I forget the name). I've heard with pack200 you can get the jars down under 2megs, which is alot smaller than most desktop apps. I'll post more on it as I research other alternatives.
Great article!
2006-05-25 11:35:00 dog
[Reply | View]
Yes this is a great article because:
It's simple and short (even though I'm sure most readers know what a primary key is)
It shows the virtues of hybernate (which I've never had time to work with)
It shows the virtues of the new API
It seems like code that could actually maybe work
Great article!
2006-05-25 15:46:23 evickroy
[Reply | View]
Two things.
If switching to the persistence impl that comes with GlassFish, would we then have a dependency on GlassFish?
One problem with Hibernate in the past was that you weren't gauranteed when the transaction was committed after issuing a commit. Do you know if this has changed?
Great article!
2006-05-25 15:50:31 joshy
[Reply | View]
I believe you can pull out the jars you want from GlassFish. No matter what implementation you choose you'll have some jars to add to your classpath, but it will be entirely under your control. It also opens the possibility of someone creating a desktop targeted implementation that's very slim and lightweight.
Great article!
2006-05-25 13:18:08 joshy
[Reply | View]
Thanks. Part 2 is coming soon which will show a full address book application and more complicated mapping. If this pair of articles gets a good response (which it seems like it will) then I'll consider doing a session at JavaOne next year on it. I'm also considering building a more ambitious application to use it. Hibernate provides Lucene integration for even more powerful searching.
I'm currently involved in a free time project which will work with hibernate and HSQL (maybe later on switching to H2, depending on performance tests to be made once evrything works). I've done quite some online investigation, creating little test applications, printing out the handbook and some tutorials. Right now I'm pretty much at the beginning, trying to define my data objects (domain layer), getting them hooked up with hibernate and keeping my fingers crossed that I won't have to refactor too much as I don't know yet how easy or hard it will be to rewrite the mappings and get the test data changed.. it'll remain a white spot on my map
At work I currently have to deal with another situation. I'm developing client applications hooked up to our web apps via XML-RPC. By now I only had to read data out of our web app's database but currently I'm working on a client which will act as most db client apps, only with the difference that I can't access it via JDBC but will have to use XML-RPC. There are so many persistence frameworks / ORMs out there, but I just can't seem to find something that is not focussed on working with JDBC or (XML) flat files. I'm now at a point where I feel forced to do my own persistence framework. Armed with a printout of Scott Ambler's "The Design of a Robust Persistence Layer For Relational Databases" I'll see what I can do and hope I'll achieve something right before the my boss ripps off my head because of the delay.
I just wanted to remind you and other readers, that there may be more to 'persistence' than what's currently coverred in magazines and blogs. Hibernate, all those JDO implementations and others come from the server side and only work with direct JDBC access, which you may not get everywhere as security policies may forbid the related database ports to be opened in firewalls.
I'd be thankful for every tip someone can give me on how to do persistence with XML-RPC / webservices.
So clearly Java Persistence only addresses part of the problem. For a networked application (rather than a local storage app like iTunes or an AddressBook) you can't give the application direct access to the database. Even if you used a secure connection and obfuscated classfiles someone could eventually hack into your server. I discussed this issue with a friend of mine who's a server side developer and he recommends transferring my domain objects over the wire with SOAP and then using Persistence on the server side. The advantage here is that you can reuse your annotated data model objects on both sides and still have the security of server side validation. I plan to do another article in the future as I work out the details.
I should have mentioned, that on our server side things are implemented in PHP for historical reasons. So reuse of my domain objects isn't an option. Real life doesn't like it the easy way ;)
I'd be very cautious about trying to do a grand persistence engine that abstracts the difference between JDBC, XML-rpc, soap, etc etc. You'll get the product out the door much faster if you just admit what your data access technology is and write straight to it. EJB3, Hibernate and JDO are all targeted at persisting to the database. XML-RPC has nothing directly to do with persistence, just with passing messages to the backend. Two different domains.
I'd definitely recommend splitting your data access logic out from the rest of your application, such that changing the data access logic from JDBC/EJB3/JDO to XML-RPC/SOAP/other doesn't affect any of the rest of your application. This doesn't mean a grand unifying framework, it just means a simple "persist(Object bean)" sort of interface into which the rest of the application calls
It should take a few hours to get this kind of interface down, for the 80% case. Spending a few months to a year on a grand framework is going to lead nowhere fast.
Thank you for your feedback, Richard. It just seemed a bit odd to me that noone seems to have addressed this particular scenario before. There are plenty of rich client/server solutions out there, so I expected to find at least some frameworks or more information about how to build one.
I usually hold my data in some models, most of them derived from TreeModel, TableModel and TreeTableModel. The approach I'm currently evaluating is to plug in a persistence mechanism via an appropriate ModelListener. Right now this seems to be the most primising and easiest way, although I had hoped to be able to create a more general solution. Well, time is precious...
you are wrong in assuming that no one has addressed this scenario before. However, in the end the prevailing conclusion is that the relational model (which is mirrored in the JDBC API) is so rich and important that it warrants its own access methodology and a direct and dedicated mapping to the java language.
Moreover, I dont understand why you refer to XML-RPC as "persisting" something. As the name says, XML-RPC is about remote procedure calls, not persistence.
I'm not meaning that XML-RPC is a persistence mechanism. I am aware of that it's just a transport layer, but it's the vehicle I have to use to connect our clients to the data source and unfortunately all the solutions around have been made with JDBC connectivity in mind.
I have hoped for some some framwork delivering an API which I can use in my clients and implements certain common functions, but which allows me to implement commication to 'the other side' by myself.