Caucho Technology
documentation
examples
changes

overview
quick start
installation
command-line
configuration
admin
amber
clustering
caching
database
deployment
ejb 3.0
embedding
filters
hessian
hmtp
ioc
jsp
logging
messaging
performance
quercus/php
remoting
scheduled tasks
security
server push
servlets
third-party
troubleshooting
virtual hosting
watchdog
webapp
xml and xslt

servlets


Servlets are Java classes which service HTTP requests. The only requirement for writing a servlet is that it implements the javax.servlet.Servlet interface.

Servlets are loaded from the classpath like all Java classes. Normally, users put servlets in WEB-INF/classes so Resin will automatically reload them when they change.

JSP pages are implemented as Servlets, and tend to be more efficient for pages with lots of text.

Configuration

Configuring the web.xml

The following is a complete working web.xml to run this example.

The servlet-mapping tells Resin that the URL /hello should invoke the hello-world servlet.

The servlet tells Resin that hello-world uses the test.HelloWorld class and that the value of the greeting init parameter is Hello World.

WEB-INF/web.xml
<web-app>
  <servlet-mapping url-pattern='/hello'
                   servlet-name='hello-world'/>

  <servlet servlet-name='hello-world'
           servlet-class='test.HelloWorld'>
    <init-param greeting='Hello, World'/>
</web-app>

The Java code, HelloWorld.java belongs in

$app-dir/WEB-INF/classes/test/HelloWorld.java

Or, if you're compiling the servlet yourself, the class file belongs in

$app-dir/WEB-INF/classes/test/HelloWorld.class

Following is the actual servlet code. It just prints a trivial HTML page filled with the greeting specified in the web.xml.

init() and destroy() are included mostly for illustration. Resin will call init() when it starts the servlet and destroy before Resin destroys it.

package test;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {
  private String greeting;

  public void init()
    throws ServletException
  {
    greeting = getInitParameter("greeting");
  }

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
    throws ServletException, IOException
  {
    PrintWriter out = response.getWriter();

    out.println("<title>" + greeting + "</title>");
    out.println("<h1>" + greeting + "</h1>");
  }
  
  public void destroy()
  {
    // nothing to do
  }
}

Servlet Example for JSP Programmers

Because Resin compiles JSP pages into servlets, programmers familiar with JSP can start writing servlets fairly easily. The following template can be used to see how to write a servlet for someone familiar with JSP.

package test;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {
  public void service(HttpServletRequest request,
                      HttpServletResponse response)
    throws ServletException, IOException
  {
    PrintWriter out = response.getWriter();
    ServletContext application = getServletContext();
    HttpSession session = request.getSession();

    try {
      // code goes here

      // The equivalent of jsp:include:
      // request.getRequestDispatcher("/inc.jsp").include(request, response);
    } catch (ServletException e) {
      throw e;
    } catch (Exception e) {
      throw new ServletException(e);
    }
  }
}

Using Databases from a Servlet

The following is a sample design pattern for getting new database connections. The try ... finally block is very important. Without the close in the finally block, Resin's database pool can loose connections.

Configuring the database is described in the database configuration page.

TestDatabase.java
package test;

import java.io.*;

import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.naming.*;
import javax.sql.*;

public class TestDatabase extends HttpServlet {
  DataSource pool;

  public void init()
    throws ServletException
  {
    try {
      Context env = (Context) new InitialContext().lookup("java:comp/env");

      pool = (DataSource) env.lookup("jdbc/test");

      if (pool == null)
        throw new ServletException("`jdbc/test' is an unknown DataSource");
    } catch (NamingException e) {
      throw new ServletException(e);
    }
  }

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
    throws IOException, ServletException
  {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();

    Connection conn = null;
    try {
      conn = pool.getConnection();

      // code for the servlet using the database goes here

      rs.close();
      stmt.close();
    } catch (SQLException e) {
      throw new ServletException(e);
    } finally {
      try {
        if (conn != null)
          conn.close();
      } catch (SQLException e) {
      }
    }
  }
}

Servlet Configuration

init

Configures servlets using bean-style initialization. Each entry in an <init> tag will configure a setFoo method in a Servlet. JSP EL expressions are allowed.

