CS636 Class 21: hw5 available,  due next Mon.

Note on possible spurious ORA-08177 errors: Last time we looked at context.xml with the following entry for Oracle:

<Resource auth="Container" defaultAutoCommit="false" defaultTransactionIsolation="SERIALIZABLE" driverClassName="oracle.jdbc.OracleDriver" maxActive="8" maxIdle="4" name="jdbc/dbs3" password="xxxxx" type="javax.sql.DataSource" url="jdbc:oracle:thin@dbs3.cs.umb.edu:1521:dbs3" username="xxxxx"/>

I've seen off-and-on ORA-08177 errors "can't serialize access for this transaction".  These are related to serializable execution.
If you have trouble with this error, simply remove the defaultTransactionIsolation="SERIALIZABLE" part of this XML element, so that your program executes with the default READ COMMITTED isolation, which is sufficient for our applications.

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. (Alternatively, we could create per-request service and DAO objects, giving up the use of singletons.)

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.

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.

At init time: call PizzaSystemConfig.configureServices() from servlet init(), unless it has already been set up (find out by calling PizzaSystemConfig.getStudentService() and seeing if the returned value is null or not)

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. 

Last time: moving the system into the web container, using SysTestServlet, a special-case servlet

Two production servlets in pizza3:

You can use either model in music3

The pizza3 view pages:

These URLS “.../WEB-INF/jsp/...) are not used in JSPs of the app. Instead, all URLs (except the initial URL used to start the app) in the web app point to the servlet using xxx.html names, for example, in orderForm.jsp:

    <c:url var="orderPizzaURL" value="orderPizza.html" />

    <!--change to method="post" when development is done -->
    <form method="get" action="${orderPizzaURL}">

This generates HTML with a URL of form xxx.html. This goes back to the browser where the user sees the form.

    <form method="get" action="orderPizza.html">

In web.xml: URL mapping for DispatcherServlet:

       <servlet-mapping>
              <servlet-name>DispatcherServlet</servlet-name>
              <url-pattern>*.html</url-pattern>            ---URL relative to servlet context
       </servlet-mapping>

The submit of the  pizza order form with action=orderPizza.html goes to the DispatcherServlet

 In more detail, worrying about the directory involved, since this is a relative URL.

This action=orderPizza.html goes back in the HTML of the response. The browser has used a URL like

http://localhost:8080/pizza3/studentWelcome.html to get to the last page, so the browser uses

http://localhost:8080/pizza3/orderPizza.html to submit the form, and this is orderPizza.html relative to the pizza3 servlet context

In the servlet (DispatcherServlet), the incoming URL is examined, and it determines what processing to do and forwards to the appropriate jsp. The browser never sees a URL in the jsp area--it's secret to the servlet.

 The DispatcherServlet’s work is to handle the incoming request and determine what to forward to. The work for one action (one incoming URL) is

In DispatcherServlet, the work for one action (one incoming URL) is abstracted into a Controller object, that is, an object that implements the Controller interface:

package cs636.pizza.presentation.web;

import …

// Each controller does the guts of doGet/doPost
// via handleRequest declared here
public interface Controller {
     // return forward-to URL
     String handleRequest(HttpServletRequest request,
              HttpServletResponse response)
     throws IOException, ServletException;
}

For example, the order form has an OrderFormContoller that implements Controller. Its object (a singleton) is created at startup of DispatcherServlet. This Controller object then goes on to handle all the requests that are order form submissions.

In OrderFormController, handleRequest does the following:

--gets all sizes and toppings from the DB, using studentService ref provided at construction time

--attaches these sets to request attributes “allSizes” and “allToppings”

--also sets request attribute “numRooms” to 10

--return the String URL “/WEB-INF/jsp/orderForm.jsp”, which was provided at contruction time

All the incoming student-action requests get handled by DispatcherServlet, which looks at the URL and calls the appropriate controller. The controller Java code does the business logic and loads up some session and/or request variables with the results that need display to the user. Finally, the controller forwards the request to a URL which is often a JSP to compose the HTML of the response, or back to the servlet if necessary.

DispatcherServlet

We have one master servlet for student pages, DispatcherServlet, which calls various controllers

Servlet gets the actual URL by using request.getServletPath(), so it knows what Controller to call on.

We can make a table of cases:

Request URL                              Controller                             forward-to-URL (for “view” or further servlet processing)

/welcome.html           ---                         /welcome.jsp

/studentWelcome.html    StudentWelcomeController    /WEB-INF/jsp/studentWelcome.jsp

/orderForm.html         OrderFormController         /WEB-INF/jsp/orderForm.jsp

/orderPizza.html        OrderPizzaController        /WEB-INF/jsp/studentWelcome.html
                                                OR
