CS636 Class 20 Handout: Using DB from Webapp

Project 2 materials are now available

We looked at pizza3's config, how to run it as client-server and web app

See pizza3/README and build.xml, also persistence.xml for each db under directory database.

Model 1 Coverage: not covered in class

Bottom line: For this class, you can skip the Model-1 related material:

Guiding principle: We are doing MVC Model 2, which has a servlet to accept UI, but it is possible to live without servlets (except JSP servlets of course). That's "Model 1". Then everything for presentation is done in JSP, including interpreting incoming parameters.

For Model 1 JSP-only webapps we need a pure JSP way to set up the user object/bean to allow ${user.firstName} to work. EL itself does not provide a way. Here it is, on pg. 187 of Chap 6:

<jsp: useBean id=”user” class=”murach.business.User” scope=”request”  />

However, the bean set up this way has just whatever the no-args constructor sets up.

A fancier useBean ispossible, with nested <jsp:setProperty…> to set  properties of the new bean.  These setProperties are not executed if the bean already exists.

<jsp:setProperty…> can also  be used at the top level to set a property in a bean held as a session or request variable. See pg. 189

Accessing request parameters in EL: it’s easy with EL’s implicit object “param”

In EL, have implicit var “param” with properties ßà params

In basicjsp of my UNIX tomcat

testform.jsp (could be .html)

<form action=”getparam.jsp” method=”post”>
       enter something:
       <input type=”text” name=”formitem”/></p>
       <p><input type=”submit”/></p>
</form>

Click on submit, HTTP POST, with request parameter formitem=hello in the POST body

Getparam.jsp

Your input was ${param.formitem}

POST: sends params in the body of the message to the server

Tomcat decodes params from GET or POST & puts them in request parameters

EL Implicit object paramValues is useful for gaining access to multiple params of the same name.

The example here would have a URL with ?emailAddress=oneval&emailAddress=anotherval, two params both named emailAddress (actually hidden away in the POST body here, because the form has method=”post”)

Pg. 257, how to access these: ${paramValues.emailAddress[0]} and  ${paramValues.emailAddress[1]}  --seeing arrays in use in EL. Here paramValues.emailAddress is itself an array, or works like an array.

However, we don’t need param, paramValues for pure MVC apps, because the servlet interprets incoming parameters.

End of Model 1 discussion

Pg 197: JSP error display and hints for fixes. Relevant to hw4 #5

Note HTTP 404, 500

Next challenge: Moving pizza2/music2 to the web container inside tomcat

We expect to get our BL+DAO code from pizza2 or music2 to execute inside the web container, i.e., in tomcat, but obviously the presentation layer has to be completely rewritten, a big job.

How can we start?  We need an absolutely minimal presentation code.

Hey, we already have it, in SystemTest!

We will get SystemTest to run from a servlet…The System.out.println output will show up in tomcat's log

Tomcat executes servlets in its own JVM. It uses the Java capability to load in additional classes and execute them.  Of course these classes have to follow certain rules for tomcat to know how call them. They have to provide methods doGet and/or doPost for tomcat to call when a HTTP request comes in with a URL that is recognizable as belonging to that servlet. 

When we execute ordinary Java programs, execution starts in main (SystemTest for example).  Tomcat itself has a main, but our servlets don’t.  Execution reaches our servlet code by a call from tomcat to doGet or doPost.

Here is a way to get our BL+DAO code from pizza2 or music2 to execute inside the web container, i.e., in tomcat, with no web UI at all.

See pizza3/src/cs636/music/presentation/web/SysTestServlet.java

One fix for this problem is to use a static initializer in say PizzaSystemConfig: This is useful in the Model 1 case, where there may only be JSPs, no servlets.

static {

    code that gets executed at class-load time

}

Then when the servlet calls PizzaSystemConfig.getAdminService() the first time, the class will be loaded and the static initializer run.  The class will stick around in memory because of its static fields.  So it won’t be reloaded again as further requests come in.

