An Introduction to LDAP

Configuring a Data Source

In the following sections, we show you how to configure a data source in your application server, such as GlassFish and Tomcat, and how to access the data source from a web application.

Configuring a Database Resource in GlassFish

GlassFish has a convenient web-based administration interface that you can use to configure a data source. Point your browser to http://localhost:4848 and log on. (The default username is admin and the default password is adminadmin.)

First, configure a database pool. Select "Connection Pools" and set up a new pool. Give a name to the pool, select a resource type (javax.sql.DataSource), and pick your database vendor (see Figure 10-1).

Figure 10-1. Configuring a connection pool in GlassFish


On the next screen, you specify database connection options such as username and password (see Figure 10-2).

Figure 10-2. Specifying database connection options


Next, you configure a new data source. Give it the name jdbc/mydb and select the pool that you just set up (see Figure 10-3).

Figure 10-3. Configuring a data source


Finally, you need to place the database driver file (such as postgresql-8.2.jdbc3.jar for the PostgreSQL database) into the domains/domain1/lib/ext subdirectory of your GlassFish installation.

Configuring a Database Resource in Tomcat

In this section, we walk you through the steps of configuring a database resource pool in the Tomcat 5 container. If you do not use Tomcat, just skip this section.

Locate the conf/server.xml file and look for the element that describes the host that will contain your web application, such as

  <!-- Define the default virtual host -->   <Host name="localhost" debug="0" appBase="webapps"      unpackWARs="false" autoDeploy="true">   ...   </Host>

Inside this element, place a DefaultContext element that specifies both the database details (driver, URL, username, and password) and the desired characteristics of the pool.

Here is a typical example, specifying a connection pool to a PostgreSQL database. The values that you need to customize are highlighted in bold.

  <DefaultContext>      <Resource name="jdbc/mydb" auth="Container"         type="javax.sql.DataSource"/>      <ResourceParams name="jdbc/mydb">         <parameter>            <name>factory</name>             <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>         </parameter>         <parameter>            <name>driverClassName</name>            <value>org.postgresql.Driver</value>         </parameter>         <parameter>            <name>url</name>            <value>jdbc:postgresql://127.0.0.1:5432/postgres</value>         </parameter>         <parameter>           <name>username</name>            <value>dbuser</value>         </parameter>         <parameter>            <name>password</name>            <value>dbpassword</value>         </parameter>         <parameter>            <name>maxActive</name>            <value>20</value>         </parameter>         <parameter>            <name>maxIdle</name>            <value>10</value>         </parameter>         <parameter>            <name>poolPreparedStatements</name>            <value>true</value>         </parameter>      </ResourceParams>   </DefaultContext>     

Note

You can also add the Resource and ResourceParams elements into the context of a specific web application. Then the data source is available only to that application.


To configure the pool, you specify a sequence of parameters (see Table 10-1 for the most common ones). A complete description of all valid parameters can be found at http://jakarta.apache.org/commons/dbcp/configuration.html.

Table 10-1. Common Tomcat Database Pool Parameters
Parameter Name Description
driverClassName The name of the JDBC driver, such as org.postgresql.Driver
url The database URL, such as jdbc:postgresql:mydb
username The database username
password The password of the database user
maxActive The maximum number of simultaneous active connections, or zero for no limit
maxIdle The maximum number of active connections that can remain idle in the pool without extra ones being released, or zero for no limit
poolPreparedStatements true if prepared statements are pooled (default: false)
removeAbandoned true if the pool should remove connections that appear to be abandoned (default: false)
removeAbandonedTimeout The number of seconds after which an unused connection is considered abandoned (default: 300)
logAbandoned true to log a stack trace of the code that abandoned the connection (default: false)


To activate the pooling of prepared statements, be sure to set poolPreparedStatements to true.

