Unfortunately, there are no downloads available yet.
After an imaginary download, you would have opencabinet.jar which you can add to the classpath of your Java program, and a simple command-line utility to create the database tables that OpenCabinet needs.
OpenCabinet offers a couple of Java classes (mostly collection types) that you have to use when you want to store data in OpenCabinet. Each of these classes maps to a database table.
Continuing the bug database example, let us see how OpenCabinet's data types can be used.
| Field | Type | Remarks |
| bug_id | int | The bug ID |
| bug_severity | varchar(64) | The bug severity level |
| bug_status | varchar(64) | The bug's status |
| product_id | int | Foreign key into products table |
| assigned_to | ? | The current owners of the bug (user account numbers) |
| reporter | int | The user who reported this (user account number) |
| creation_ts | datetime | The time of the bug's creation. |
| description | text | The bug report and follow-up discussions |
For assigned_to we want to store a set of account numbers. We will use the OpenCabinet collection type IntegerSet, which implements the Java Set<Integer> interface.
While we are at it, let us also replace the varchar fields bug_severity, bug_status, and the numeric product_id with IdStrings.
An IdString is a short (up to 400 characters), non-empty string type that is especially userful for keys or ids that come from a limited set of options.
The contents of these data types are stored in separate tables that are being managed by OpenCabinet. To refer to them, every piece of data is assigned an integer id, which you can then store in your original database table.
| Field | Type | Remarks |
| bug_id | int | The bug ID |
| bug_severity | int (IdString) | The bug severity level |
| bug_status | int (IdString) | The bug's status |
| product_id | int (IdString) | Foreign key into products table |
| assigned_to | int (IntegerSet) | The current owners of the bug (user account numbers) |
| reporter | int | The user who reported this (user account number) |
| creation_ts | datetime | The time of the bug's creation. |
| description | text | The bug report and follow-up discussions |
The data associated with a given integer id never changes. Furthermore, if you save the same data twice, you will get the same id (and the data will actually be only stored once).
QueryRunner q = new QueryRunner(dataSource);
In this (and all other code examples), we will use the popular Apache Commons DbUtils library instead of the raw JDBC API, because raw JDBC is too painful to write and look at. You can use OpenCabinet without DbUtils, though.
// without cache CabinetManager cabMan = new DatabaseCabinetManager(dataSource);
All interaction with OpenCabinet is done via a CabinetManager. The example above creates one using a JDBC DataSource.
// with cache CabinetManager cabMan = new DatabaseCabinetManager(dataSource, 100);
Since the data in OpenCabinet never changes, it lends itself to caching. The second parameter in the constructor above creates an in-memory for the most recently used 100 instances of each data type. This should significantly reduce repeated database access.
int bugId = 1;
int reporter = 34567;
Timestamp ts = new Timestamp(System.currentTimeMillis());
String description = "it just does not work";
IdString severity = new IdString("CRITICAL");
IdString status = new IdString("OPEN");
IdString product = new IdString("VaporWare Enterprise Edition");
IntegerSet assignedTo = new IntegerSet(12345, 23456);This creates instances of OpenCabinet data. They are not yet stored in the database, though (or maybe they are, from a previous session, but we cannot be sure about that).
q.update("insert into tbl_bugs values(?,?,?,?,?,?,?,?)",
cabMan.persistAll(
bugId, severity, status, product, assignedTo, reporter, ts, description ));We can use the CabinetManager to persist these data in OpenCabinet's internal tables, and then use the the integer id that are thereby created to insert into the bug database table.
The convenience method persistAll takes a variable number of arguments, and returns an Object[] with the same number of elements. For every argument that is an OpenCabinet persistable data type, that data is stored and its id is placed in the output array. Any other kind of argument is simple passed through. This provides for a simple way to create the bind array for the insert statement.
Object[] row = (Object[]) q.query(
"select * from tbl_bugs where bug_id = ?", bugId,
new ArrayHandler());
IntegerSet a = cabMan.get(IntegerSet.class, ((Number)row[4]).intValue());
In order to retrieve OpenCabinet data from the database, you have to go the other way round: turn the integer id into a Java instance.
// or all at once
cabMan.getAll(row, null, IdString.class, IdString.class,
IdString.class, IntegerSet.class, null, null, null);
// now row contains IdStrings and the IntegerSet
Again, there is a convenience method getAll that turns a whole row of data (in the form of an Object[]) into instances. The arguments after the row specify what kind of data this should be. You can pass in null for unrelated data .
Searching the bug database using fields containing OpenCabinet data involves establishing the integer ids for data instances that match the search criteria, and then using these integer in the WHERE clause of the SELECT statement against TBL_BUGS.
The easiest search pattern you can do are queries for exact matches. In this case, you can ask OpenCabinet for the unique id for the piece of data to match, and use that id directly in your SQL:
// find all bugs for a given product
Integer id = cabMan.getId(product);
List<Object[]> result =
(id != null) // the product name could be invalid, then the id is null
? q.query("select * from tbl_bugs where product_id = ?", id, new ArrayListHandler())
: new ArrayList<Object[]>();Instead of manually retrieving the id, you can also use the OpenCabinet Query interface. The OpenCabinet data types (like IdString or IntegerSet) define a number of find methods that are used to specify search criteria.
// find all bugs for a given product Set<Integer> productIds = cabMan.findIds(product.findExactMatch()); // find all bugs assigned to user 12345 Set<Integer> assignedIds = cabMan.findIds(new IntegerSet(12345).findSuperSets())
This way, you will end up with a number of id sets that you can use to match against product_id and assigned_to. Assuming that TBL_BUGS is in the same database as the OpenCabinet tables, you can avoid both these potentially large intermediate results and the need to manually bind them in your WHERE clause by asking OpenCabinet to create sub-select queries instead of materializing the search results.
// find all bugs for a given product assigned to user 12345
DatabaseCabinetManager cab = (DatabaseCabinetManager) cabMan;
SingleTableSelect select = new SingleTableSelect("*", "tbl_bugs");
select.addWhereClause(cab.makeSQLWhereClause("product_id", product.findExactMatch()));
select.addWhereClause(cab.makeSQLWhereClause("assigned_to", new IntegerSet(12345).findSupersets()));
List<Object[]> result = q.query(select.getSQL(), select.getBinds(), new ArrayListHandler());