Notes for class 8

Relationships in DB and among Objects

DB Relationships

In DB, N-1 relationship are implemented with FK’s on the “many side”, holding PK values of the “one side”.

One-side                            Many-side: has FK to PK on one-side

pizza_orders                      pizza_topping (pizza_topping.order_id is FK)

Products                            track (track.product_id is FK)

Since each Track belongs to one Product, there is a field of  "Product product" in Track, so we can navigate from a Track object to its Product.
Since each Product has a collection of Tracks, there is a field "Set<Track> tracks" or "List<Track> tracks in Product, so we can find all the Tracks for a Product object.

Primary key => not null, unique             FK: not null in this table (can be null in general)




All the FKs  in the pizza and music schemas are not-null, for simplicity and sturdy DBs.

Ex of possible nullable FK (not covered in class)

Download: FK to User is not null in music, but could be nullable in a similar project. 

We could allow anonymous downloads & then have nullable FK to User (null for anonymous DLs)

In this case, watch out when you join DL to User you lose the anonymous DL rows on inner join so probably want an outer join

In the DB, the FK is in one of the 2 related tables, but the relationship is not unidirectional.  It’s always bidirectional:

--but the database does not choose one of these approaches over the other: either is there whenever you need it.

But when we look at object relationships, we often see unidirectional relationships, as well as bidirectional, among the objects.

Example: PizzaOrder can navigate to its PizzaToppings, but PizzaTopping doesn't have a ref to its PizzaOrder

Diagrams collected up: ER and UML diagrams

Looking at the handout diagrams:

For the Pizza project, the handout shows a UML class diagram for the domain classes and an object diagram for the infrastructure objects (singletons). The object diagram is not an official UML diagram because it uses ovals instead of boxes to represent objects.

Now look at relationships among the domain objects for Music, will find mostly unidirectional relationships (in terms of inter-object refs)

In Music,

A Product has Set (in a field)

A Track has a reference to its Product (so we can find the Product for DL by object navigation [DL à Track àProduct])

So we’ve found a bidirectional relationship between Product and Track!

Note: a bidirectional relationship can be drawn with no arrowheads or two arrowheads.

A Download has a certain User & a certain Track by ref’s but a User does not have Set -no action requires this lookup!

Also Track does not have Set -no action requires this lookup!

So two unidirectional relationships here.

An Invoice has a field of type Set, as you would expect.

UML Class Diagrams : For more info, see http://en.wikipedia.org/wiki/Class_diagram




The handout shows UML class diagram. Each class can be used to generate multiple domain objects. We can draw a picture >of the objects involved in one pizza order: Here, each arrow represents an object reference.. Lots of unidirectional relationships.  One bidirectional.

Also on the class diagram : property names.

For example, the « track »  marked to the left of Track means that the Download’s Track property is named « track », promising a getter for track Track getTrack() in the Download class.  The idea is that when you look along the arrow from Download to Track, you are looking from Download’s perspective. It has a certain Track, named « track ». 

Similarly, looking from Product, it has a Set named tracks, i.e., Product has a getter Set getTracks().

Note there are names at arrowheads (including bidirectional ends) but not at non-arrowhead ends of relationships.  That’s because there is no getter for that type object in the other-end class.  For example, in Track-Download, Track does not have a field for Set, and thus no getter for such a set that would provide a name.  Is that clear?  Sounds like drivel.

Architecture Definitions and Principles

Definition: Domain Data.

Domain data is app-specific data, data that is processed or used in the app and is or could be kept in a database. UI details like HTML don’t count as domain data. It may or may not be held in app-defined Java objects.

for pizza: pizza order number, PizzaOrder object, row, student room number, PizzaTopping object, topping row, current day. Note that the current day is held in an integer variable--domain data doesn't have to be held in objects.

for music: User/site_user, Product/product, etc., Not in DB but still domain data: mp3 files, Cart

Not “domain data”: the service objects, DAOs: these are infrastructure things