The last three parameters in Table 10-1 refer to a useful feature of the Tomcat pool. The pool can be instructed to monitor and remove connections that appear to be abandoned. If a connection has not been used for some time, then it is likely that an application forgot to close it.

After all, a web application should always close its database connections after rendering the response to a user request. The pool can recycle unused connections and optionally log these events. The logging is useful for debugging because it allows the application programmer to plug connection leaks.

Place the database driver file into Tomcat's common/lib directory. If the database driver file has a .zip extension, you need to rename it to .jar, such as classes12.jar for the Oracle database.

Tip

You can find detailed configuration instructions for a number of popular databases at http://jakarta.apache.org/tomcat/tomcat-5.5-doc/jndi-datasource-examples-howto.html.


Accessing a Container-Managed Resource

The Java EE specification requires that resources are declared in the web.xml file of your web application. For a data source, add the following entry to your web.xml file:

  <resource-ref>      <res-ref-name>jdbc/mydb</res-ref-name>      <res-type>javax.sql.DataSource</res-type>      <res-auth>Container</res-auth>   </resource-ref>

Note the name of the resource: jdbc/mydb. That name is used to look up the data source. There are two ways for doing the lookup. The most elegant one is resource injection. You declare a field in a managed bean and mark it with an annotation, like this:

  @Resource(name="jdbc/mydb")   private DataSource source;

When the application server loads the managed bean, then the field is automatically initialized.

