아파치 톰캣 서블릿/JSP 컨테이너

아파치 톰캣 7

Version 7.0.28-dev, Oct 2 2013
Apache Logo

Links

User Guide

참고

아파치 톰캣 개발

JNDI 자원 활용법

목차
소개

톰캣은 JNDI(Java Naming and Directory Interface)에서 각각의 웹 애플리케이션의 실행을 위해, 최초 컨텍스트를 구현할 인스턴스(instance)를 적절한 방식으로 제공하고, 자바 엔터프라이즈 에디션프로그램 서버에 의해 호환이 가능하게 지원된다. 자바 EE 스탠다드는 /WEB-INF/web.xml 파일의 내부에서 요소들의 기준이 되는 세트로 "참조사항/정의된 경로의 자원"를 제공한다.

JNDI의 원활한 사용을 위해 프로그래밍 API(Application Programming Interface)에 대한 많은 정보를 위해 아래에 열거된 사항을 참고하며,자바 엔터프라이즈 에디션(Java EE)서버에 의해 지원되는 여러 기능들(자바 엔터프라이즈 에디션(Java EE) 서버가 제공하는 서비스에 의한 톰캣 에뮬레이트)을 보라:

web.xml 환경설정

자원을 정의하기 위한 사용자의 웹 애플리케이션의 웹 애플리케이션 개발에 관련한 내용을 기록하는 파일(/WEB-INF/web.xml)내에 다음의 요소들이 사용되고 있을 수도 있다.:

  • <env-entry> - 환경 설정에 있어서, 해당 애플리케이션이 어떻게 작동할 것인지 환경설정을 하기 위해 오직 하나의 값을 가진 인자가 사용되곤 한다.
  • <resource-ref> - 리소스의 참조하는 것은, 보통 오브젝트 팩토리로 예를 들자면, JDBC의DataSource와 자바메일의 Session자원을 참조하는 것이거나 커스텀 오브젝트 팩토리가 톰캣 안에 환경설정에 반영되는 것이다.
  • <resource-env-ref> - 리소스 환경 참조사항에서, 서블릿 2.4 내에서 추가된 resource-ref의 새로운 변수는 리소스 때문에 환경설정을 하기 위하여 더 단순하고, 관리자 정보를 요구하지 않는다.

톰캣은 어떤 적절한 리소스 팩토리를 규정하고 사용하며 그 리소스를 정의하기 위해 더 이상 추가할 필요없는 정보를 제공할 것이고, 톰캣은 /WEB-INF/web.xml에서 리소스를 만들기 위해 정보를 사용한다.

context.xml 환경설정

만약 톰캣이 적절한 리소스 팩토리를 정의할 수 없고(혹은 없거나) 추가적인 환경설정이 요구된다면, 추가적인 톰캣의 특별한 환경설정은 반드시 톰캣으로 리소스를 만들기 전에 명시되어져야 한다. 톰캣의 명시하는 리소스 환경설정은 <Context>의 요소에 들어가져 있다. 톰캣의 특별한 리소스 환경설정은 <에 들어가서 할 수 있고, Context> 속성에는 $CATALINA_BASE/conf/server.xml에 상세화 되어 있거나, 오히려, 퍼-웹-어플리케이션 컨텍스트 XML 파일에(META-INF/context.xml)되어 있을수도 있다.

