Team ModelBridge of the OT/JPA example "Order-System" (role file of OrderSystemPersistenceTeam).
team package org.objectteams.samples.ordersystem.persistence.OrderSystemPersistenceTeam; import java.util.Collection; import org.objectteams.samples.ordersystem.data.Customer; import org.objectteams.samples.ordersystem.order.StockOrder; import org.objectteams.samples.ordersystem.store.StockItem; /** * <p> * This role intercepts initialization of data and either reads data from DB if existent * or invokes the default behavior of creating hard coded initial objects. * </p><p> * Nested roles (subclasses of {@link EntityBridge} furthermore intercept * addition/removal of elements in order to persist these operations. * <p> * * @author stephan */ protected team class ModelBridge playedBy ModelAdapterTeam { /** Custom lifting constructor to further initialize this team/role. */ public ModelBridge(ModelAdapterTeam modelAdapterTeam) { // when initializing this role (no later than at createOrRetrieveXYZ) // activate it for callins in nested roles to take effect. this.activate(ALL_THREADS); } // --- Accessors for instances of roles defined below: --- StorageBridge getStorageBridge() -> StorageAdapter<@base> getStorageAdapter(); CustomerBridge getCustomerBridge() -> CustomerAdapter<@base> getCustomerAdapter(); OrderBridge getOrderBridge() -> OrderAdapter<@base> getOrderAdapter(); /** * This callin method generically handles requests to create a set of data of a given type. * <ul> * <li>If it can find corresponding entities in the given table it reads them from DB and * feeds them into the given bridge thus making them accessible for the application</li> * <li>If no persistent entities are found it delegates back to the underlying creation * (of hard-coded demo instances). It does so in a transaction so that all newly * created objects will be committed in one step.</li> * </ul> * @param bridge this instance is used for accessing the DB table and for * feeding retrieved elements into the application. */ @SuppressWarnings("basecall") callin <E> void createOrRetrieveElements(final EntityBridge<E> bridge) { simpleLog("checking for existing elements"); Collection<E> allElements = bridge.findAllEntities(); if (allElements != null && allElements.size() > 0) { simpleLog("...retrieving elements"); this.deactivate(); // prevent recursion in callout below try { for (E element: allElements) bridge.addToApplication(element); // Technical note: // Although this call leads to invoking XYZAdapter.add(E) // which is also callin bound in role XYZBridge, // this causes no re-entrance since that callin is not active // due to the this.decativate() call above. } finally { this.activate(); } } else { simpleLog("...creating initial elements"); inTransactionDo(new Runnable() { public void run() { base.createOrRetrieveElements(bridge); }}); } simpleLog("done"); } // ==== hook above callin method into several join points within the application: void createOrRetrieveElements(EntityBridge<StockItem> bridge) <- replace void fillStorage() with { bridge <- getStorageBridge() } void createOrRetrieveElements(EntityBridge<Customer> bridge) <- replace void createCustomers() with { bridge <- getCustomerBridge() } void createOrRetrieveElements(EntityBridge<StockOrder> bridge) <- replace void createOrders() with { bridge <- getOrderBridge() } /** * Generic gateway to an entity adapter (roles of base team * {@link org.objectteams.samples.ordersystem.gui.ModelAdapterTeam}). * <br /> * It serves as a two-way bridge: * <ul> * <li>DB -> application --- using <code>addElement</code></li> * <li>application -> -- using <code>persistNewElement, removeElement</code>, * to be invoked by callin triggers</li> * </ul> * Subclasses have to define method bindings for both directions. */ abstract protected class EntityBridge<E> { /** Specifies the database table containing the entities managed by this bridge. */ abstract String getTableName(); /** Feed one element (assumably retrieved from DB) into the application. */ abstract protected void addToApplication(E element); /** Retrieve all entities from the table specified by {@link #getTableName()} */ protected Collection<E> findAllEntities() { return OrderSystemPersistenceTeam.this.findAllEntities(getTableName()); } static void persistNewElement(Object entity) { simpleLog("persisting "+entity); persistInTransaction(entity); } static void removeElement(Object entity) { removeInTransaction(entity); } } /** Bind EntityBridge for StockItems managed by the StorageAdapter. */ protected class StorageBridge extends EntityBridge<StockItem> playedBy StorageAdapter<@ModelBridge.base> { String getTableName() { return "StockItem"; } void addToApplication(StockItem anItem) -> void add(StockItem anItem); persistNewElement <- after add; removeElement <- before delete; } /** Bind EntityBridge for Customers managed by the CustomerAdapter. */ protected class CustomerBridge extends EntityBridge<Customer> playedBy CustomerAdapter<@ModelBridge.base> { String getTableName() { return "Customer"; } void addToApplication(Customer aCustomer) -> void addElement(Customer aCustomer); persistNewElement <- after addElement; removeElement <- before removeElement; } /** Bind EntityBridge for StockOrders managed by the OrderAdapter. */ protected class OrderBridge extends EntityBridge<StockOrder> playedBy OrderAdapter<@ModelBridge.base> { String getTableName() { return "StockOrder"; } protected void addToApplication(StockOrder anOrder) { internalAddElement(anOrder); anOrder.init(); // one more action: orders must be initialized after retrieval. } void internalAddElement(StockOrder anOrder) -> void addElement(StockOrder anOrder); // same as above role, but more explicit syntax (just for illustration): void persistNewElement(Object entity) <- after void addElement(StockOrder anOrder); void removeElement(Object entity) <- before void removeElement(StockOrder anOrder); } }
all news
RSS feed