Another way, the one we’ll use, is to use the servlet’s init() method, which is called once at servlet class load (see Murach, pg. 161)

There is another technical detail: SystemTest reads a file, but a web app doesn’t know where it is in the filesystem, or this is not obvious anyway.  We need to put test.dat in the top-level deployment directory (say), and then ask the servlet software to convert its path for us.  See pg, 141 of Murach for code accessing a file from a servlet.

All transactions happen strictly inside service calls, so inside individual request cycles.  They can be concurrent, however, so we need to argue that they don’t interact badly.  Our stateless service layer helps with this, and the fact that each transaction has its own independent persistence context. More on this later.

Of course we need to add the UI—use JSP to present HTML to the users via their browsers.

Pa2, pizza3: “MVC” approach, using a “dispatcher servlet”, doing decisions/business logic in Java, using JSP for display to user only. Model 2 (diagram, pg. 33)

Controller servlet --> View JSP

The --> is a request forward operation, done inside tomcat, so very fast

Forwarding a request: discussed, pg. 144, though not completely.

The forwarding action occurs inside the server, so there is no round-trip time back to the browser involved. The browser doesn’t know anything about it, and so the address bar in the browser doesn’t change either, never displaying the name of the .jsp being forwarded to. It gets the HTML generated by the .jsp when the response goes back.

Timeline: browser B uses URL for servlet S, which forwards to JSP J, which creates HTML response for browser B:

---*---------------------------**-------------------------------*---------
   B                           SJ                               B

   time--->

The request and response objects are forwarded, so for example, the servlet can attach attributes to the request and the JSP can use them. Similarly, the servlet can attach attributes to the session that are usable. Here is a picture, showing the servlet as an oval forwarding to the JSP shown as a rectangle. Of course the JSP is actually another servlet at runtime.

servlet to JSP diagramNote that the exceptions are usually due to calling the service layer, which we do in servlet code in MVC. So we don’t have to worry about handling exceptions in the JSP: it’s working with already-collected-in-memory data.

Practical Details

Needed libraries for JSPs: in WEB-INF/lib

JSP with EL: no libraries needed.  Note how basicjsp has no WEB-INF/lib directory. It has

Add.jsp  

1 + 2 + 3 = ${1 + 2 + 3}

JSTL, however, requires libraries

See discussion of JSTL libraries on pg. 271. All our needs are covered by the Core library with the two jar files you can see in pizza3 webapp, in WEB-INF/lib, that is, jstl-1.2.1.jar and jstl-api-1.2.1.jar.

Note that names of jar files can be misleading. What’s important is what classes are inside a jar file, not its name.  You can see the classes using the jar tool: “jar tf jstl-1.2.1.jar” for example.

Needed Setup in the JSP: none for JSP with just EL

JSP: set up c: alias for core JSTL library:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

If you forget this, any <c:…> gets sent out as part of the response, causing no end of trouble.

Look at example JSP from pizza3

See includes of header and footer—look at header see own taglib, CSS linkage, script to support old browsers, shortcut icon for browser tabs, and image in header (same pizzapie image as icon)

<c:if  test=… >…</c:if>

<c:forEach…>

See <c:url for each URL: this is supporting URL-rewriting for session tracking.

JNDI and Connection pooling: see handout “Using a Database from a Web App”

Connection pooling is discussed in Murach, pp 464-469. It is important for web apps because they need Connections for such short periods of time that the Connection startup time with the database looks huge and would impact performance.  The Connection pool has hot standby Connections that the web app can borrow and return.

Connection pooling is provided by the DataSource JEE service.  We want one of these objects for each database in use, so three for our setup.

With a DataSource object, you can get a Connection by ds.getConnection(). A simple JDBC webapp can use this Connection normally, and must close it when done.

We want tomcat to set these up for us and provide refs to these objects—how does that work?