톰캣의 상세한 리소스 환경설정은 다음의 사용하고 있는 속성에서 <Context> 운영되고 있다 :

  • <환경> - 전반적으로 자세한 내용을 위해 환경설정 이름과 값을 JNDI를 통해 웹 어플리케이션에 노출시킬 것이다. InitialContext (웹 어클리케이션 배치 디스크립터에서 <env-entry> 속성이 포함한 것과 맞먹는 것이다.
  • <리소스> - 해당 어플리케이션에 이용할 수 있는 리소스의 데이터종류와 이름을 설정하라. (웹 어플리케이션 배치 설정에서<resource-ref> 속성에 동시에 포함하고 있는 것으로 정한다).
  • <리소스 링크> - 글로벌 JNDI 컨텍스트에 어떤 리소스의 링크를 정의하고 추가하라. Use resource links to give a web application access to a resource defined in the <GlobalNamingResources> child element of the <Server> element.
  • <트랜잭션 (단말의 이용자가 중앙처리시스템에 서비스를 요구하는 작업의 단위)> - java:comp/UserTransaction에서 가능한 사용자 트랜잭션 오브젝트 인스턴스를 예를 들어서 하나의 리소스 팩토리를 추가하라.

이러한 요소들의 몇몇은 <Context> 요소들이 포함되어 있을 수도 있고 오직 특정 웹 어플리케이션에서만 같이 있게 될 것이다.

만약 어떤 리소스가 <Context>속성 내부에 정의 된다면, 그것은 /WEB-INF/web.xml파일에 반드시 정의되야 하는 것은 아니다. 그러나, 웹 어플리케이션을 위해 리소스에 필수조건으로 해당문서의 /WEB-INF/web.xml에 입력하는 것을 권장한다.

웹 어플리케이션 배치 기술자(/WEB-INF/web.xml)에 포함된 <env-entry>속성에 대해 동일한 리소스가 정의되어 있고, <Environment>속성내에 웹 어클리케이션을 위한 <Context>속성의 한 부분으로서, 배치 기술자 파일내의 값들은 오로지 만약 <Environment>속성에서("true"로 override 설정함으로서)답신하는 것에 따라서 허락되었을 때 우선권을 가진다.

글로벌 환경설정

톰캣은 전체적인 서버를 위해서 다수의 글로벌 리소스 각각의 이름을 지정할 수 있는 공간을 유지한다. $CATALINA_BASE/conf/server.xml <GlobalNamingResources>속성에서 환경설정을 할 수 있다. 사용자는 각각의-웹-어플리케이션 컨텍스트(per-web-application)내에 <리소스 링크>를 포함하고 사용함으로서 웹 어플리케이션에 이러한 자원들을 노출할 수도 있다.

어떠한 자원이 <리소스 링크>로 사용하는 것이 정의되었다면, 그것이 필수적으로 /WEB-INF/web.xml내에 리소스가 정의되는 것은 아니다. 그러나 /WEB-INF/web.xml안에 해당 웹어플리케이션을 위한 리소스의 필수조건을 기록하기 위해서 전체적으로 들어가 있는 것을 추천한다.

리소스를 사용하는 것

InitialContext(이니셜 컨텍스트)는 웹 어플리케이션이 최초로 배치됨으로서 환경설정이 되고 웹 어플리케이션 컴포넌트에 만들어진다.(오로지 읽기전용을 위해서) 모든 설정된 영역과 리소스들은 JNDI명이 저장된 곳의 부분적인 공간java:comp/env내에 지정되고, 또한 리소스에 일반적인 접근이 있다. 이런 경우는 JDBC의 DataSource와 같이 뭔가를 바라보는 경우이다.

// 컨텍스트를 설정하여 적합한 환경을 구성한다.
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");

// 데이터소스를 바라본다.
DataSource ds = (DataSource)
  envCtx.lookup("jdbc/EmployeeDB");

// 할당하고 풀로부터 어떤 커넥션객체를 사용한다.
Connection conn = ds.getConnection();
... 데이터베이스의 접속을 위해 이 커넥션객체를 사용한다...
conn.close();
톰캣 표준 리소스팩토리들

톰캣은 표준 리소스 팩토리에서 당신의 웹 어플리케이션 서비스를 제공할 수 있는 기능을 가지고 있으나, 배치 기술자나 웹 어플리케이션의 변경없이( <컨텍스트> 속성을 통해서) 사용자 중심의 환경설정이 가능하다. 표준 리소스 팩토리들의 사용접과 환경설정을 아래와 같이 각각의 세부항목을 보고 참고하라.

여기 생성하는 방법에 대한 정보와 설치, 환경설정과 톰캣과 함께 사용자의 맞춤형 리소스 팩토리 클래스를 사용하는 것에 대한 추가된 맞춤형 리소스 팩토리를 보라.

주의사항 - 표준 리소스 팩토리들 중에서, 오직 "JDBC 데이터소스"와 "사용자 처리" 팩토리들은 다른 플랫폼들에서 사용 할 수 있는 권한을 갖게 되고, "JDBC 데이터소스"와 "사용자 처리" 팩토리들은 해당 플랫폼이 자바 엔터프라이즈 에디션(Java EE) 조건을 실행할 수 있어야만 사용할 수 있게된다. 모든 그밖의 표준 리소스 팩도리들은, 거기에 더해서 사용자가 직접 작성한 커스텀 리소스 팩토리들은, 특히 톰캣과 그밖에 다른 컨테이너들에서 작동할 수 없게 되어있다.

일반적인 자바빈 리소스들

0. 소개

이 리소스 팩토리는 불특정 다수의자바 클래스 객체를 제작하기 위해 만들어질 수 있으며. 표준 자바빈을 정의하는 약속을 확인한다.(즉, 이것은 아무것도 없는 인자값 수행을 하며, 그리고 해당 setFoo() 메소드의 네이밍 패턴에서 속성 지시자를 확인한다. 해당 리소스 팩토리는 적절한 빈 클래스의 새로운 인스턴스를 매시간마다 만들어진 엔트리를 위해 lookup() 을 만든다.

이 과정은 아래에 기술된 내용을 사용하는 것이 요구된다.

1. 사용자의 자바빈 클래스 만들기

자바빈 클래스를 리소스 팩토리가 볼 수 있게 각각의 시간마다 예시로 설명하게 만들어라. 이러한 예시에서, 아래와 같다면 사용자가 com.mycompany.MyBean를 만든것으로 추정한다:

package com.mycompany;

public class MyBean {

  private String foo = "Default Foo";

  public String getFoo() {
    return (this.foo);
  }

  public void setFoo(String foo) {
    this.foo = foo;
  }

  private int bar = 0;

  public int getBar() {
    return (this.bar);
  }

  public void setBar(int bar) {
    this.bar = bar;
  }


}

2. 사용자 자원 필수조건 제시

다음으로,사용자의 웹 어클리케이션 배치 기술자 (/WEB-INF/web.xml)를 JNDI 이름밑에 빈(Bean)의 새로운 인스턴스를 요청할 것으로 선언하고 변경하라. The simplest approach is to use a <resource-env-ref> element, like this:

<resource-env-ref>
  <description>
    Object factory for MyBean instances.
  </description>
  <resource-env-ref-name>
    bean/MyBeanFactory
  </resource-env-ref-name>
  <resource-env-ref-type>
    com.mycompany.MyBean
  </resource-env-ref-type>
</resource-env-ref>

WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

3. Code Your Application's Use Of This Resource

A typical use of this resource environment reference might look like this:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");

writer.println("foo = " + bean.getFoo() + ", bar = " +
               bean.getBar());

4. Configure Tomcat's Resource Factory

To configure Tomcat's resource factory, add an element like this to the <Context> element for this web application.

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="org.apache.naming.factory.BeanFactory"
            bar="23"/>
  ...
</Context>

Note that the resource name (here, bean/MyBeanFactory must match the value specified in the web application deployment descriptor. We are also initializing the value of the bar property, which will cause setBar(23) to be called before the new bean is returned. Because we are not initializing the foo property (although we could have), the bean will contain whatever default value is set up by its constructor.

UserDatabase Resources

0. Introduction

UserDatabase resources are typically configured as global resources for use by a UserDatabase realm. Tomcat includes a UserDatabaseFactoory that creates UserDatabase resources backed by an XML file - usually tomcat-users.xml

The steps required to set up a global UserDatabase resource are described below.

1. Create/edit the XML file

The XMl file is typically located at $CATALINA_BASE/conf/tomcat-users.xml however, you are free to locate the file anywhere on the file system. It is recommended that the XML files are placed in $CATALINA_BASE/conf. A typical XML would look like:

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="tomcat" roles="tomcat"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>

2. Declare Your Resource

Next, modify $CATALINA_BASE/conf/server.xml to create the UserDatabase resource based on your XMl file. It should look something like this:

<Resource name="UserDatabase"
          auth="Container"
          type="org.apache.catalina.UserDatabase"
          description="User database that can be updated and saved"
          factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/tomcat-users.xml"
          readonly="false" />

The pathname attribute can be absolute or relative. If relative, it is relative to $CATALINA_BASE.

The readonly attribute is optional and defaults to true if not supplied. If the XML is writeable then it will be written to when Tomcat starts. WARNING: When the file is written it will inherit the default file permissions for the user Tomcat is running as. Ensure that these are appropriate to maintain the security of your installation.

3. Configure the Realm

Configure a UserDatabase Realm to use this resource as described in the Realm configuration documentation.

JavaMail Sessions

0. Introduction

In many web applications, sending electronic mail messages is a required part of the system's functionality. The Java Mail API makes this process relatively straightforward, but requires many configuration details that the client application must be aware of (including the name of the SMTP host to be used for message sending).

Tomcat includes a standard resource factory that will create javax.mail.Session session instances for you, already configured to connect to an SMTP server. In this way, the application is totally insulated from changes in the email server configuration environment - it simply asks for, and receives, a preconfigured session whenever needed.

The steps required for this are outlined below.

1. Declare Your Resource Requirements

The first thing you should do is modify the web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will look up preconfigured sessions. By convention, all such names should resolve to the mail subcontext (relative to the standard java:comp/env naming context that is the root of all provided resource factories. A typical web.xml entry might look like this:

<resource-ref>
  <description>
    Resource reference to a factory for javax.mail.Session
    instances that may be used for sending electronic mail
    messages, preconfigured to connect to the appropriate
    SMTP server.
  </description>
  <res-ref-name>
    mail/Session
  </res-ref-name>
  <res-type>
    javax.mail.Session
  </res-type>
  <res-auth>
    Container
  </res-auth>
</resource-ref>

WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

2. Code Your Application's Use Of This Resource

A typical use of this resource reference might look like this:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session) envCtx.lookup("mail/Session");

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(request.getParameter("from")));
InternetAddress to[] = new InternetAddress[1];
to[0] = new InternetAddress(request.getParameter("to"));
message.setRecipients(Message.RecipientType.TO, to);
message.setSubject(request.getParameter("subject"));
message.setContent(request.getParameter("content"), "text/plain");
Transport.send(message);

Note that the application uses the same resource reference name that was declared in the web application deployment descriptor. This is matched up against the resource factory that is configured in the <Context> element for the web application as described below.

3. Configure Tomcat's Resource Factory

To configure Tomcat's resource factory, add an elements like this to the <Context> element for this web application.

<Context ...>
  ...
  <Resource name="mail/Session" auth="Container"
            type="javax.mail.Session"
            mail.smtp.host="localhost"/>
  ...
</Context>

Note that the resource name (here, mail/Session) must match the value specified in the web application deployment descriptor. Customize the value of the mail.smtp.host parameter to point at the server that provides SMTP service for your network.

Additional resource attributes and values will be converted to properties and values and passed to javax.mail.Session.getInstance(java.util.Properties) as part of the java.util.Properties collection. In addition to the properties defined in Annex A of the JavaMail specification, individual providers may also support additional properties like password.

4. Install the JavaMail libraries

Download the JavaMail API.

Unpackage the distribution and place mail.jar into $CATALINA_HOME/lib so that it is available to Tomcat during the initialization of the mail Session Resource. Note: placing this jar in both $CATALINA_HOME/lib and a web application's lib folder will cause an error, so ensure you have it in the $CATALINA_HOME/lib location only.

5. Restart Tomcat

For the additional JAR to be visible to Tomcat, it is necessary for the Tomcat instance to be restarted.

Example Application

The /examples application included with Tomcat contains an example of utilizing this resource factory. It is accessed via the "JSP Examples" link. The source code for the servlet that actually sends the mail message is in /WEB-INF/classes/SendMailServlet.java.

WARNING - The default configuration assumes that there is an SMTP server listing on port 25 on localhost. If this is not the case, edit the <Context> element for this web application and modify the parameter value for the mail.smtp.host parameter to be the host name of an SMTP server on your network.

JDBC Data Sources

0. Introduction

Many web applications need to access a database via a JDBC driver, to support the functionality required by that application. The Java EE Platform Specification requires Java EE Application Servers to make available a DataSource implementation (that is, a connection pool for JDBC connections) for this purpose. Tomcat offers exactly the same support, so that database-based applications you develop on Tomcat using this service will run unchanged on any Java EE server.

For information about JDBC, you should consult the following:

NOTE - The default data source support in Tomcat is based on the DBCP connection pool from the Commons project. However, it is possible to use any other connection pool that implements javax.sql.DataSource, by writing your own custom resource factory, as described below.

1. Install Your JDBC Driver

Use of the JDBC Data Sources JNDI Resource Factory requires that you make an appropriate JDBC driver available to both Tomcat internal classes and to your web application. This is most easily accomplished by installing the driver's JAR file(s) into the $CATALINA_HOME/lib directory, which makes the driver available both to the resource factory and to your application.

2. Declare Your Resource Requirements

Next, modify the web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will look up preconfigured data source. By convention, all such names should resolve to the jdbc subcontext (relative to the standard java:comp/env naming context that is the root of all provided resource factories. A typical web.xml entry might look like this:

<resource-ref>
  <description>
    Resource reference to a factory for java.sql.Connection
    instances that may be used for talking to a particular
    database that is configured in the <Context>
    configurartion for the web application.
  </description>
  <res-ref-name>
    jdbc/EmployeeDB
  </res-ref-name>
  <res-type>
    javax.sql.DataSource
  </res-type>
  <res-auth>
    Container
  </res-auth>
</resource-ref>

WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

3. Code Your Application's Use Of This Resource

A typical use of this resource reference might look like this:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource)
  envCtx.lookup("jdbc/EmployeeDB");

Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();

Note that the application uses the same resource reference name that was declared in the web application deployment descriptor. This is matched up against the resource factory that is configured in the <Context> element for the web application as described below.

4. Configure Tomcat's Resource Factory

To configure Tomcat's resource factory, add an element like this to the <Context> element for the web application.

<Context ...>
  ...
  <Resource name="jdbc/EmployeeDB"
            auth="Container"
            type="javax.sql.DataSource"
            username="dbusername"
            password="dbpassword"
            driverClassName="org.hsql.jdbcDriver"
            url="jdbc:HypersonicSQL:database"
            maxActive="8"
            maxIdle="4"/>
  ...
</Context>

Note that the resource name (here, jdbc/EmployeeDB) must match the value specified in the web application deployment descriptor.

This example assumes that you are using the HypersonicSQL database JDBC driver. Customize the driverClassName and driverName parameters to match your actual database's JDBC driver and connection URL.

The configuration properties for Tomcat's standard data source resource factory (org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory) are as follows:

  • driverClassName - Fully qualified Java class name of the JDBC driver to be used.
  • username - Database username to be passed to our JDBC driver.
  • password - Database password to be passed to our JDBC driver.
  • url - Connection URL to be passed to our JDBC driver. (For backwards compatibility, the property driverName is also recognized.)
  • initialSize - The initial number of connections that will be created in the pool during pool initialization. Default: 0
  • maxActive - The maximum number of connections that can be allocated from this pool at the same time. Default: 8
  • minIdle - The minimum number of connections that will sit idle in this pool at the same time. Default: 0
  • maxIdle - The maximum number of connections that can sit idle in this pool at the same time. Default: 8
  • maxWait - The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception. Default: -1 (infinite)

Some additional properties handle connection validation:

  • validationQuery - SQL query that can be used by the pool to validate connections before they are returned to the application. If specified, this query MUST be an SQL SELECT statement that returns at least one row.
  • validationQueryTimeout - Timeout in seconds for the validation query to return. Default: -1 (infinite)
  • testOnBorrow - true or false: whether a connection should be validated using the validation query each time it is borrowed from the pool. Default: true
  • testOnReturn - true or false: whether a connection should be validated using the validation query each time it is returned to the pool. Default: false

The optional evictor thread is responsible for shrinking the pool by removing any conections which are idle for a long time. The evictor does not respect minIdle. Note that you do not need to activate the evictor thread if you only want the pool to shrink according to the configured maxIdle property.

The evictor is disabled by default and can be configured using the following properties:

  • timeBetweenEvictionRunsMillis - The number of milliseconds between consecutive runs of the evictor. Default: -1 (disabled)
  • numTestsPerEvictionRun - The number of connections that will be checked for idleness by the evitor during each run of the evictor. Default: 3
  • minEvictableIdleTimeMillis - The idle time in milliseconds after which a connection can be removed from the pool by the evictor. Default: 30*60*1000 (30 minutes)
  • testWhileIdle - true or false: whether a connection should be validated by the evictor thread using the validation query while sitting idle in the pool. Default: false

Another optional feature is the removal of abandoned connections. A connection is called abandoned if the application does not return it to the pool for a long time. The pool can close such connections automatically and remove them from the pool. This is a workaround for applications leaking connections.

The abandoning feature is disabled by default and can be configured using the following properties:

  • removeAbandoned - true or false: whether to remove abandoned connections from the pool. Default: false
  • removeAbandonedTimeout - The number of seconds after which a borrowed connection is assumed to be abandoned. Default: 300
  • logAbandoned - true or false: whether to log stack traces for application code which abandoned a statement or connection. This adds serious overhead. Default: false

Finally there are various properties that allow further fine tuning of the pool behaviour:

  • defaultAutoCommit - true or false: default auto-commit state of the connections created by this pool. Default: true
  • defaultReadOnly - true or false: default read-only state of the connections created by this pool. Default: false
  • defaultTransactionIsolation - This sets the default transaction isolation level. Can be one of NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE. Default: no default set
  • poolPreparedStatements - true or false: whether to pool PreparedStatements and CallableStatements. Default: false
  • maxOpenPreparedStatements - The maximum number of open statements that can be allocated from the statement pool at the same time. Default: -1 (unlimited)
  • defaultCatalog - The name of the default catalog. Default: not set
  • connectionInitSqls - A list of SQL statements run once after a Connection is created. Separate multiple statements by semicolons (;). Default: no statement
  • connectionProperties - A list of driver specific properties passed to the driver for creating connections. Each property is given as name=value, multiple properties are separated by semicolons (;). Default: no properties
  • accessToUnderlyingConnectionAllowed - true or false: whether accessing the underlying connections is allowed. Default: false

For more details, please refer to the commons-dbcp documentation.

Adding Custom Resource Factories

If none of the standard resource factories meet your needs, you can write your own factory and integrate it into Tomcat, and then configure the use of this factory in the <Context> element for the web application. In the example below, we will create a factory that only knows how to create com.mycompany.MyBean beans from the Generic JavaBean Resources example above.

1. Write A Resource Factory Class

You must write a class that implements the JNDI service provider javax.naming.spi.ObjectFactory inteface. Every time your web application calls lookup() on a context entry that is bound to this factory, the getObjectInstance() method is called, with the following arguments:

  • Object obj - The (possibly null) object containing location or reference information that can be used in creating an object. For Tomcat, this will always be an object of type javax.naming.Reference, which contains the class name of this factory class, as well as the configuration properties (from the <Context> for the web application) to use in creating objects to be returned.
  • Name name - The name to which this factory is bound relative to nameCtx, or null if no name is specified.
  • Context nameCtx - The context relative to which the name parameter is specified, or null if name is relative to the default initial context.
  • Hashtable environment - The (possibly null) environment that is used in creating this object. This is generally ignored in Tomcat object factories.

To create a resource factory that knows how to produce MyBean instances, you might create a class like this:

package com.mycompany;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

public class MyBeanFactory implements ObjectFactory {

  public Object getObjectInstance(Object obj,
      Name name, Context nameCtx, Hashtable environment)
      throws NamingException {

      // Acquire an instance of our specified bean class
      MyBean bean = new MyBean();

      // Customize the bean properties from our attributes
      Reference ref = (Reference) obj;
      Enumeration addrs = ref.getAll();
      while (addrs.hasMoreElements()) {
          RefAddr addr = (RefAddr) addrs.nextElement();
          String name = addr.getType();
          String value = (String) addr.getContent();
          if (name.equals("foo")) {
              bean.setFoo(value);
          } else if (name.equals("bar")) {
              try {
                  bean.setBar(Integer.parseInt(value));
              } catch (NumberFormatException e) {
                  throw new NamingException("Invalid 'bar' value " + value);
              }
          }
      }

      // Return the customized instance
      return (bean);

  }

}

In this example, we are unconditionally creating a new instance of the com.mycompany.MyBean class, and populating its properties based on the parameters included in the <ResourceParams> element that configures this factory (see below). You should note that any parameter named factory should be skipped - that parameter is used to specify the name of the factory class itself (in this case, com.mycompany.MyBeanFactory) rather than a property of the bean being configured.

For more information about ObjectFactory, see the JNDI 1.2 Service Provider Interface (SPI) Specification.

You will need to compile this class against a class path that includes all of the JAR files in the $CATALINA_HOME/lib directory. When you are through, place the factory class (and the corresponding bean class) unpacked under $CATALINA_HOME/lib, or in a JAR file inside $CATALINA_HOME/lib. In this way, the required class files are visible to both Catalina internal resources and your web application.

2. Declare Your Resource Requirements

Next, modify your web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will request new instances of this bean. The simplest approach is to use a <resource-env-ref> element, like this:

<resource-env-ref>
  <description>
    Object factory for MyBean instances.
  </description>
  <resource-env-ref-name>
    bean/MyBeanFactory
  </resource-env-ref-name>
  <resource-env-ref-type>
    com.mycompany.MyBean
  </resource-env-ref-type>
<resource-env-ref>

WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

3. Code Your Application's Use Of This Resource

A typical use of this resource environment reference might look like this:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");

writer.println("foo = " + bean.getFoo() + ", bar = " +
               bean.getBar());

4. Configure Tomcat's Resource Factory

To configure Tomcat's resource factory, add an elements like this to the <Context> element for this web application.

<Context ...>
  ...
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="com.mycompany.MyBeanFactory"
            bar="23"/>
  ...
</Context>

Note that the resource name (here, bean/MyBeanFactory must match the value specified in the web application deployment descriptor. We are also initializing the value of the bar property, which will cause setBar(23) to be called before the new bean is returned. Because we are not initializing the foo property (although we could have), the bean will contain whatever default value is set up by its constructor.

You will also note that, from the application developer's perspective, the declaration of the resource environment reference, and the programming used to request new instances, is identical to the approach used for the Generic JavaBean Resources example. This illustrates one of the advantages of using JNDI resources to encapsulate functionality - you can change the underlying implementation without necessarily having to modify applications using the resources, as long as you maintain compatible APIs.


Copyright © 1999-2013, Apache Software Foundation