This feature works only in an application server that conforms to the Java EE 5 standard. If you use JSF 1.1 or the standalone Tomcat server, you have to work a little harder, and make a JNDI (Java Naming and Directory Interface) lookup yourself:

  try {      InitialContext ctx = new InitialContext();      source = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");   }   catch (NamingException ex) {      . . .   }

The java:comp/env prefix is the standard JNDI directory lookup path to the component environment in a Java EE container. By convention, you place JDBC resources in the jdbc subpath. It is up to you how to name the individual resources.

Caution

GlassFish distinguishes beween "resource reference" names and JNDI names. For most resources, you need to specify a mapping in the sun-web.xml file (see page 489 for an example). However, for JDBC resources, no mapping is required.


Of course, for such a simple lookup, the @Resource annotation is only a minor convenience. However, other resource initializations are more complex. For another example of resource injection, see the section "Using Web Services" on page 516. There, we show you how to inject a web service port with a simple annotation. Without resource injection, we would need to access unsightly helper classes.

To be consistent, we like to use the annotation mechanism to initialize all resources. Table 10-2 lists the annotations that you can use to inject resources.

Table 10-2. Annotations for Resource Injection
Annotation Resource Type

  @Resource   @Resources

Arbitrary JNDI Resource

  @WebServiceRef   @WebServiceRefs

Web service port

  @EJB   @EJBs

EJB Session Bean

  @PersistenceContext   @PersistenceContexts

Persistent Entity Manager

  @PersistenceUnit   @PersistenceUnits

Persistent Entity Manager Factory


A Complete Database Example

In this example, we show you how to verify a username/password combination. As with the example program in Chapter 1, we start with a simple login screen (Figure 10-4). If the username/password combination is correct, we show a welcome screen (Figure 10-5). Otherwise, we prompt the user to try again (Figure 10-6). Finally, if a database error occurred, we show an error screen (Figure 10-7).

Figure 10-4. Login screen


Figure 10-5. Welcome screen


Figure 10-6. Authentication error screen


Figure 10-7. Internal error screen


Thus, we have four JSF pages, shown in Listing 10-1 through Listing 10-4. Listing 10-5 shows the faces-config.xml file with the navigation rules. The navigation rules use the loginAction and logoutAction properties of the UserBean class. Listing 10-6 gives the code for the UserBean.

In our simple example, we add the database code directly into the UserBean class. It would also be possible to have two layers of objects: beans for communication with the JSF pages, and data access objects that represent entities in the database.

We place the code for database access into the separate method:

  public void doLogin() throws SQLException

That method queries the database for the username/password combination and sets the loggedIn field to true if the username and password match.

The button on the index.jsp page references the login method of the user bean. That method calls the doLogin method and returns a result string for the navigation handler. The login method also deals with exceptions that the doLogin method reports.

We assume that the doLogin method is focused on the database, not the user interface. If an exception occurs, doLogin should report it and take no further action. The login method, on the other hand, logs exceptions and returns a result string "internalError" to the navigation handler.

  public String login() {      try {         doLogin();      }      catch (SQLException ex) {         logger.log(Level.SEVERE, "loginAction", ex);         return "internalError";      }      if (loggedIn)         return "loginSuccess";      else         return "loginFailure";   }

Before running this example, you need to start your database and create a table named Users and add one or more username/password entries:

  CREATE TABLE Users (username CHAR(20), password CHAR(20))   INSERT INTO Users VALUES ('troosevelt', 'jabberwock')

You can then deploy and test your application.

Figure 10-8 shows the directory structure for this application, and Figure 10-9 shows the navigation map. The before mentioned application files follow in Listing 10-1 through Listing 10-6.

Figure 10-8. Directory structure of the database application


Figure 10-9. Navigation map of the database application


Note

Lots of things can go wrong with database configurations. If the application has an internal error, look at the log file. In GlassFish, the default log file is domains/domain1/logs/server.log. In Tomcat, it is logs/catalina.out.


Listing 10-1. db/web/index.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <h1><h:outputText value="#{msgs.enterNameAndPassword}"/></h1>  11.             <h:panelGrid columns="2">  12.                <h:outputText value="#{msgs.name}"/>  13.                <h:inputText value="#{user.name}"/>  14.  15.                <h:outputText value="#{msgs.password}"/>  16.                <h:inputSecret value="#{user.password}"/>  17.             </h:panelGrid>  18.             <h:commandButton value="#{msgs.login}" action="#{user.login}"/>  19.          </h:form>  20.       </body>  21.    </f:view>  22. </html>     

Listing 10-2. db/web/welcome.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <p>  11.                <h:outputText value="#{msgs.welcome}"/>  12.                <h:outputText value="#{user.name}"/>!  13.             </p>  14.             <p>  15.                <h:commandButton value="#{msgs.logout}" action="#{user.logout}"/>  16.             </p>  17.          </h:form>  18.       </body>  19.    </f:view>  20. </html>     

Listing 10-3. db/web/sorry.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <h1><h:outputText value="#{msgs.authError}"/></h1>  11.             <p>  12.                <h:outputText value="#{msgs.authError_detail}"/>!  13.             </p>  14.             <p>  15.                <h:commandButton value="#{msgs.continue}" action="login"/>  16.             </p>  17.          </h:form>  18.       </body>  19.    </f:view>  20. </html>     

Listing 10-4. db/web/error.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <h1><h:outputText value="#{msgs.internalError}"/></h1>  11.             <p><h:outputText value="#{msgs.internalError_detail}"/></p>  12.             <p>  13.                <h:commandButton value="#{msgs.continue}" action="login"/>  14.             </p>  15.          </h:form>  16.       </body>  17.    </f:view>  18. </html>     

Listing 10-5. db/web/WEB-INF/faces-config.xml

  1. <?xml version="1.0"?>   2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.       http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"   6.    version="1.2">   7.    <navigation-rule>   8.       <from-view-id>/index.jsp</from-view-id>   9.       <navigation-case>  10.          <from-outcome>loginSuccess</from-outcome>  11.          <to-view-id>/welcome.jsp</to-view-id>  12.       </navigation-case>  13.       <navigation-case>  14.          <from-outcome>loginFailure</from-outcome>  15.          <to-view-id>/sorry.jsp</to-view-id>  16.       </navigation-case>  17.       <navigation-case>  18.          <from-outcome>internalError</from-outcome>  19.          <to-view-id>/error.jsp</to-view-id>  20.       </navigation-case>  21.    </navigation-rule>  22.    <navigation-rule>  23.       <from-view-id>/welcome.jsp</from-view-id>  24.       <navigation-case>  25.          <from-outcome>login</from-outcome>  26.          <to-view-id>/index.jsp</to-view-id>  27.       </navigation-case>  28.    </navigation-rule>  29.    <navigation-rule>  30.       <from-view-id>/sorry.jsp</from-view-id>  31.       <navigation-case>  32.          <from-outcome>login</from-outcome>  33.          <to-view-id>/index.jsp</to-view-id>  34.       </navigation-case>  35.    </navigation-rule>  36.    <navigation-rule>  37.       <from-view-id>/error.jsp</from-view-id>  38.       <navigation-case>  39.          <from-outcome>login</from-outcome>  40.          <to-view-id>/index.jsp</to-view-id>  41.       </navigation-case>  42.    </navigation-rule>  43.  44.    <managed-bean>  45.       <managed-bean-name>user</managed-bean-name>  46.       <managed-bean-class>com.corejsf.UserBean</managed-bean-class>  47.       <managed-bean-scope>session</managed-bean-scope>  48.    </managed-bean>  49.  50.    <application>  51.       <resource-bundle>  52.          <base-name>com.corejsf.messages</base-name>  53.          <var>msgs</var>  54.       </resource-bundle>  55.    </application>  56. </faces-config>     

Listing 10-6. db/src/java/com/corejsf/UserBean.java

  1. package com.corejsf;   2.   3. import java.sql.Connection;   4. import java.sql.PreparedStatement;   5. import java.sql.ResultSet;   6. import java.sql.SQLException;   7. import java.util.logging.Level;   8. import java.util.logging.Logger;   9.  10. import javax.annotation.Resource;  11. import javax.sql.DataSource;  12.  13. public class UserBean {  14.    private String name;  15.    private String password;  16.    private boolean loggedIn;  17.    private Logger logger = Logger.getLogger("com.corejsf");  18.  19.    @Resource(name="jdbc/mydb")  20.    private DataSource ds;  21.  22.    /*  23.    If you use Tomcat or JSF 1.1, remove the @Resource line and add this constructor:  24.    public UserBean()  25.    {  26.       try {  27.          Context ctx = new InitialContext();  28.          ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");  29.       } catch (NamingException ex) {  30.          logger.log(Level.SEVERE, "DataSource lookup failed", ex);  31.       }  32.    }  33.    */  34.  35.    public String getName() { return name; }  36.    public void setName(String newValue) { name = newValue; }  37.  38.    public String getPassword() { return password; }  39.    public void setPassword(String newValue) { password = newValue; }  40.  41.    public String login() {  42.       try {  43.          doLogin();  44.       }  45.       catch (SQLException ex) {  46.          logger.log(Level.SEVERE, "login failed", ex);  47.          return "internalError";  48.       }  49.       if (loggedIn)  50.          return "loginSuccess";  51.       else  52.          return "loginFailure";  53.    }  54.  55.    public String logout() {  56.       loggedIn = false;  57.       return "login";  58.    }  59.  60.    public void doLogin() throws SQLException {  61.       if (ds == null) throw new SQLException("No data source");  62.       Connection conn = ds.getConnection();  63.       if (conn == null) throw new SQLException("No connection");  64.  65.       try {  66.          PreparedStatement passwordQuery = conn.prepareStatement(  67.             "SELECT password from Users WHERE username = ?");  68.  69.          passwordQuery.setString(1, name);  70.  71.          ResultSet result = passwordQuery.executeQuery();  72.  73.          if (!result.next()) return;  74.          String storedPassword = result.getString("password");  75.          loggedIn = password.equals(storedPassword.trim());  76.       }  77.       finally {  78.          conn.close();  79.       }  80.    }  81. }     



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net