Shared vs. private data: Many users can be clients at the same time, coming in from different client machines. 

Private Data. The presentation layer runs on behalf of a certain user session, so its domain data collection is private to that user. For example, the Toppings chosen by a user who is thinking about making an order. The user's room number.

Shared Data. Data that can be accessed by multiple users is shared data. To protect it, we make sure all changeable shared data resides in the database.  Our static web pages are shared, but are considered unchangeable.

Idea of Stateless Service Layer

We are following the EJB (Enterprise Java Bean of JEE) “stateless session bean” architecture, without actually using EJBs, since these require an app server like JBoss. This is the simplest kind of EJB.

This means we need a “stateless” Service layer, a set of service calls that are self-contained in the same way that web services are self-contained, so you are getting experience easily transferred to that realm.

We have already discussed how the service layer calls represent what the system can do. Each call represents some particular action.

Stateless: from http://whatis.techtarget.com/definition/stateless: Stateless means there is no record of previous interactions and each interaction request has to be handled based entirely on information that comes with it. Or long-term knowledge in the database.

What’s good about stateless?  It offloads the job of holding state from the Java core program environment. This is particularly important once that core code is running inside the web server.  It is also more robust—if a message gets lost, it doesn’t change the meaning of the current request.   HTTP is stateless: each GET must say exactly what URL on the server it is asking for, for example.  HTTP service is so simple that printers and other apparently non-computer devices can provide it.

Aside (optional material): Other important stateless services: IP, NFS (Network File System, the distributed file service on UNIX/Linux), web services.