The init(config) method is called after all the bean setters are called.

Bean-style Configuration
<servlet servlet-name='test.HelloWorld'>
  <init>
    <greeting>Hello, ${host.url}</greeting>
  </init>
</servlet>
HelloWorld bean
public HelloWorld extends GenericServlet {
  private String _greeting;

  public void setGreeting(String greeting)
  {
    _greeting = greetin;
  }

  public void service(ServletRequest req,
                      ServletResponse res)
    throws IOException, ServletException
  {
    PrintWriter out = res.getWriter();

    out.println("Greeting: " + _greeting);
  }
}

init-param

Initializes servlet variables. servlet-param defines initial values for getServletConfig().getInitParameter("foo").

The full servlet 2.2 syntax is supported and allows a simple shortcut.

<web-app id='/'>

<servlet servlet-name='test.HelloWorld'>
  <init-param foo='bar'/>

  <init-param>
    <param-name>baz</param-name>
    <param-value>value</param-value>
  </init-param>
</servlet>

</web-app>

load-on-startup

If present, starts the servlet when the server starts.

<web-app id='/'>

<servlet servlet-name='hello'
         servlet-class='test.HelloWorld'>
  <load-on-startup/>
</servlet>

</web-app>

run-at

If present, calls the servlet's service() method at the specified times. <run-at> lets servlet writers execute periodic tasks without worrying about creating a new Thread.

The value is a list of 24-hour times when the servlet should be automatically executed. To run the servlet every 6 hours, you could use:

<servlet servlet-name='test.HelloWorld'>
  <run-at>0:00, 6:00, 12:00, 18:00</run-at>
</servlet>

If the hour is omitted, the servlet runs every hour at the specified minute. To run the server every 15 minutes, you could use:

<servlet servlet-name='test.HelloWorld'>
  <run-at>:00, :15, :30, :45</run-at>
</servlet>

servlet

Defines a servlet alias for later mapping.

ATTRIBUTEDESCRIPTION
servlet-nameThe servlet's name (alias)
servlet-classThe servlet's class (defaults to servlet-name)
init-paramInitialization parameters
load-on-startupInitializes the servlet when the server starts.
run-atTimes to execute the servlet automatically

The following example defines a servlet alias 'hello'

<web-app id='/'>

<servlet-mapping url-pattern='/hello.html'
                 servlet-name='hello'/>

<servlet servlet-name='hello'
         servlet-class='test.HelloWorld'>
  <init-param title='Hello, World'/>
</servlet>

<servlet servlet-name='cron'
         servlet-class='test.DailyChores'>
  <run-at>3:00</run-at>
</servlet>

</web-app>

servlet-class

Class of the servlet. The CLASSPATH for servlets includes the WEB-INF/classes directory and all jars in the WEB-INF/lib directory.

servlet-name

Alias of the servlet, uniquely naming a servlet configuration. Several <servlet> configurations might configure the same servlet class with different <init-param> values. Each will have a separate servlet-name.

Multiple Servlets
<web-app>
  <servlet servlet-name='foo-a'>
    <servlet-class>test.FooServlet</servlet-class>
    <init-param name='foo-a sample'/>
  </servlet>

  <servlet servlet-name='foo-b'>
    <servlet-class>test.FooServlet</servlet-class>
    <init-param name='foo-b sample'/>
  </servlet>
</web-app>

servlet-mapping

Maps from a URL to the servlet to execute. The servlet-mapping has a url-pattern to match the URL and a servlet-name to match the configured servlet.