/WEB-INF/jsp/orderForm.html for form resubmission

/orderReceive.html      OrderReceiveController      /WEB-INF/jsp/studentWelcome.jsp


Note that the URLs here are “servlet-context-relative”, so /welcome.html means .../pizza3/welcome.html, etc.

Here we see studentWelcome.jsp as the page displayed after the OrderFormController runs, and also after the OrderPizzaController runs successfully (student actually ordered something, not needing resubmission of form), and after the OrderReceiveController runs. This just means that the student welcome page is redisplayed originally when the student selects this service, again after they order a pizza, and again after they acknowledge receipt of pizza, showing them the changes to their collection of orders.

Note there are only two pages in the page flow for the student actions, ones generated by studentWelcome.jsp and orderForm.jsp. We already determined this in hw3--see the page flow diagrem its solution

The complicated case is when a form is submitted with unusable input. For example, the user is trying to order Mushrooms as a topping, but meanwhile the admin deleted that topping. Then the user submits the form using URL orderForm.html, the DispatcherServlet does the validation, decides it failed, and forwards to URL orderForm.html, i.e., forwards to itself as a servlet. Then the DispatcherServlet is reentered (with the same request and response objects) and goes to the OrderFormController, and forwards to orderForm.jsp.

UI in general for a Collection of objects. Here the UI has to manage various collections of objects: student orders or a room, toppings, sizes, days, all orders. The pattern we use is to display the collection on the "main" page, and provide a link or form for additions and updates and deletions from the collection, causing redisplay of the main page to show the new collection. 

When the order form is completed successfully by the user, the servlet actually redirects to /studentWelcome.html instead of forwarding to it, to change the URL known to the browser, so that a refresh of the page does not re-POST the form, but rather only re-GETs the result page. A complete (long-winded) discussion is  in http://www.theserverside.com/news/1365146/Redirect-After-Post

AdminServlet

Note that there is another servlet for the admin pages, AdminServlet, with url-mapping:

       <servlet-mapping>
              <servlet-name>AdminServlet</servlet-name>
              <url-pattern>/adminController/*</url-pattern>
     </servlet-mapping>

Thus any URL like … /pizza3/adminController/xxx will be handled by this servlet

See in sidebar.jsp:

<c:url var="adminWelcomeURL" value="/adminController/adminWelcome.html" />

...

     <a href="${adminWelcomeURL}">Admin Service</a><br>


Here the URL in c:url starts with /, which means app-context-relative URL, a nice feature of c:url discussed on pg. 286. That means this URL turns into /pizza3/adminController/adminWelcome.html in the HTML, a doc-root-relative URL.AKA "relative to webapps directory" URL, covered on pg. 101.  (webapps is tomcat's document root as a web server.)   Since sidebar.jsp is included in several pages, an ordinary relative URL isn't useful.

You can drop the use of <c: url if you want, but then there is no concept of app-relative URLs. You can use instead the one line:

     <a href="/pizza3/adminController/adminWelcome.html">Admin Service</a><br>

but then it doesn't work under another webapp name, like pizza3a. Note that this HTML URL is also a document-root relative URL.

Either way, (with or without c:url), when the user clicks the “Admin Service” link, their request is handled by AdminController, and this sets the browser’s concept of current server directory to /pizza3/adminController, so relative URLs in the view JSPs work to stay in this area.

Example: in toppingView.jsp: <c:url var="toppingsURL" value="toppings"/>

<form action="${toppingsURL}" method="post">

---or alternatively just---

<form action="toppings" method="post">

Here "toppings" is a relative URL to the browser-known current directory /pizza3/adminController, so the full URL will be ... /pizza3/adminController/toppings, and fit the url-mapping of the AdminController.

As mentioned before, the AdminServlet is coded in a less structured way than DispatcherServlet. It doesn’t use Controllers, but we could still set up a table showing request URLs and forward-to targets: ADMIN_JSP_DIR="/WEB-INF/admin/"

Request URL                                                        forward-to-URL (for “view” or further servlet processing)
                                                                                 (assuming no errors)

/adminController/adminWelcome.html        ADMIN_JSP_DIR + "adminWelcome.jsp”

/adminController/toppings                 ADMIN_JSP_DIR + "toppingView.jsp”

/adminController/sizes                    ADMIN_JSP_DIR + "sizeView.jsp”   

/adminController/orders                   ADMIN_JSP_DIR + "orderView.jsp”

/adminController/days                     ADMIN_JSP_DIR + "dayView.jsp"

/adminController/initializeDB.html        ADMIN_JSP_DIR + "initializeDB.jsp"

 Note: There is no form resubmission here.