ONJava.com -- The Independent Source for Enterprise Java  
oreilly.comSafari Books Online.Conferences.
 

A Tour Through WebLogic Workshop 8.1: Westside Auto Sales
Pages: 1, 2, 3, 4, 5, 6

Security

When the user hits the "buyCar" link, we want to make them sign in as a registered user. There are plenty of articles on the dev2dev site already on security, so we will simply create a single user and ensure that a prospective buyer signs in as this user to access the buy action. To create the new user, right-click on Security Roles and choose "Create New Role". Name this new role "WASUser" and click "OK". To secure the "buyCar" action, go into WestsideWeb\WEB-INF\web.xml and add the following at the end of the file before the </web-app> tag:

    <security-constraint>
      <display-name>Security Constraint for resources within this project.</
	  display-name> 
    - <web-resource-collection>
          <web-resource-name>Security for the buyCar action
		  </web-resource-name> 
          <description>A web service secured by basic authentication
		  </description> 
          <url-pattern>/Inventory/buyCar.do</url-pattern> 
          <http-method>GET</http-method> 
          <http-method>POST</http-method> 
      </web-resource-collection>
    - <auth-constraint>
          <role-name>WASUser</role-name> 
      </auth-constraint>
      </security-constraint>
    - <security-role>
          <description>A general pre-defined role in WebLogic Server. 
		  All logged in 
		  users are mapped to this role by default.</description> 
            <role-name>WASUser</role-name> 
      </security-role>

This will force the user to log in when they try to buy a car. If they log in as "WASUser" with a password of "password" they can continue. Otherwise they get an error. Go to WestsideWeb\Inventory\Confirm.jsp and add the following code to make it look like the rest of the site:

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
<%@ taglib uri="netui-tags-html.tld" prefix="netui"%>
<%@ taglib uri="netui-tags-template.tld" prefix="netui-template"%>
<netui-template:template templatePage="/resources/jsp/grid_template.jsp">
    <netui-template:setAttribute value="Confirmation" name="title"/>
    <netui-template:section name="bodySection">
        <blockquote>
        <h2>Thank you for your order.</h2><br>
        <a href="InventoryController.jpf">Continue Shopping</a>
        </blockquote>
    </netui-template:section>
</netui-template:template>

Now we need to add the meat of the application - setting the car as sold and ordering a new one. Before we do this, feel free to test the code we have so far. When you hit the buy button, you should be forced to log in. Once you log in successfully, you should get the confirmation page.

Entity Enterprise Java Beans

Because we will be working with individual cars, it would be nice to simply work with a car entity rather than deal with reading and writing fields from a database. Entity EJBs allow us to do this. An entity EJB represents an individual row in a database. It is accessed via member variables, and new rows can be created as easily as creating a new object.

We will use an EJB to access the cars in the inventory table. To do this, first add an EJB project to our application by right-clicking on the top "Westside" folder and choosing "New\Project\EJB Project". Name the new project "WASejb". Right-click on the WASejb folder and choose "New Entity Bean from Database Table". Choose the "WASDataSource", click next, then pick the inventory table. Click "next" twice more and type "CarBean" as the bean name and "Westside" as the package name. Click "Finish". Because we will be adding new rows to the inventory table, we need to add the following at the top of the CarBean.ejb file (code to add in italics):

/**
 * @ejbgen:automatic-key-generation
 *   type="SQL_SERVER" 
 *   cache-size="0" 
 *   name="SQL_SERVER"
 *
 * @ejbgen:entity order-database-operations="false" 
   enable-batch-operations="false"
 *   ejb-name = "CarBean"
 *   data-source-name = "WASDataSource"
 *   table-name = "Inventory"
 *   prim-key-class = "java.lang.Integer"
 *
 * @ejbgen:jndi-name
 *   local = "ejb.CarBeanHome"
 *
 * @ejbgen:file-generation local-class = "true" local-class-name = "Car" 
 local-home = "true" local-home-name = "CarHome" remote-class = "false" 
 remote-class-name = "CarRemote" remote-home = "false" 
 remote-home-name = "CarRemoteHome" value-class = "false" 
 value-class-name = "CarValue" pk-class = "true"
 */

Also, because our db table creates new primary keys for us, we need to modify the create() and ejbPostCreate methods in this file so they do not require any parameters:

  public Java.lang.Integer ejbCreate() 
throws CreateException
  {
    return null;
  }

  public void ejbPostCreate() 
throws CreateException
  {}