typical servlet-mapping
<servlet>
  <servlet-name>hello</servlet-name>
  <servlet-class>test.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
  <url-pattern>/hello/*</url-pattern>
  <servlet-name>hello</servlet-name>
</servlet-mapping>

Resin allows for a shortcut combining the servlet and the servlet mapping:

shortcut servlet-mapping
<servlet-mapping url-pattern="/hello/*"
                 servlet-class="test.HelloServlet"/>

url-pattern

Matches a set of URLs for servlet-mapping.

PATTERNDESCRIPTION
/foo/bar.htmlMatches exactly the /foo/bar.html URL.
/foo/*Matches /foo and any children
*.fooMatches any URL with a .foo extension
/Replaces the default servlet.

/ defines a default handler and /* defines a prefix handler. /* will override extension handlers like *.foo. / will only be used if no other pattern matches.

No default. Either url-pattern or url-regexp is required.

ErrorStatusServlet

Sends an HTTP error code and optionally an error message back to the client.

status-codethe HTTP status code to send404
messagethe message to sendno message

This servlet is particularily useful for blocking access to portions of your web-app that contain files not meant to be accessible to users. In this example, the default 404 (meaning "Not Found") is used as the error message; the user cannot even determine if the file they are trying to access exists.

Blocking access to files using the ErrorStatusServlet
<web-app>
  <servlet>
    <servlet-name>block-access</servlet-name>
    <servlet-class>com.caucho.servlets.ErrorStatusServlet</servlet-class>
  <servlet>

  <servlet-mapping>
    <servlet-name>block-access</servlet-name>
    <url-pattern>/config/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>block-access</servlet-name>
    <url-pattern>*.properties</url-pattern>
  </servlet-mapping>

  ...

</web-app>

See com.caucho.servlets.ErrorStatusServlet.

LoadBalanceServlet

Configures a front-end Resin instance to load-balance requests to backend Resin instances. Each LoadBalanceServlet instance will distribute the requests to a configured cluster.

The urls that get load balanced are the ones that are mapped to the LoadBalancedServlet, using the usual servlet-mapping.

LoadBalanceServlet supports sticky-sessions. If the request already has a session, the backend server matching that session will be used. Otherwise, the least busy backend server will be used as counted by number of active requests. If several backend servers are equally busy, the selection uses a round-robin to distribute the load.

cluster-idthe cluster that gets the matching requestsrequired
sticky-sessionswhether or not sessions should be stickytrue
strategythe load balancing strategy, `round-robin' or `least-connection'least-connection

The usual case balances all requests to backend servers. The front-end Resin instance has a resin.conf similar to the one shown here. It configures the front-end instance to balance the load to the backend servers. The backend Resin instances have a resin.conf file that configures the web site, similar to a conf file that is used when only one instance of Resin used for the server.

frontend.conf
<resin xmlns="http://caucho.com/ns/resin">
  <server>

    <http id='frontend' port='8080'/>

    <cluster id='backend'>
      <srun id='a' host='192.168.0.11' port='6810'/>
      <srun id='b' host='192.168.0.12' port='6810'/>
    </cluster>

    <!-- the front-end does the access logging -->
    <access-log path='log/access.log'>
      <rollover-period>2W</rollover-period>
    </access-log>

    <!-- all urls are load balanced to the backend -->
    <host id=''>
      <web-app id='/'>
        <servlet>
          <servlet-name>backend</servlet-name>
          <servlet-class>com.caucho.servlets.LoadBalanceServlet</servlet-class>
          <init>
            <cluster>backend</cluster>
          </init>
        </servlet>

        <servlet-mapping url-pattern='/*' servlet-name='backend'/>
      </web-app>
   </host>
  </server>
</resin>

LoadBalanceServlet is also used to allow a separate JVM for a web-app or a host.

The strategy determines the strategy to use for choosing a backend server for a request that does not have a sticky-session. The `least-connection' strategy chooses the backend server that has the least number of connections at the time the decision is made. This is a good general purpose strategy, and compensates for differences in a backend server's ability to service connections. The `round-robin' strategy does a straight round robin, choosing the backend server that follows the last backend server chosen.

See com.caucho.servlets.LoadBalanceServlet.

CGIServlet

Implements CGI calls. The url is assumed to refer to an executable file, and the operating system is instructed to execute the program or script. The usual CGI environment variables are set, and the current directory is the value of $RESIN_HOME

executablePath to the script programdefault exec
ignore-exit-codeIf true, do not treat a non-zero exit code as an errorfalse
stderr-is-exceptionIf false, ignore output on stderr instead of triggering an exceptiontrue
WEB-INF/resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin">
  <servlet>
    <servlet-name>cgi</servlet-name>
    <servlet-class>com.caucho.servlets.CGIServlet</servlet-class>
  </servlet>

  <servlet-mapping servlet-name="cgi" url-pattern="/cgi-bin/*.exe"/>
</web-app>

The servlet-mapping specifies the requests that will be treated as CGI exectutables. In the example above, only files in the /cgi-bin directory with an extension of ".exe" will be executed. It is important to limit the url-pattern as much as possible to avoid allowing unintended execution of scripts or binaries on the system.

A CGI script must output a blank line between the HTTP header(s) and the rest of the response. If no blank line is encountered, the contents of your browser page will be blank. Usually a CGI script will output a Content-Type: header and then a blank line before the content:

Minimal CGI script
#!/bin/sh

echo "Content-Type: text/html"
echo
echo "<h>CGI Test<h1>"
echo "CGI Test"

echo "<pre>"
env
echo "</pre>"

DirectoryServlet

The directory servlet provides the basic directory browsing. The servlet-name must be "directory" for the servlet to take effect. Sites will normally disable it.

enableEnable or disable the servlettrue
<servlet servlet-name="directory"
         servlet-class="com.caucho.servlets.DirectoryServlet">
  <init enable="false"/>
</servlet>

FastCGIServlet

Implements the FastCGI protocol. FastCGI allows some CGI clients like PHP to run quicker and more efficiently.

server-addressthe host and port number, in the form host:portrequired

The FastCGIServlet creates a socket connection from Resin to the backend program that supports the fastcgi protocol. servlet-mapping is used to configure the filename patterns of scripts that are handled by the backend program.

The following example configures Resin so that any files within a single webapp matching the pattern"*.php" are handled by the backend program:

WEB-INF/web.xml
<web-app>
  <servlet>
    <servlet-name>php-fastcgi</servlet-name>
    <servlet-class>com.caucho.servlets.FastCGIServlet</servlet-class>
    <init>
      <server-address>localhost:6666</server-address>
    </init>
  </servlet>
  <servlet-mapping>
    <servlet-name>php-fastcgi</servlet-name>
    <url-pattern>*.php</url-pattern>
  </servlet-mapping>
</web-app>

Assuming PHP has been compiled with -fastcgi enabled, you might start PHP like:

unix> php -b 6666 

Mapping is enabled for all web-apps with the use of web-app-default. In this example, filenames with the pattern "*.php" and the pattern "*.phtml" are handled by the backend program:

resin.conf
<web-app-default>
  <servlet>
    <servlet-name>php-fastcgi</servlet-name>
    <servlet-class>com.caucho.servlets.FastCGIServlet</servlet-class>
    <init>
      <server-address>localhost:6666</server-address>
    </init>
  </servlet>

  <servlet-mapping url-pattern="*.php"   servlet-name="php-fastcgi"/>
  <servlet-mapping url-pattern="*.phtml" servlet-name="php-fastcgi"/>

</web-app>

See com.caucho.servlets.FastCGIServlet.

HttpProxyServlet

com.caucho.servlets.HttpProxyServlet is a servlet that proxies to another server. This can be useful for providing access to legacy backend servers.

HttpProxyServlet
  <servlet>
    <servlet-name>http-proxy</servlet-name>
    <servlet-class>com.caucho.servlets.HttpProxyServlet</servlet-class>
    <init host='localhost:8081'/>
  </servlet>

  <servlet-mapping url-pattern="/foo/*" servlet-name="http-proxy"/>
  <servlet-mapping url-pattern="/bar/*" servlet-name="http-proxy"/>

There is a bit more power using servlet-regexp and regular expressions:

HttpProxyServlet with regexp
<servlet-regexp url-regexp="^/foo(/.*)?"
                servlet-class="com.caucho.servlets.HttpProxyServlet">
  <init host='localhost:8081'/>
</servlet-regexp>

SSIServlet

com.caucho.servlets.ssi.SSIServlet is a servlet that processes server side include directives. The syntax for server side includes is the same as the syntax used in Apache httpd.

resin-web.xml SSIServlet
<web-app xmlns="http://caucho.com/ns/resin">
  <servlet-mapping url-pattern="*.shtml"
                   servlet-class="com.caucho.servlets.ssi.SSIServlet"/>
</web-app>
test.shtml
<h1>A little test</h1>

<!--#config timefmt="%Y-%m-%d" -->
<!--#echo var="DATE_GMT" -->

<!--#include virtual="inc.jsp" -->

<!--#set var="a" value="$REQUEST_METHOD" -->
<!--#include virtual="inc.jsp?q=$a" -->

WebDAVServlet

WebDAV, web-based distributed authoring and versioning, is a set of extensions to the HTTP protocol that is a convenient replacement for FTP when developing web sites. Many editing tools can save to a WebDAV server directly and several operating systems can provide a filesystem to a WebDAV server.

From www.webdav.org:

What is WebDAV?
Briefly: WebDAV stands for "Web-based Distributed Authoring and Versioning". It is a set of extensions to the HTTP protocol which allows users to collaboratively edit and manage files on remote web servers.

The WebDAV site also contains pointers to programs which understand WebDAV.

The WebDAV servlet must be enabled explicitly. By default, it also requires a logged in user playing the 'webdav' role and requires a secure (SSL) connection. These can be relaxed, but having the defaults require security makes it unlikely that a webmaster will enable WebDAV by mistake.

enableEnable webdav servlet for read ("read") or read/write ("write")false (disabled)
roleThe role required for webdav, '*' means no role requiredwebdav
userA specific user required for webdavnone
secureIf true, only allow updates over a secure connection (SSL)true
rootConfigures the root directory for webdavThe application root
path-sourceThe jndi name of a custom path backing previously defined as a resource. This allows a custom path backing, e.g. a database sourcean instance of com.caucho.servlets.webdav.ApplicationPath

The following example is a typical WebDAV configuration. The explicit servlet-mapping and setting enable to 'write' is necessary. Since secure is left as the default, it will require an SSL connection.

Enabling WebDAV
<servlet>
  <servlet-name>webdav</servlet-name>
  <servlet-class>com.caucho.servlets.webdav.WebDavServlet</servlet-class>
  <init>
    <enable>write</enable>
  </init>
</servlet>

<servlet-mapping url-pattern='/webdav/*' servlet-name='webdav'/>

<authenticator>
  <type>com.caucho.server.security.XmlAuthenticator</type>
  <init>
    <user>Harry Potter:quidditch:webdav</user>
    <password-digest>none</password-digest>
  </init>
</authenticator>

<login-config>
  <auth-method>basic</auth-method>
</login-config>

<security-constraint url-pattern='/webdav/*' role-name='webdav'/>

The following example is not recommended because it would allow anyone to update the site:

WebDAV with no security
<servlet>
  <servlet-name>webdav</servlet-name>
  <servlet-class>com.caucho.servlets.webdav.WebDavServlet</servlet-class>
  <init>
    <enable>write</enable>
    <secure>false</secure>
    <role>*</role>
  </init>
</servlet>

<servlet-mapping url-pattern='/webdav/*' servlet-name='webdav'/>

The WebDAV servlet can point to a different directory by setting the root parameter. The path is relative to the web-app, and allows path variables. For example, the following would read and write files from WEB-INF/webdav:

WebDAV based on WEB-INF/webdav
<servlet>
  <servlet-name>webdav</servlet-name>
  <servlet-class>com.caucho.servlets.webdav.WebDavServlet</servlet-class>
  <init>
    <root>WEB-INF/webdav</root>
    <enable>write</enable>
    <role>webdav</role>
  </init>
</servlet>

<servlet-mapping url-pattern='/webdav/*' servlet-name='webdav'/>

Configuring Windows

Recent versions of Windows and the Windows Office suite directly support WebDAV. WebDAV is configured in "My Network Places".

When browsing "My Network Places" in IE, click on Tools/Map Network Drive from the menu. IE will open a dialog. The dialog contains a link to "Create a shortcut to Web folder or FTP site". Clicking on that will open the "Add Network Place Wizard".

The Add Network Place Wizard will ask for the location of the WebDAV server. Type the full URL, e.g. http://www.foo.com/webdav and complete the dialog.

Adding the WebDAV link will let you save directly to your server. Windows programs can load and save to the server. You can also open an IE window to the mapped folder and use it as a normal folder.

Custom Path Sources

The WebDAV servlet can be customized to use a source other than the default path source. For example, it would be possible to use WebDAV with files stored in a database.

There's a <path-source>java:comp/env/my-path</path-source> parameter in the WebDavServlet(see Configuring the WebDAV Servlet). You configure an object with the JNDI name java:comp/env/my-path using resource to configure a custom class that extends com.caucho.servlets.webdav.AbstractPath

WebDAV with a custom source
<resource jndi-name='resin/webdav'>
  <type>test.foo.MyDataSource</type>
  <init>
    <my-foo>bar</my-foo>
  </init>
</resource>

<servlet>
  <servlet-name>webdav</servlet-name>
  <servlet-class>com.caucho.servlets.webdav.WebDavServlet</servlet-class>
  <init>
    <enable>write</enable>
    <path-source>resin/webdav</path-source>
  </init>
</servlet>

<servlet-mapping url-pattern='/webdav/*' servlet-name='webdav'/>

You can completely customize your WebDav backend, linking it to databases or some EJB-based data source or whatever.

Configuring the WebDAV servlet to recognize more than one root folder?

There's a "root" parameter for the WebDavServlet (see Configuring the WebDAV Servlet). You can set that and use several separate webdav instances.

<servlet>
  <servlet-name>webdav1</servlet-name>
  <servlet-class>com.caucho.servlets.webdav.WebDavServlet</servlet-class>
  <init>
    <root>/opt/root1</root>
  </init>
</servlet>

<servlet>
  <servlet-name>webdav2</servlet-name>
  <servlet-class>com.caucho.servlets.webdav.WebDavServlet</servlet-class>
  <init>
    <root>/opt/root1</root>
  </init>
</servlet>

<servlet-mapping url-pattern='/root1' servlet-name='webdav1'/>
<servlet-mapping url-pattern='/root2' servlet-name='webdav2'/>

Making the root path match a user name?

What if one wants to make the root user-dependant? i.e. have user "ferg" have the root in "/somefolder/ferg" and user "jeff" have the root in "/somefolder/jeff"

It's possible, but you need to write a bit of code.

As discussed in Custom Path Sources, you can customize the data source by creating your own ApplicationPath.

In this case, you probably want to extend com.caucho.servlets.webdav.FilePath and override the getPath method.

run-at

Some web applications need a task to be run at regular intervals, e.g. once an hour or once a day. For example, a search application might want to spider the web site every day to automatically pick up any new pages. Syndication applications might poll their news sites every hour to check for updates.

Resin's run-at servlets make periodic tasks simple. At the specified interval, Resin will execute a configured servlet. Because the periodic task is implemented as a servlet, the API is familiar and debugging is simple.

run-at has several advantages over spawning a new thread. First, when you spawn a thread, you need to make sure you close it properly when the servlet is unloaded. Servlets can be unloaded at any time. Also, run-at automatically handles classloader issues. A thread implementation needs to ensure that the running thread has the same classloader as the application.

Sample Service

The following example doesn't do much. When the service routine is called, is just prints a message to the standard output.

Because there is no request, the request and response objects are just stubs. There's no reason to ever use them in a run-at service. (Yes, that makes the arguments a little silly, but it's better than creating a new API.)

The service does have access to the ServletConfig and ServletContext objects.

TestAlarm.java
package test;

import javax.servlet.*;

public class TestAlarm extends GenericServlet {
  public void service(ServletRequest request,
                      ServletResponse response)
    throws IOException, ServletException
  {
    System.out.println("alarming");
  }
}

The alarm is configured as any other servlet, with the addition of the run-at tag. The following configuration runs the servlet every 15 minutes. If the hour is missing, e.g. :15 the service is run at the specified minute.

15 minute configuration
...
<servlet name='alarm' servlet-class='test.TestAlarm'>
  <run-at>:00, :15, :30, :45</run-at>
</servlet>
...

You can also run an alarm every hour. Just specify the full hour:minute in the run-at. For example, 16:30 runs the service once a day at 4:30 PM.

Daily at 4:30 PM Configuration
...
<servlet name='alarm' servlet-class='test.TestAlarm'>
  <run-at>16:30</run-at>
</servlet>
...

Copyright © 1998-2008 Caucho Technology, Inc. All rights reserved.
Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.