The Windows distributed file protocol, SMB (Server Message Block Protocol), is stateful. A client can open a file on the server, and the server may deny other clients access to that file until the client closes it (from http://answers.yahoo.com/question/index?qid=20100506202029AAXBrTK) (Details from Microsoft)

End Aside

Stateless Service Layer Rule: No domain data is saved in the service layer (or DAO layer) between calls to the service API. Instead, each call works entirely from its arguments plus data from the database obtained via DAO calls.

Note that this is why StudentService.java has no fields holding domain data, just the infrastructure references to the DAOs.  And similarly the DAO objects. And that is why StudentService can be a singleton, since if we had two of them they would be identical, just a waste of bits.

How does this make calls self-contained? They can’t know things from past calls, unless that info was put in the database or held by the presentation layer (where it is private to that user) and sent back down through an argument.

This is another way of saying that we are completely dedicated to using the database to hold changeable shared data. And we like to get the user-private data stored in variables in the UI code. So the code in core of the app ends up not having to store any domain data for a significant time.

Example of non-self-contained call (not in use, of course): studentService.addToppingToOrder(Topping t);

This assumes there is a “current order” being built up, known to the service layer code, but this is not allowed. If we allow toppings to be added to orders already in the DB, then we need to pass the order ID or Order object in the call. However, this complicates the system, because now there are incomplete orders to deal with in the database while the user makes decisions about what toppings should be there. We’ll keep things simple by using makeOrder(...), which has arguments for everything needed in a pizza order.

Example of temporary data held in local variables while we’re computing in the service layer.  Here temporary means a lifetime contained within a single service call.

In makeOrder:  order holds data for just the time this code is running—that’s OK. We could get the current day into a local variable, and then use it in the order constructor.

  
 public void makeOrder(int roomNum, String sizeName, Set<String> toppingNames) 
							throws ServiceException {
	try {
		// TODO: ck args
		// Create dependent objects here to avoid having one constructor call another
		PizzaSize size = new PizzaSize(sizeName);
		Set<PizzaTopping> toppings = new TreeSet<PizzaTopping>();
		for (String toppingName: toppingNames) {
			toppings.add(new PizzaTopping(toppingName));
		}
		PizzaOrder order = new PizzaOrder(-1, roomNum, size, toppings,
				 adminDAO.findCurrentDay(), PizzaOrder.PREPARING);
		pizzaOrderDAO.insertOrder(order);
	} catch (SQLException e) {
		throw new ServiceException("Order can not be inserted" + e, e);
	}
  }

This still satisfies the rule, because this code is all inside one service call.  We can’t split it up into two service calls, however, without breaking the rule or putting this code in the presentation layer, which is not a good idea since it’s a core action of this app.

Example of longer-term data in presentation layer: roomNo in TakeOrder. Here is a run of TakeOrder, done after "ant hsqlSysTest" so there is a pizza size and a topping.

Possible Commands
O: Order
S: Status Report
R: Receive Order (acknowledge receipt)
Q: Quit
Please Enter the Command:
o
Please Enter the room Number:
5                                      <-- program gets room no. into a variable
Basic Pizza: tomato sauce and cheese  <-- program calls getToppings, getPizzaSizes
Additional toppings:
  Pepperoni
Sizes:
  small
Available pizza sizes to choose from:
1  small
Enter the size #:
1
Available pizza toppings to choose from:
1  Pepperoni
Enter Topping number, or q for no more Toppings:
1
Enter Topping number, or q for no more Toppings:
q
Thank you for your order              <-- program calls makeOrder, using room no.

Here the room number is held in the presentation layer, in a variable, across several calls to the service layer. That's fine because it's user-private. The presentation layer is private to one user. If there are two current users of the app, each has their own client process with their own presentation variables.

Note that:

Architecture Principles

1.  Pull UI. We are assuming a “pull UI”, that is, all info provided to the user is a response to a user request, i.e., all info provided by the service API to the presentation code is via returns from calls. There is no notification to the user generated by the system (email is an exception here), for ex., to notify the user that their pizza order is ready. This means we can use a simple call-down layering: no upcalls are needed (an upcall would be a call from service code to presentation code). Also note that JDBC follows the pull model, that is, it can’t notify its calling code about changes in the database, just respond to explicit requests for database state.

2.  Stateless service layer. As discussed above, this underlies the singleton SOs. Each service call is self-contained in sense of knowing what to do based only on its arguments and its access to database state via the DAOs. The DAOs are also stateless in the same sense of not holding domain data separate from the DB, but this follows naturally from their job as a veneer over the DB.

3.  Repository for shared domain data. All changeable domain data held between service calls that is shared among users resides in the database. The database is the expert in handling shared data, especially changing shared data.

Note that 3 follows from 2: a shared datum x is not allowed to be saved in the service layer or DAO, and the presentation layer is private to a user, so by elimination it must be in the database. On the other hand, the database is allowed to hold user-private data, like shopping carts.

But 2 does not follow from 3, since 3 does not cover user-private data. So a system that follows 1 and 3 allows user-private data held in the service layer, and this design in EJBs is known as “stateful session beans”, the other kind of EJBs.  We’ll stick to the stateless service layer model.

4.  Only one database. Working with multiple databases is extremely difficult, “distributed databases”, so we are assuming only one in use. It’s better to stretch your database system than to duplicate it. Use a server with 40 CPUs if you need to.  If your site is bigger than that, you can afford consultants that can know how to use distributed databases. Later, we will consider splitting the database into two parts, the "sales" db and the "catalog" db. This still means that each table belongs to only one database, the essential simplifying assumption.

We have also discussed:

5.   Thin presentation layer. The presentation layer should do the minimal work for UI. No business decisions, no domain object changes or creations. If a domain object needs to change, name the action and put it in the service API. However, the presentation layer code may hold domain data (as ints, Strings, etc., or possibly immutable domain objects) across calls to the service API.

Note that the service layer is the heart of the app. It’s in charge of what happens, yet is not allowed to manage state on its own. It has the database to hold long-term shared domain data and forces the presentation layer to hold needed user-private data by refusing to do it itself, (or saving it to the database if it knows a user id to identify it.)

By having all the real actions of the app coded in the service layer, and expressed in the service API, it is possible to implement multiple presentation layers for different ways of using the app.  For example, a web app for big-screen clients, vs for smart phones. Or as part of another app, receiving direction via web services.