feedback / send your comments
mail to luc peuvrier
chat channel
joafip users mailing list
forums

BACK

En Français

Database versus JOAFIP

This page is to give you an idea how simple it is to use JOAFIP to create your own database.

We are going to learn how to open, store, retrieve, update and delete instances of a record entity class stored on a persistent table entity. In our example the record entity will be an Item whose attributes are the item code and price.

In fact it is only a data model instance in memory that will be persisted.

UML class diagram of our data model (simple example)

 item table
Relation composition between ItemTable and Item is realized using PTreeMap
other collection usable for multiple cardinality relation

The Item class

A simple class with to members: code and price.

/**
 * item entity<br>
 * comparable compare item code ( the main key )
 */
public class Item implements Comparable<Item> {

    /** item code is immutable : it is the main key */
    private final String code;

    /** the item price */
    private BigDecimal price;

    public Item(final String code) {
        super();
        this.code = code;
    }

    public Item(final String code, final BigDecimal price) {
        super();
        this.code = code;
        this.price = price;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(final BigDecimal price) {
        this.price = price;
    }

    public String getCode() {
        return code;
    }

    @Override
    public int compareTo(final Item otherItem) {
        // /!\ JOAFIP persistable object rule
        // do not use code.compareTo(otherItem.code)
        // see joafip persistent pojo
    // or use joafip 3.0.0 java agent
        return code.compareTo(otherItem.getCode());
    }

    @Override
    public String toString() {
        return code + ";" + price + ";";
    }
}

The ItemTable class

The item table that will be persisted.

public class ItemTable {

    /** map of {@link Item} by item code */
    private final Map<String, Item> itemByCodeMap =
    /**/new PTreeMap<String, Item>();

    /** map of {@link Item} by item price, can have multiple item for same price
     */

    private final NavigableMap<BigDecimal, Set<Item>> itemByPrice =
    /**/new PTreeMap<BigDecimal, Set<Item>>();

    public Item addItem(final Item item) {
        final Item previousItem = itemByCodeMap.put(item.getCode(), item);
        if (previousItem != item) {// NOPMD must compare object instance
            removeOfPriceMap(previousItem);
            addToPriceMap(item);
        }
        return previousItem;
    }

    public Item getItemByCode(final String itemCode) {
        return itemByCodeMap.get(itemCode);
    }

    public Collection<Item> getAllItem() {
        return itemByCodeMap.values();
    }

    public List<Item> getItemByPrice(final BigDecimal fromPrice, final BigDecimal toPrice) {
        final NavigableMap<BigDecimal, Set<Item>> subMap = itemByPrice
                .subMap(fromPrice, true/* fromInclusive */,
                        toPrice, true/* toInclusive */);

        final List<Item> list = new PLinkedList<Item>();
        for (Set<Item> set : subMap.values()) {
            list.addAll(set);
        }
        return list;
    }

    public Item removeItem(final String itemCode) {
        final Item removed = itemByCodeMap.remove(itemCode);
        removeOfPriceMap(removed);
        return removed;
    }

    private void addToPriceMap(final Item toAdd) {
        final BigDecimal price = toAdd.getPrice();
        Set<Item> set = itemByPrice.get(price);
        if (set == null) {
            set = new PTreeSet<Item>();
            itemByPrice.put(price, set);
        }
        set.add(toAdd);
    }

    private void removeOfPriceMap(final Item toRemove) {
        if (toRemove != null) {
            final BigDecimal price = toRemove.getPrice();
            final Set<Item> set = itemByPrice.get(price);
            if (set != null) {
                set.remove(toRemove);
            }
        }
    }
}

Opening the "database"

To access a storage file or create a new file persistence manager providing the path to your storage file as the parameter. The data access session is the facade to manage object in storage file. Closing the file persistence with the #close() method will close the storage file and release all resources associated with it.

since 4.0.0

/* open file persistence */
final FilePersistenceBuilder builder = new FilePersistenceBuilder();
builder.setPathName(STORAGE_DIRECTORY);
builder.setProxyMode(true);
builder.setRemoveFiles(false);
builder.setGarbageManagement(false);
builder.setCrashSafeMode(false);
final IFilePersistence filePersistence = builder.build();
    ............
/* close file persistence */
filePersistence.close();

before 4.0.0

/* open file persistence */
final FilePersistence filePersistence =
    new FilePersistence(STORAGE_DIRECTORY, false, false);
final IDataAccessSession session = filePersistence.createDataAccessSession();
    ............
/* close file persistence */
filePersistence.close();

Opening a data access session

open the session for CRUD operation ( Create Read Update Delete ).

session.open();

close session saving mode to replicate change in memory to storage file.

session.close(EnumFilePersistenceCloseAction.SAVE);

in case of read only access, close session not replicate change in memory to storage file, this can be a kind of rollback.

session.close(EnumFilePersistenceCloseAction.DO_NOT_SAVE);

Storing object

store ItemTable class instance

/* store new item table (empty) */
session.open();
ItemTable itemTable = new ItemTable();
session.setObject("itemTable", itemTable);
session.close(EnumFilePersistenceCloseAction.SAVE);

add Item class instance to stored ItemTable instance will persist these Item object

/* populate item table */
session.open();
itemTable = (ItemTable) session.getObject("itemTable");
Item item = new Item("123", 10);
itemTable.addItem(item);
item = new Item("456", 10);
itemTable.addItem(item);
item = new Item("789", 11);
itemTable.addItem(item);
session.close(EnumFilePersistenceCloseAction.SAVE);

Retrieving object

Joafip have not queering system, but ItemTable implement all that is need to retrieve object: all goes with accessor methods.

/* retrieve by code */
session.open();
itemTable = (ItemTable) session.getObject("itemTable");
item = itemTable.getItemByCode("456");
// _log.info("retrieved by code 456: " + item);
item = (Item) filePersistence.copy(item);// create accessible out of session deprecated in 3.0.0
item = (Item) filePersistence.deepCopy(item);// create accessible out of session
session.close(EnumFilePersistenceCloseAction.DO_NOT_SAVE);
// item is accessible out of data access session
_log.info("retrieved by code 456:" + item);

Updating object

Updating objects is just as easy as get object in memory, call modifier method, and then close data access session saving.

/* update */
session.open();
itemTable = (ItemTable) session.getObject("itemTable");
item = itemTable.getItemByCode("123");
item.setPrice(9);
session.close(EnumFilePersistenceCloseAction.SAVE);

Deleting object

Deleting objects is just as easy as for update.

/* delete */
session.open();
itemTable = (ItemTable) session.getObject("itemTable");
item = itemTable.removeItem("456");
_log.info("deleted " + item);
session.close(EnumFilePersistenceCloseAction.SAVE);

Conclusion

More complex query can be added by adding accessor/modifier methods to ItemTable class.

It is possible to create a DataBase class that is a composition of multiple tables. This DataBase class can act as a facade to store, retrieve, update and delete data entity. This facade can implement a set of method for complex queries, all in java navigating in object graph constituted of table of data entity.

get full sources


feedback / send your comments
mail to luc peuvrier
chat channel
joafip users mailing list
forums

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
© 2007-2012, joafip