Quick Start

Before you start

Go to our download page and download the binary distribution. It's a ZIP file containing:

  • the Marbles JAR file
  • all dependencies are located under /lib
  • the complete API javadoc
  • default Hibernate configuration files located under /config

You must put all jars and the configuration files in your application's classpath. You should also tweak the hibernate.properties file to point to the database you want to use. Tiny Marbles ships with Hypersonic SQL, so you'll need to add the required JDBC drivers if you plan to use other databases.

You might need to read the complete download and installation documentation.

TOP

How to access the repository

You will need one RepositoryFactory instance in your application. We highly recommend that you provide it to your components via Dependency Injection, but you can use a singleton too:

public static final RepositoryFactory factory = RepositoryFactory.createDefault();

The method above creates a Hibernate SessionFactory using the default configuration and a RepositoryFactory that uses it.

Since release 0.9, Tiny Marbles only allows transactional access to the database. This is recommended when dealing with JDBC, and that's what Marbles uses (by using Hibernate). A major difference between ordinary JDBC (or Hibernate) access is that Marbles guarantees successful cleanup. You don't have to worry about possible failures during rollback:

Repository repo = factory.open();
try {
 
  // change something:
  PObject dog = repo.load(dogId);
  dog.set("lastWalk", new DateTime());
 
  // commit now:
  repo.commit();
 
  // update the user interface (represented by the object "ui")
  // We can use lazy loading and everything
  ui.setTitle(dog.get("name"));
  for (PObject friend : (Set<PObject>) obj.get("friends")) {
    ui.addFriend(friend.get("name"));
  }
  repo.close(); // never throws an exception
}
catch (StorageException e) {
  // nothing to do besides notifying the user
  ui.showError(e);
}

Whenever access to Hibernate or the underlying database fails, the Marbles repository automatically discards the transaction and closes the active Session. If an error occurs during commit, an exception is thrown, but the cleanup has already been done.

As you can see above, a commit doesn't close or invalidate the repository. You can proceed showing data, benefitting from lazy loading and the first-level cache, in a transactional environment. You may issue several commits if you see fit. Check out the blog post that discusses it.

TOP

How to describe your data

You will describe your data model at runtime, using the repository. We believe that large-scale components need duck typing and encourage you to do the same: instead of determining the type of an object, you can just check if it has the correct attributes and proceed. Here's the complete documentation on attributes.

Objects in Tiny Marbles are instances of PObject. The data contained in a PObject is described by its PType. The following example creates a type and a new instance of that type in the same unit of work:

Repository repository = factory.open();
PType type = repository.createType("MyType");
  .put("name", PAttribute.STRING)
  .put("weight", PAttribute.INTEGER)
  .put("height", PAttribute.FLOAT);
 
PObject obj = type.newInstance()
  .set("name", "Max Mustermann")
  .set("weight", 70)
  .set("height", 175.3);
 
repository.commit();
repository.close();

After a PObject is persisted, it's given a persistent id that can be used to find it again:

Long objectId = obj.getId();

If you need the persistent Id before the commit() call, you can save an object explicitly:

PObject obj = type.newInstance()
  .set("name", "Max Mustermann")
  .set("weight", 70)
  .set("height", 175.3);
 
obj.save();
 
// returns not null:
Long objectId = obj.getId();
 
repository.commit();
 
// somewhere else later
PObject obj = repository.load(objectId);

The method load() throws an ObjectNotFoundException when the object doesn't exist. If you are looking for an object that might have been deleted, you can use get() instead:

PObject obj = repository.get(objectId);
if (obj != null) {
  // do something
}

If you want your persistent object to have a unique name across the whole repository, you can set its system ID before you save it:

obj.setSystemId("UniqueName");
 
// somewhere else
PObject obj = repository.load("UniqueName");

You can also get() objects using the system ID:

PObject other = repository.get("MightBeThere");
if (other != null) {
  // do something
}

You can also set the persistent ID when you create the object:

PObject obj = type.newInstance("UniqueName");

TOP

How to find objects in the repository

The Repository object provides two kinds of load operation, one with a persistent identifier, another with a System ID that you specify yourself. What if you only know how the object looks like? You can find it with a Filter:

Filter filter = repository.createFilter("MyType");
List<PObject> list = filter.eq("name", "Max Mustermann").list();

Filters work much like Hibernate's Criteria API, where you chain calls that refine the search more and more:

Filter filter = repository.createFilter("MyType")
  .eq("name", argName);
if (startDate != null) {
  filter.after("date", startDate);
}
List<PObject> list = filter.list();

A Filter can also be used to:

  • count the matching elements with Filter.count()
  • search for a unique result with Filter.uniqueResult()
  • delete several objects at once with Filter.delete()

TOP

Please send us comments, questions, criticism:

Please send us comments, questions, criticism!