The app servers offer a JNDI service, another JEE service, that supports an object repository, i.e. a place to hold objects so that webapps can get them.  The objects are looked up by their JNDI names. For example, the DataSource object for our Oracle DB has JNDI name “jdbc/dbs2” in the part of the name space managed by tomcat, or full JNDI name “java:comp/env/jdbc/dbs2”. See http://en.wikipedia.org/wiki/Java_Naming_and_Directory_Interface for more info if interested.

We configure the entries in tomcat’s JNDI by using XML Resource entries in tomcat’s conf/context.xml or conf/server.xml. You see Resource elements with type and name attributes, for the type of object to hold and the name to use to look it up.  The other attributes specify parameters to the constructor or what setters to call, customizing the object.  Notably, the username and password needed for database access are held here, instead of in the app itself.

You need to edit context.xml!

Note that you need to edit your tomcat’s conf/context.xml as indicated on the handout, so that it will use your own DB accounts.  You only have to edit this one file, not the various persistence.xml’s of pizza3 and pizza4.  The web versions (web-persistence.xml under the database directory) all use the JNDI names.  Although named web-persistence.xml under database, they are installed as persistence.xml. See build.xml.

Even a plain JDBC webapp can use JNDI lookup, using the code on the handout, assuming it is being executed in a servlet.

For our webapps using JPA, we need to provide the DataSource object to the JPA provider by configuration, for its startup. Instead of username, password, jdbc URL, etc., we just need to provide one DataSource object.  So the lines in persistence.xml are changed to use a <non-jta-datasource> element.

When tomcat comes up, it reads context.xml and creates the DataSource objects. It needs access to the DB drivers to do this, so they have been put in tomcat’s lib directory.  A web app using a DataSource does not need its own driver jar files.

Threads and Sessions and EntityManagers in a JPA Web App as we have set it up

Each transaction is running in a Java thread, the same thread for the whole transaction and in fact the same thread for the whole request/response cycle, in tomcat’s JVM.

In pizza3, we are using the Java capability of attaching variables to a thread, using the ThreadLocal class.  We’ll use it to hold the em object for the current transaction. By sticking the em on the thread, we can keep our service API objects simple, that is, singletons independent of the threads executing with their help.

How to Handle Concurrency: get an EM and store it in the thread, get it from the thread when needed. Note that we get an EM from the EMF, the entity manager factory, and this object is accessed from each thread, so it needs to be "thread-safe". That means it has internal mutexes designed to let the code safely work under onslaught from multiple threads.

Each thread (thus each transaction) gets its own private EM and with it, the whole persistence unit (PU), the set of domain objects being tracked by the EM. We drew a picture showing the groups of objects for two threads executing concurrently. This, along with the stateless session layer, ensures that no domain objects are shared between threads.

This is key to easy coding of web apps: normal multi-threaded coding is a nightmare. Note that JPA is not essential to this approach. We could use a JDBC layer that produced separate domain objects for each thread.

Implementation of EM/EMF idea: not yet covered in class.

From above: Idea is to get an EM and store it in the thread, get it from the thread when needed. That’s what a ThreadLocal object allows us to do.

In DbDAO.java

privateThreadLocal<EntityManager> threadEM = newThreadLocal<EntityManager>();

public EntityManager getEM() {
       return threadEM.get(); // get this thread's EM
}

public void startTransaction() {
       EntityManager em = emf.createEntityManager();  <---create an EM for txn
       threadEM.set(em); // save in thread-local storage   <--save it "in thread"
       EntityTransaction tx = em.getTransaction();    <--access and start txn
       tx.begin();
}

public void commitTransaction() {
       getEM().getTransaction().commit();
       getEM().close(); // this causes the entities to become detached   
       threadEM.set(null);
}

With this approach, one DAO object can work for many concurrent requests!

So we again can have a single long-lived object graph of singleton service objects and DAO objects. Without this, we would need to create a whole SO-DAO object graph for each request.

Blow by blow, at request time:

Note that the em is active only for the lifetime of the transaction, typically about 50 ms.

If we start another transaction in the same request cycle, we'll get another em, but usually we have only one transaction in a certain request-response cycle. 

 

 

 

 

.