Distributed Systems Lab 10
Distributed Systems Lab 10
10. Data services (JDO & SDO) and Service Component Architecture (SCA)
December 14, 2009
Design your entity classes and their relationship Next question is should you be writing code to create tables, and persist or query data from these tables or data stores
It is preferable to answer 'No' for this question, since the more code you write, the more are the chances of making errors, and further, developer time is costly. Today you may write JDBC for doing the "technical functionalities", and tomorrow you may want to change all your JDBC to some other standard since you want to port your data from a relational store to a different persistence mechanism.
Features of JDO
Separation of Concerns: Application developers can focus on the BDOM and leave the persistence details (storage & retrieval) to the JDO implementation. API-based: JDO is based on a Java interface-based programming model. => All persistence behavior including most commonly used features of OR mapping is available as metadata, external to your BDOM source code. => We can also Plug and Play multiple JDO implementations. Data store portability: Irrespective of whether the persistent store is a relational or object-based file, or just an XML DB or a flat file, JDO implementations can still support the code =>JDO applications are independent of the underlying database. Performance: A specific JDO implementation knows how to interact better with its specific data store, which will improve performance as compared to developer written code. J2EE integration: JDO applications can take advantage of J2EE features like EJB and thus the enterprise features such as remote message processing, automatic distributed transaction coordination, security, etc
1.
2.
3.
4.
Example
two entity classes: OrderList and LineItem BDOM illustrates that
an Order can contain multiple line items. each line item is related to one and only one Order.
BDOM classes:
Example
OrderList is the class representing the Order, and is having a primary key attribute that is number. public class OrderList{ private int number; private Date orderDate; private Set lineItems; // other getter & setter methods go here // Inner class for composite PK public static class Oid implements Serializable{ public int number; public Oid(){ } public Oid(int param) { this.number = param; } public String toString(){ return String.valueOf(number); } public int hashCode() { return number; } public boolean equals(Object other){ if (other != null && (other instanceof Oid)){ Oid k = (Oid)other; return k.number == this.number; } return false; } } }
LineItem represents each item container in the Order. We don't explicitly define a primary key for LineItem even though JDO will have its own mechanism to do that. public class LineItem{ private String productId; private int numberOfItems; private OrderList orderList; // other getter & setter methods go here }
Example
In this sample, we will persist our entities to a relational database, Oracle. We specify the main connection parameters in jpox.PROPERTIES file. javax.jdo.PersistenceManagerFactoryClass=org.j pox.jdo.JDOPersistenceManagerFactory javax.jdo.option.ConnectionDriverName=oracle.jd bc.driver.OracleDriver javax.jdo.option.ConnectionURL=jdbc:oracle:thin: @127.0.0.1:1521:orcl javax.jdo.option.ConnectionUserName=scott javax.jdo.option.ConnectionPassword=tiger org.jpox.autoCreateSchema=true org.jpox.validateTables=false org.jpox.validateConstraints=false
Main class contains the code to test the JDO functionalities. it creates two Orders and adds few line items to each order. it persists these entities and queries back these entities using the id.
public class Main{ static public void main(String[] args){ Properties props = new Properties(); try{ props.load(new FileInputStream("jpox.properties"));} catch (Exception e){ e.printStackTrace();} PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); Object id = null; try{ tx.begin(); LineItem lineItem1 = new LineItem("CD011", 1); LineItem lineItem2 = new LineItem("CD022", 2); OrderList orderList = new OrderList(1, new Date()); orderList.getLineItems().add(lineItem1); orderList.getLineItems().add(lineItem2); LineItem lineItem3 = new LineItem("CD033", 3); LineItem lineItem4 = new LineItem("CD044", 4); OrderList orderList2 = new OrderList(2, new Date()); orderList2.getLineItems().add(lineItem3); orderList2.getLineItems().add(lineItem4); pm.makePersistent(orderList); id = pm.getObjectId(orderList); System.out.println("Persisted id : "+ id); pm.makePersistent(orderList2); id = pm.getObjectId(orderList2); System.out.println("Persisted id : "+ id); orderList = (OrderList) pm.getObjectById(id); System.out.println("Retreived orderList : " + orderList); tx.commit(); } catch (Exception e){ e.printStackTrace(); if (tx.isActive()){ tx.rollback(); } } finally{ pm.close(); } } }
This necessitates a Common Data Model (CDM), which is often referred to as the Canonical Data Model or Information Model.
In such a model, you will often have entities that represent "domain" concepts, for example, customer, account, address, order, and so on. So, multiple LOB systems will make use of these domain entities in different ways, seeking different information-based on the business context.
Data Services are specialization of WSs which are data and information oriented.
They need to manage the traditional CRUD (Create, Read, Update, and Delete) operations as well as a few other data functionalities such as search and information modeling. The Create operation will give back a unique ID whereas Read, Update, and Delete operations are performed on a specific unique ID. Search done with some form of search criteria and information modeling, or retrieval happens when we pull useful information, for example, retrieving the address for a customer.
SDO Architecture
In SDO, data is organized as a graph of objects, called DataObject.
A DataObject is the fundamental component which is a representation of some structured data, with some properties. These properties have either a single value or multiple values, and their values can be even other data objects. Each data objects also maintains a change summary, which represents the alterations made to it.
A single data graph can represent data from different data sources.
This is actually a design model to deal with data aggregation scenarios from multiple data sources. The data graphs form the basics of the disconnected architecture of SDO, since they can be passed across layers and tiers in an application. When doing so, they are serialized to the XML format.
SDO clients are disconnected from both the DMS and the data source. A Change Summary contains any change information related to the data in the data object.
Change summaries are initially empty and are populated as and when the data graph is modified.
Example
SDO can handle heterogeneous data sources, but for the sample here, we will make use of an XML file as a data source. The sample will read as well as write an XML file, when the client program makes use of SDO API to do data operations. The main artifacts for running the samples in SDO include
an XSD schema file and an XML instance file.
Example - CreateEmployees
define DataObjects in code and build the SDO graph. the root DataObject is persisted to a file and also to the system output stream as shown in the following code.
public class CreateEmployees extends SampleBase { private static final String HR_XML_RESOURCE_NEW = "hr_new.xml"; public static final String HR_XSD_RESOURCE = "hr.xsd"; public static final String HR_NAMESPACE = "http://www.binildas.com/apache/tuscany/sdo/sample"; public CreateEmployees(Integer commentaryLevel) { super(commentaryLevel, SAMPLE_LEVEL_BASIC); } public static void main(String[] args) throws Exception{ CreateEmployees sample = new CreateEmployees(COMMENTARY_FOR_NOVICE); sample.runSample(); } public void runSample() throws Exception{ HelperContext scope = createScopeForTypes(); loadTypesFromXMLSchemaFile(scope, HR_XSD_RESOURCE); DataFactory factory = scope.getDataFactory(); DataObject purchaseOrder = factory.create(HR_NAMESPACE, "employees"); DataObject employee1 = purchaseOrder.createDataObject("employee"); employee1.setString("id", "3457"); employee1.set("name", "Cindy Jones"); DataObject homeAddress1 = employee1.createDataObject("address"); homeAddress1.set("street1", "Cindy Jones"); homeAddress1.set("city", "Stanchion"); homeAddress1.set("state", "TX"); homeAddress1.set("zip-code", "79021"); DataObject organization1 = employee1.createDataObject("organization"); organization1.setString("id", "78"); organization1.set("name", "Sales"); DataObject office1 = employee1.createDataObject("office"); office1.setString("id", "43"); DataObject officeAddress1 = office1.createDataObject("address"); officeAddress1.set("street1", "567 Murdock"); officeAddress1.set("street2", "Suite 543"); officeAddress1.set("city", "Millford"); officeAddress1.set("state", "TX"); officeAddress1.set("zip-code", "79025"); DataObject employee2 = purchaseOrder.createDataObject("employee");
Example
A single booking service with a default SCA binding. BookingAgentServiceComponent exercises this component by calling three other components: FlightServiceComponent, HotelServiceComponent, and CabServiceComponent
1. 2. 3.
Example
Fine-grained service components FlightServiceComponent public interface IFlightService{ String bookFlight(String date, int seats, String flightClass); } public class FlightServiceImpl implements IFlightService{ public String bookFlight(String date, int seats, String flightClass){ } } HotelServiceComponent public interface IHotelService{ String bookHotel(String date, int beds, String hotelClass); } public class HotelServiceImpl implements IHotelService{ public String bookHotel(String date, int beds, String hotelClass){ } } CabServiceComponent public interface ICabService{ String bookCab(String date, String cabType); } public class CabServiceImpl implements ICabService{ public String bookCab(String date, String cabType){ }
BookingAgentServiceComponent import org.osoa.sca.annotations.Reference; public class BookingAgentServiceComponent implements IBookingAgent{ private IFlightService flightService; private IHotelService hotelService; private ICabService cabService; @Reference public void setFlightService(IFlightService flightService) { this.flightService = flightService; } @Reference public void setHotelService(IHotelService hotelService) { this.hotelService = hotelService; } @Reference public void setCabService(ICabService cabService) { this.cabService = cabService; } public String bookTourPackage(String date, int people, String tourPack){ System.out.println("BookingAgent.bookTourPackage..."); String flightBooked = flightService.bookFlight(date, people, tourPack); String hotelBooked = hotelService.bookHotel(date, people, tourPack); String cabBooked = cabService.bookCab(date, tourPack); if((flightBooked.equals("Success")) && (hotelBooked.equals("Success")) && (cabBooked.equals("Success"))){ return "Success"; } else{ return "Failure"; } } }
Example
BookingAgentClient
creates an instance of SCADomain gets a reference of the BookingAgentServiceComponent using the name of the configured service component. executes the business method, bookTourPackage.
import org.apache.tuscany.sca.host.embedded.SCADomain; public class BookingAgentClient{ public static void main(String[] args) throws Exception { SCADomain scaDomain = SCADomain.newInstance("BookingAgent.composite"); IBookingAgent bookingAgent = scaDomain.getService(IBookingAgent.class, "BookingAgentServiceComponent"); System.out.println("BookingAgentClient.bookingTourPackage..."); String result = bookingAgent.bookTourPackage("20Dec2008", 5, "Economy"); System.out.println("BookingAgentClient.bookedTourPackage : " + result); scaDomain.close(); } }