CS636 Class 7

Handout: Music Project Schema

Kinds of objects
Our projects have two kinds of objects, domain objects to carry data around and act on it, and infrastructure objects to carry the API methods.

In the code inside makeOrder of StudentService we see:
	pizzaOrderDAO.insertOrder(order);

Back to the big picture: how the API objects ref each other

Presentation: needs 2 refs: studentService and adminService, so it can do calls like studentService.makeOrder(...)

Service layer: needs refs to DAO objects, so it can do calls like pizzOrderDAO.insertOrder(...)

We have special “config” code to create these major objects 

singletons

Each oval represents a (singleton) object. Arrows out from the upper part of the oval represent references from (private) fields of that object.

The label on the oval is the object's class name. Note there is only one object of each class, thus a "singleton".

The three layers are shown: presentation at top (which has objects of its own, not shown), the service layer in the middle, with code in those two classes. and the DAO layer with its three classes.

Blue arrows show object ref’s from service objects to DAO objects, all singletons. More on singletons below. For example, the AdminService object has a private field pizzaOrderDAO of type PizzaOrderDAO, which ref’s the PizzaOrderDAO singleton.

Example class:

public class StudentService {
      private PizzaOrderDAO pizzaOrderDAO;  <-- one blue arrow above
    private MenuDAO menuDAO; <-- another blud arrow
      private AdminDAO adminDAO; <-- another blue arrow

We want to avoid having a service code do “new” to create a DAO object, because then the service object could not be unit tested completely, and also, we would end up with duplicate DAO objects, one created by StudentService and the other by AdminService. Instead, we want to provide the DAO object refs to the service object in the service object’s constructor (or using a setter). This important technique is called Inversion of Control, or IofC for short.

Pizza Project:    6 API singletons

Singletons

What is a singleton? Normally a class is expected to be used to create multiple objects of that type. But sometimes it is reasonable to create a class and then create only one object from it. In that case the object is a singleton object, or just “singleton”. This is considered a pattern, the singleton pattern, but it is so simple it hardly deserves that title.

Why use a singleton for StudentService?  The StudentService class is set up to express part of the service API. It holds the code for the API calls. The calls of the service API are doing work using database data expressed mainly as domain objects, and each call receives what it needs in the arguments of the call, and then is able to do its work using appropriate DAO calls. It doesn’t need to hold data for the user from call to call. We hold all the long-term data in the database. So one instance of the class works fine.

Another way to express an API like this is with no objects at all, just a static class with static methods expressing the API. But this is not good for testability. The class is “wired in”. You can’t substitute one API implementation for another. So objects are better, even when there is only one.

The service object singletons need refs to DAOs, presentation layer code needs refs to SOs, to call the next lower layer.

Recall picture of needed object graph of 6 singletons. Note that singletons, being one and only objects, normally are created once and for all at program startup, and this is no exception.

How to set up an object graph like this: the Hollywood Principle (aka Dependency Injection)

Simplified case: after setup, class A has a ref to class B.  We say A has B as a dependency.

One way to set this up: have code in A that does “new B”.  But then we’re always stuck with B. To be testable, we would like the option of supplying a mock for B, but there is no wiggle room if A’s code does “new B”.

Better way for testability: arrange to pass B to A via a setter or constructor.  Then we can pass A an object that is a subclass of B, for example, and it will be perfectly happy with it.  Since it doesn’t to “new B” any more, it doesn’t specify the exact type of B.  This is called the “Hollywood principle”, because from A’s standpoint, the system is saying “Don’t call us, we’ll call you”.  A has to give up control a little for the good of the system.

So we see that in this simple case, the best way to create A and B is to create B, the dependency, first, and then A. 

To create an object graph, find the objects with no dependencies, create them, then create objects that depend on them, passing the dependent object to the new object either in the constructor or by a setter. This avoids any “new” of dependent objects in object code, promoting testability.  It also avoids duplication of dependent objects.

Config Code

So what code does the new for the singletons?

Special code that sets up the system, typically in a static method, so that it can be called by Classname.config(...), i.e., before any objects are created.

Question from class: isn't this done by Spring configuation?

Answer: Yes, the Spring framework can help with this. We are doing the same thing "by hand", that is, by plain Java code.

In fact, PizzaSystemConfig.java has only static methods and static fields. No objects of this class are created. The static fields are housed in the class object, which every class has (once loaded) whether or not it is used to create ordinary objects. 

Look at Pizza1’s configureServices, a static method, so called by PizzaSystemConfig.configureServices(...); 

It simply creates the DAOs, then the *Service singletons, passing them the DAO refs in their constructors, then offers up the resulting service API refs to anything interested in them, i.e., the apps. See the two getters at the end of the source.

Turning to the Music DB and its schema handout: 

We looked at the handout of the load script and discussed the conversion of Murach’s MySQL-specific script to a portable SQL script. 

In particular, we studied the FKs to see how the tables are related. The following shows a "crows foot" at the end we would put a star in the UML-style diagram.  This is another common notation.

music schema

The FKs define the N-1 relationships, and their constraints help keep the database consistent.

But FK constraints do cause problems for load and drop database scripts : we need to order the create tables and drop tables to avoid FK violations.

First table create : need to find a table with no FK columns. Choice of site_user or product. Createdb.sql uses site_user. Once site_user is created, we can create tables with FK to it. And so on.

First table drop : need to find a table with no incoming FK constraints to it. Ex : download. With download gone, can drop track, and so on.  See dropdb.sql.

Note that a user downloads an mp3 file for a certain track of a CD, not for the CD in general, so the download row should reference a row of track, not product.  On the other hand, a user purchases a whole CD, not a single track, so the lineitem references a certain product, not a certain track.

Consider a table with a FK. The corresponding domain object has an object reference to another domain object.  For example, a Download object has a ref to its Track object and its User object. 

The other end of the N-1 relationship may have a set of refs to the corresponding domain objects.  For example, an Invoice has a set of lineitems, so the Invoice object has a Set ref.  However, the User object does not have such sets. More on this later.

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 tracks" or "List 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

Architecture Definitions and Principles--next time