Building EJBs used to be a lot of work. In fact, it's one of the most misunderstood areas in J2EE. We've just done all the work we need to do to create our entity bean. To use it, we'll wrap the calls to the bean in an EJB control. This will hide the dirty work of finding or creating the bean when we want to use it. First we need to build and deploy the EJB by right-clicking on the WASejb project and choosing "Build". Now, right-click in the "Controls" directory under WestsideWeb and choose "New Java Control". Choose EJB control, call it "InventoryEJB" and click next. The bean we want is local, so click "Browse local EJBs...", choose the CarBean, and click "Create". This gives us a wrapper for our EJB, which we will use later.

Custom Java Control

Instead of embedding code in the page flow, we will use a custom Java control to handle all the calls to our entity bean and, later, our JMS bean. Both our JPF and the car ordering Web service will share this control. To create the control, right-click on the "Controls" directory and choose "New Custom Java Control". Call it "WASControlImpl" and click "Create". Custom controls have two files: the Java file that describes the control as a class, and the implementation file that contains the actual code of the implementation of this class. We will put all our code in this implementation file. The first thing we need in this file is a method to mark a car as sold. This method will be called by the buyCar action in InventoryController.jpf. To create the method, right-click in the design view of the control and choose "Add Method". Name the method "purchaseCar". Go to design view and modify the method declaration to the following:

/**
 * @common:operation
 */
public String purchaseCar(Integer SKU, String User)
{
    return "";
}

When we call the method, we need to pass in the SKU of the car the user wants to buy along with their user name. We will then mark the car as sold and send a message back to the user confirming they have successfully purchased the car. We will call the method from the "buyCar" action of the JPF. To do this, first drag and drop the WASControl onto InventoryController.jpf. This will create a member variable called wASControl you can use to call the control. Add the following code to the "buyCar" action to call the purchaseCar method (new code in italics):

protected Forward buyCar()
{
  // Call the main control to purchase the car and order a new one
  String OrderText = new String();
  OrderText = wASControl.purchaseCar
  (new Integer(getRequest().getParameter("SKU")), 
  getRequest().getRemoteUser());

  // Put the message in the request string so we can show it on the JSP
  getRequest().setAttribute("Message", OrderText);
                
  return new Forward("success"); }

We first get the SKU sent in the request and the remote user name and send them to the purchaseCar method of the custom control. We then take the resulting message and put it in the request string so we can pull it out and display it to the user on confirm.jps.

Switch back to the design view of WASControl.jcx, and drag and drop the InventoryEJB.jcx onto the control. This will give us a variable named "inventoryEJB" we can use to access the InventoryEJB. Add the following code to the purchaseCar method to set the current car as sold and to create a new vehicle in the database:

public String purchaseCar(Integer SKU, String User)
{
  String OrderText = new String();

  try{
    // Use my entity bean wrapper to access the Inventory EJB
    Car IBean = inventoryEJB.findByPrimaryKey(SKU);

    // Can only sell the car if it is available    
    if (IBean.getStatus().equals("Available"))
    {
	// Set the status of the car to sold
	IBean.setStatus("Sold to " + User);
	OrderText = "Thank you for your order, " + User + ". 
	Your bill is $" + 
	IBean.getPrice() + ".";
	
	// Create a new car based on the old car to 
	replace it in inventory
	Car NewBean = inventoryEJB.create();
	NewBean.setCarID(IBean.getCarID());
	NewBean.setPrice(-1);
	NewBean.setStatus("Waiting to be ordered");	
    }
    else
	// Opps. Someone else got it first. 
	OrderText = "I'm sorry. That vehicle has been sold. 
	Please choose another one.";

  } catch (Exception e){
    OrderText = "Error using EJB: " + e.getMessage();
  }
       
  return OrderText;
}

Again, you will want to hit "Alt+Enter" when prompted to add "Westside.Car" as an import statement. Back in WestsideWeb\Inventory\Confirm.jsp we need to show the message generated by the call to the WASControl to the user. The JPF put the message in the request stream, so we just need to pull it out (new code in italics):

<h2>Thank you for your order.</h2><br>
<%= request.getAttribute("Message") %><p>
<a href="InventoryController.jpf">Continue Shopping</a>

At this point, we can try the app out. From the details page of a car, click the buy link. Once you log in you will see a confirmation on Confim.jsp. When you return to the inventory, you will see the car marked as sold to that user, and a new car in the database with a status of "Waiting to be ordered". In the next section, we will use JMS to send a message to a message-driven bean to order another car from the manufacturer.

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow