Pluggable mail sessions in Seam apps using JBoss7 mail module

If you are writing a web application using the Seam framework and that application is required to send mails, you usually need to configure your seam application to use a mail session. In seam, you specify mail sessions for your app in the components.xml file which is usually found in the WEB-INF/ folder of the application.


<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
            xmlns:core="http://jboss.com/products/seam/core"
            xmlns:mail="http://jboss.com/products/seam/mail"
            xsi:schemaLocation=
                "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd
                 http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.2.xsd
                 http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd">

        .....

	<mail:mail-session />
        
        ......

</components>

The seam mail session tag in components.xml has several properties which have to be specified if you do not intend to use the default mail session. One of these properties is “session-jndi-name” which is used to reference a mail session using its JNDI name.

In JBoss7 it is very easy to specify multiple mail sessions and then instruct your seam app to use one of those sessions for sending mail. This means that your web application delegates it’s mail functionality to the server container and we have one less thing to worry about.

The point for configuration of the mail session in JBoss7 is the configuration file which is found in {JBOSS_HOME}/standalone/configuration/{mode}.xml where {mode} corresponds to the JBoss7 startup mode for which you intend to deploy your application. That is, either standalone or standalone-ha (standalone clustered mode).

Open the file you wish to use and find the mail subsystem.

In the default jboss7 distribution, the mail subsystem looks something like the following:



<subsystem xmlns="urn:jboss:domain:mail:1.0">
     <mail-session jndi-name="java:jboss/mail/Default">
         <smtp-server outbound-socket-binding-ref="mail-smtp"/>
     </mail-session>
</subsystem>

This is the default mail session, with a JNDI name of java:jboss/mail/Default. This session connects to an SMTP server and the outbound-socket-binding reference is called mail-smtp. This reference is defined within the socket-binding-group element which is also within the configuration file.


<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <socket-binding name="management-native" interface="management" port="${jboss.management.native.port:9999}"/>
        <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
        <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9443}"/>
        <socket-binding name="ajp" port="8009"/>
        <socket-binding name="http" port="8080"/>
        <socket-binding name="https" port="8443"/>
        <socket-binding name="jgroups-diagnostics" port="0" multicast-address="224.0.75.75" multicast-port="7500"/>
        <socket-binding name="jgroups-mping" port="0" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
        <socket-binding name="jgroups-tcp" port="7600"/>
        <socket-binding name="jgroups-tcp-fd" port="57600"/>
        <socket-binding name="jgroups-udp" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
        <socket-binding name="jgroups-udp-fd" port="54200"/>
        <socket-binding name="modcluster" port="0" multicast-address="224.0.1.105" multicast-port="23364"/>
        <socket-binding name="osgi-http" interface="management" port="8090"/>
        <socket-binding name="remoting" port="4447"/>
        <socket-binding name="txn-recovery-environment" port="4712"/>
        <socket-binding name="txn-status-manager" port="4713"/>
        <outbound-socket-binding name="mail-smtp">
            <remote-destination host="localhost" port="25"/>
        </outbound-socket-binding>
</socket-binding-group>

The mail-smtp socket binding is defined to connect to an smtp server on localhost and port 25. Now unless you have an smtp server on your local development machine, you will most definitely want to change this.

So how exactly do we create new mail sessions and their corresponding socket bindings in the configuration?

In my configuration, I will be creating a mail session with a socket binding to the gmail email service and then my seam app will use this session for all its email sending.

Just add a new mail-session element to the mail subsystem config (right under the default mail session) as shown below:


<mail-session jndi-name="java:jboss/mail/google/myapp" from="do-not-reply@myapp.com">
         <smtp-server ssl="true" outbound-socket-binding-ref="mail-smtp">
             <login name="gmail-account-username" password="gmail-account-password"/>
         </smtp-server>
</mail-session>

The snippet above means that we would like to create a new mail-session with jndi name, java:jboss/mail/google/myapp. This session will be connecting to an SMTP server using ssl and the socket binding to use is called mail-smtp. The login credentials for using the smtp server are specified in the login child element of the smtp-server declaration.

Now we need to configure the socket binding to point to the gmail servers:


<outbound-socket-binding name="mail-smtp">
     <remote-destination host="smtp.gmail.com" port="465"/>
</outbound-socket-binding>

The snippet above means that the socket binding called mail-smtp connects to the gmail smtp server, smtp.gmail.com on port 465 (which is the SSL port for the gmail smtp service).

And thats all!!

Now you can simply just reference the jndi name of the configured gmail mail-session in your seam components.xml as shown below:


<components xmlns="http://jboss.com/products/seam/components"
            xmlns:core="http://jboss.com/products/seam/core"
            xmlns:mail="http://jboss.com/products/seam/mail"
            xsi:schemaLocation=
                "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd
                 http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.2.xsd
                 http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd">

        .....

	<mail:mail-session session-jndi-name="java:jboss/mail/google/myapp" />
        
        ......

</components>

Now your seam app sends mail using a configured gmail mail session which is managed by your JBoss7 runtime. You can create as many mail-sessions as you want and also as many socket bindings as you want without having to change your components.xml. Happy mailing!

Running JBoss7 in service mode using Java Service Wrapper

Introduction

Have you ever needed to run your JBoss application server unattended on a Windows machine? There are various ways to accomplish this task. By far, the best alternative is to run the JBoss instance as a Windows service. One of the easiest tools I’ve found for running  java-based applications as services is the Java Service Wrapper project from Tanukisoftware.org. According to their website, the Java Service Wrapper is an application which has evolved out of a desire to solve a number of problems common to many Java applications:

  • Run as a Windows Service or Unix Daemon
  • Application Reliability
  • Standard, Out of the Box Scripting
  • On Demand Restarts
  • Flexible Configuration
  • Ease Application Installations
  • Logging

Because it is Java-based and written completely in Java, the Java service wrapper is the perfect candidate for service/daemon enablement of the JBoss server runtime.

Getting Ready

This post specifically deals with the process of confguring JBoss 7 application server as a windows service. You will need to download the following pieces of software before proceeding:

  • JBoss Application Server 7 (download here ) or if you are on the bleeding edge, download the nightly development build from here
  • Java Platform 32-bit standard edition 6+  ( download here )
  • Tanuki Java Service Wrapper 32-bit community edition 3.5.6+ ( download here )
We need the community edition of the java service wrapper (JSW) because the standard and professional editions require purchase of a license. Furthermore, the 64-bit JSW is not available in the community edition. In addition, the 32-bit JSW native library only works with a 32-bit Java Virtual Machine (JVM). So this is why the requirements above are as they are.

Folder Structure

First, you need to create a parent folder which will contain jboss7, the jre and a folder containing the wrapper service files, as depicted in the diagram below:

Folder structure within the Jboss7jvm32 folder

As you can see, in there, I’ve got 2 different jboss7 distributions, versions 6 and 7 of the jre in case I would like to switch between either of them and a folder called service. With this structure, things are kept clean and separated. If we choose to upgrade the java service wrapper version, we only need to update files in the service folder. If a new version of jboss gets released, we just edit the service configuration to point to the new distribution.

Service Configuration

Now its time to integrate the java service wrapper into our setup. There are four directories that need to be present inside the service folder:

  • bin
  • lib
  • conf
  • logs

Let us call this service folder {SERVICE_HOME}

Unzip the Java service wrapper distribution you downloaded earlier somewhere on your computer. Let us call the directory containing the unzipped distribution {WRAPPER_HOME}.

Copy the following files into service’s bin folder.

1 {WRAPPER_HOME}\bin\wrapper.exe
2 {WRAPPER_HOME}\src\bin\App.bat.in
3 {WRAPPER_HOME}\src\bin\InstallApp-NT.bat.in
4 {WRAPPER_HOME}\src\bin\UninstallApp-NT.bat.in

Rename the three batch files, substituting App with your applications name, for example. Be sure to remove the .in extensions so that the files all end in .bat.
(Depending on how your file explorer is configured on your computer, you may not be able to see file extensions.)
You should now have:

1 {SERVICE_HOME}\bin\wrapper.exe
2 {SERVICE_HOME}\bin\JBoss7_standalone_ha_start.bat
3 {SERVICE_HOME}\bin\JBoss7_standalone_ha_install-NT.bat
4 {SERVICE_HOME}\bin\JBoss7_standalone_ha_remove-NT.bat

The wrapper.exe is the actual wrapper executable. JBoss7_standalone_ha_start.bat is used to run jboss7 in the console, and it’s Install and Uninstall counterparts are used to install and uninstall the windows service for jboss7  respectively. Notice that these three bat files are named to reflect the mode we choose to run jboss in. To remind ourserlves, the default jboss7 distribution can be run in 4 different modes.

  • standalone
  • standalone-ha (standalone mode with clustering)
  • domain
  • domain-ha (domain mode with clustering)

Create a new set of the 3 bat files for each mode you choose to support. One to start jboss7, one to install jboss7 as a service and another to stop the service in the respective mode as listed above.

Then copy the following files into service’s lib folder.

1 {WRAPPER_HOME}\lib\wrapper.jar
2 {WRAPPER_HOME}\lib\wrapper.dll

The wrapper.dll file is a native library file required by the portion of the Wrapper which runs within the JVM. The wrapper.jar file contains all of the Wrapper classes.
You should now have.

1 {SERVICE_HOME}\lib\wrapper.jar
2 {SERVICE_HOME}\lib\wrapper.dll

Now copy the following template for a wrapper.conf file into service’s conf folder

1 {WRAPPER_HOME}\src\conf\wrapper.conf.in

now you should have

1 {SERVICE_HOME}\conf\wrapper_standalone_ha.conf

The wrapper_standalone_ha.conf naming easily helps us identify that this configuration file will be used to enable jboss7 as a service in standalone clustering mode. Create corresponding wrapper.conf files for the various jboss7 startup modes that you wish to support e.g. wrapper_domain_ha.conf. Since we are creating various conf files to correspond with the jboss7 startup modes we wish to support, we also need to edit the corresponding bat files created above, to point to the respective wrapper conf file.

Open the corresponding bat files and edit the set_WRAPPER_CONF_DEFAULT default property to point to the required wrapper config file. So for JBoss7_standalone_ha_start.bat, JBoss7_standalone_ha_install-NT.bat and JBoss7_standalone_ha_remove-NT.bat I have changed that property to:

set _WRAPPER_CONF_DEFAULT=../conf/wrapper_standalone_ha.conf

Create a logs directory inside the service directory so you now have

1 {SERVICE_HOME}\logs

Now it is time to modify your wrapper.conf to tell the java service wrapper how it is supposed to run jboss7  as a service.  I have mine below (wrapper_standalone_ha.conf). Notice how the JAVA_HOME, JBOSS_HOME AND SERVICE_HOME variables are set to the locations of the desired java, jboss and service folders, allowing easy switching or upgrading of the corresponding component binaries. We only need to edit the wrapper configuration file and set a new JAVA_HOME if we choose to change the JVM, set a new JBOSS_HOME if we wish to upgrade our server to a new version and set a new SERVICE_HOME if we choose to upgrade the java service wrapper version or even just if we decide to change the name of the service folder (default is called service) or its location.

Putting it all together

encoding=UTF-8
# Configuration files must begin with a line specifying the encoding
# of the the file.

#********************************************************************
# Wrapper License Properties (Ignored by Community Edition)
#********************************************************************
# Professional and Standard Editions of the Wrapper require a valid
# License Key to start. Licenses can be purchased or a trial license
# requested on the following pages:
# http://wrapper.tanukisoftware.com/purchase
# http://wrapper.tanukisoftware.com/trial

# Include file problems can be debugged by removing the first '#'
# from the following line:
##include.debug

# The Wrapper will look for either of the following optional files for a
# valid License Key. License Key properties can optionally be included
# directly in this configuration file.
#include ../conf/wrapper-license.conf
#include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf

# The following property will output information about which License Key(s)
# are being found, and can aid in resolving any licensing problems.
#wrapper.license.debug=TRUE

#********************************************************************
# Wrapper Localization
#********************************************************************
# Specify the locale which the Wrapper should use. By default the system
# locale is used.
#wrapper.lang=en_US # en_US or ja_JP

# Specify the location of the Wrapper's language resources. If these are
# missing, the Wrapper will default to the en_US locale.
wrapper.lang.folder=../lang

#********************************************************************
# Wrapper Java Properties
#********************************************************************
# Java Application
# Locate the java binary on the system PATH:
wrapper.java.command=java
# Specify a specific java binary:
set.JBOSS_HOME=..\..\jboss-as-7.2.0.Alpha1-SNAPSHOT
set.JAVA_HOME=..\..\jre7
set.SERVICE_HOME=..\..\service
wrapper.java.command=%JAVA_HOME%\bin\java

# Tell the Wrapper to log the full generated Java command line.
wrapper.java.command.loglevel=ERROR

# Java Main class. This class must implement the WrapperListener interface
# or guarantee that the WrapperManager class is initialized. Helper
# classes are provided to do this for you. See the Integration section
# of the documentation for details.
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperJarApp

# Java Classpath (include wrapper.jar) Add class path elements as
# needed starting from 1
wrapper.java.classpath.1=%SERVICE_HOME%\lib\wrapper.jar
wrapper.java.classpath.2=%JBOSS_HOME%\jboss-modules.jar

# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=%SERVICE_HOME%\lib

# Java Bits. On applicable platforms, tells the JVM to run in 32 or 64-bit mode.
wrapper.java.additional.auto_bits=TRUE

# Java Additional Parameters
wrapper.java.additional.1=-XX:+TieredCompilation
wrapper.java.additional.2=-XX:MaxPermSize=512m
wrapper.java.additional.3=-Dprogram.name=standalone.bat
wrapper.java.additional.4=-Dorg.jboss.resolver.warning=true
wrapper.java.additional.5=-Dsun.rmi.dgc.client.gcInterval=3600000
wrapper.java.additional.6=-Dsun.rmi.dgc.server.gcInterval=3600000
wrapper.java.additional.7=-Djboss.modules.system.pkgs=org.jboss.byteman
wrapper.java.additional.8=-Djava.net.preferIPv4Stack=true
wrapper.java.additional.9=-Dorg.tanukisoftware.wrapper.WrapperManager.mbean=false
wrapper.java.additional.10=-Djboss.server.default.config=standalone-ha.xml
wrapper.java.additional.11=-Dlogging.configuration=file:%JBOSS_HOME%/standalone/configuration/logging.properties
wrapper.java.additional.12=-Dorg.jboss.boot.log.file=%JBOSS_HOME%/standalone/log/boot.log
wrapper.java.additional.13=-Djava.util.logging.manager=org.jboss.logmanager.LogManager
wrapper.java.additional.14=-Dorg.jboss.logging.Logger.pluginClass=org.jboss.logging.logmanager.LoggerPluginImpl

# Initial Java Heap Size (in MB)
#wrapper.java.initmemory=512

# Maximum Java Heap Size (in MB)
#wrapper.java.maxmemory=2048

# Application parameters. Add parameters as needed starting from 1
wrapper.app.parameter.1=%JBOSS_HOME%/jboss-modules.jar
wrapper.app.parameter.2=-mp
wrapper.app.parameter.3=%JBOSS_HOME%/modules
wrapper.app.parameter.4=-jaxpmodule
wrapper.app.parameter.5=javax.xml.jaxp-provider
wrapper.app.parameter.6=org.jboss.as.standalone
wrapper.app.parameter.7=-Djboss.home.dir=%JBOSS_HOME%

#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Enables Debug output from the Wrapper.
# wrapper.debug=TRUE

# Format of output for the console. (See docs for formats)
wrapper.console.format=PM

# Log Level for console output. (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=%SERVICE_HOME%\logs\wrapper_standalone_ha.log

# Format of output for the log file. (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output. (See docs for log levels)
wrapper.logfile.loglevel=ERROR

# Maximum size that the log file will be allowed to grow to before
# the log is rolled. Size is specified in bytes. The default value
# of 0, disables log rolling. May abbreviate with the 'k' (kb) or
# 'm' (mb) suffix. For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0

# Maximum number of rolled log files which will be allowed before old
# files are deleted. The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0

# Log Level for sys/event log output. (See docs for log levels)
wrapper.syslog.loglevel=NONE

#********************************************************************
# Wrapper General Properties
#********************************************************************
# Allow for the use of non-contiguous numbered properties
wrapper.ignore_sequence_gaps=TRUE

# Do not start if the pid file already exists.
wrapper.pidfile.strict=TRUE

# Title to use when running as a console
wrapper.console.title=JBoss Application Server 7.2.0.Alpha1 (standalone config, clustered mode)

#********************************************************************
# Wrapper JVM Checks
#********************************************************************
# Detect DeadLocked Threads in the JVM. (Requires Standard Edition)
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=10
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

# Out Of Memory detection.
# (Ignore output from dumping the configuration to the console. This is only needed by the TestWrapper sample application.)
wrapper.filter.trigger.999=wrapper.filter.trigger.*java.lang.OutOfMemoryError
wrapper.filter.allow_wildcards.999=TRUE
wrapper.filter.action.999=NONE
# (Simple match)
wrapper.filter.trigger.1000=java.lang.OutOfMemoryError
# (Only match text in stack traces if -XX:+PrintClassHistogram is being used.)
#wrapper.filter.trigger.1000=Exception in thread "*" java.lang.OutOfMemoryError
#wrapper.filter.allow_wildcards.1000=TRUE
wrapper.filter.action.1000=RESTART
wrapper.filter.message.1000=The JVM has run out of memory.

#********************************************************************
# Wrapper Email Notifications. (Requires Professional Edition)
#********************************************************************
# Common Event Email settings.
#wrapper.event.default.email.debug=TRUE
#wrapper.event.default.email.smtp.host=<SMTP_Host>
#wrapper.event.default.email.smtp.port=25
#wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification
#wrapper.event.default.email.sender=
#wrapper.event.default.email.recipient=

# Configure the log attached to event emails.
#wrapper.event.default.email.attach_log=TRUE
#wrapper.event.default.email.maillog.lines=50
#wrapper.event.default.email.maillog.format=LPTM
#wrapper.event.default.email.maillog.loglevel=INFO

# Enable specific event emails.
#wrapper.event.wrapper_start.email=TRUE
#wrapper.event.jvm_prelaunch.email=TRUE
#wrapper.event.jvm_start.email=TRUE
#wrapper.event.jvm_started.email=TRUE
#wrapper.event.jvm_deadlock.email=TRUE
#wrapper.event.jvm_stop.email=TRUE
#wrapper.event.jvm_stopped.email=TRUE
#wrapper.event.jvm_restart.email=TRUE
#wrapper.event.jvm_failed_invocation.email=TRUE
#wrapper.event.jvm_max_failed_invocations.email=TRUE
#wrapper.event.jvm_kill.email=TRUE
#wrapper.event.jvm_killed.email=TRUE
#wrapper.event.jvm_unexpected_exit.email=TRUE
#wrapper.event.wrapper_stop.email=TRUE

# Specify custom mail content
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n

#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
# using this configuration file has been installed as a service.
# Please uninstall the service before modifying this section. The
# service can then be reinstalled.

# Name of the service
wrapper.name=JBoss 7.2.0.Alpha1 (clustered mode)

# Display name of the service
wrapper.displayname=JBoss Application Server 7.2.0.Alpha1 (standalone config, clustered mode)

# Description of the service
wrapper.description=JBoss Application Server 7.2.0.Alpha1 (standalone config, clustered mode)

# Service dependencies. Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed. AUTO_START, DELAY_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false

JBoss7 can now be run by simply executing the corresponding batch file from {SERVICE_HOME}/bin. Please try running the application once as a console application to verify the configuration before attempting to run it as a service.

Congratulations. Your JBoss7 should now be up and running as a service.🙂

References: http://wrapper.tanukisoftware.com/doc/english/integrate.html

Scalable Full-Text Search Indexing using Lucene and CouchDB

The purpose of this post is to outline the steps I took in adding Full-Text Search indexing to a CouchDB installation. In addition I describe how to create a portable couchdb-lucene installation  that can be deployed to any server, runs in its own Java virtual machine and runs as a windows service using Java Service Wrapper.

The Facts

  • I am running a CouchDB server. Version 1.1.0 to be exact. For the configuration described here to work, you need to be using at least version 1.1.0 of CouchDB.
  • My couchDB sever is running at http://localhost:5984.
  • I wish to add full-text indexing to one or more of my databases on CouchDB.
  • I am running Windows 7.
  • I have java installed.

The Steps.

First of all, you need to download couchdb-lucene at least version 0.7.0 from the couchdb-lucene project on github.

You also need to download the Java Service Wrapper from Tanuki Software.  I am testing with 3.5.11 community version of the java service wrapper.

If you do not have java installed, do it now. Install, preferably, at least version 1.5 of the Java runtime environment.

Create a folder in the C: drive and name it dist. Inside this folder, extract couchdb-lucene 0.7.0. Also, copy the jre folder of the Java you have installed or just installed into this dist folder. So now you have a structure like the following:

dist

|–> couchdb-lucene.v.0.7.0

|–> jre6

Extract the java service wrapper into any folder of your choice but our dist folder from above.🙂

Now its time to integrate the java service wrapper into couchdb-lucene. There are four directories that need to be present inside the couchdb-lucene root folder:

  • bin
  • lib
  • conf
  • logs

Copy the following files into couchdb-lucene’s bin folder.

{WRAPPER_HOME}\bin\wrapper.exe
{WRAPPER_HOME}\src\bin\App.bat.in
{WRAPPER_HOME}\src\bin\InstallApp-NT.bat.in
{WRAPPER_HOME}\src\bin\UninstallApp-NT.bat.in

Rename the three batch files, substituting App with your applications name, for example. Be sure to remove the .in extensions so that the files all end in .bat.
(Depending on how your file explorer is configured on your computer, you may not be able to see file extensions.)
You should now have:

{couchdblucene_HOME}\bin\wrapper.exe
{couchdblucene_HOME}\bin\couchdblucene.bat
{couchdblucene_HOME}\bin\Installcouchdblucene-NT.bat
{couchdblucene_HOME}\bin\Uninstallcouchdblucene-NT.bat

The wrapper.exe is the actual wrapper executable. couchdblucene.bat is used to run lucene in the console, and it’s Install and Uninstall counterparts are used to install and uninstall the windows service for couchdb lucene  respectively.

Then copy the following files into couchdb-lucene’s lib folder.

{WRAPPER_HOME}\lib\wrapper.jar
{WRAPPER_HOME}\lib\wrapper.dll

The wrapper.dll file is a native library file required by the portion of the Wrapper which runs within the JVM. The wrapper.jar file contains all of the Wrapper classes.
You should now have.

{couchdblucene_HOME}\lib\wrapper.jar
{couchdblucene_HOME}\lib\wrapper.dll

Now copy the following template for a wrapper.conf file into couchdb-lucene’s conf folder

{WRAPPER_HOME}\src\conf\wrapper.conf.in

now you should have

{couchdblucene_HOME}\conf\wrapper.conf

Create a logs directory inside couchdb-lucene’s root directory so you now have

{couchdblucene_HOME}\logs

Now it is time to modify your wrapper.conf to tell the java service wrapper how it is supposed to run couchdb-lucene in service mode.  I have mine below. Notice how the JAVA_HOME variable is set to the location of the jre6 folder we have in the dist folder (next to couchdb-lucene0.7.0).

set.COUCH_HOME=..\
set.JAVA_HOME=..\..\jre6
wrapper.java.command=%JAVA_HOME%/bin/java

# Tell the Wrapper to log the full generated Java command line.
#wrapper.java.command.loglevel=INFO

# Java Main class.  This class must implement the WrapperListener interface
#  or guarantee that the WrapperManager class is initialized.  Helper
#  classes are provided to do this for you.  See the Integration section
#  of the documentation for details.
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp

# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
wrapper.java.classpath.1=../lib/wrapper.jar
wrapper.java.classpath.2=../lib/*.jar

# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=../lib

# Java Bits.  On applicable platforms, tells the JVM to run in 32 or 64-bit mode.
wrapper.java.additional.auto_bits=TRUE

# Java Additional Parameters
wrapper.java.additional.1=-server
wrapper.java.additional.2=-XX:MaxPermSize=256m

# Initial Java Heap Size (in MB)
wrapper.java.initmemory=256

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=1024

# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=com.github.rnewson.couchdb.lucene.Main

#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Enables Debug output from the Wrapper.
# wrapper.debug=TRUE

# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=../logs/wrapper.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE

#********************************************************************
# Wrapper General Properties
#********************************************************************
# Allow for the use of non-contiguous numbered properties
wrapper.ignore_sequence_gaps=TRUE

# Title to use when running as a console
wrapper.console.title=CouchDB Lucene 0.7.0

#********************************************************************
# Wrapper JVM Checks
#********************************************************************
# Detect DeadLocked Threads in the JVM. (Requires Standard Edition)
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=60
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

# Out Of Memory detection.
# (Simple match)
wrapper.filter.trigger.1000=java.lang.OutOfMemoryError
# (Only match text in stack traces if -XX:+PrintClassHistogram is being used.)
#wrapper.filter.trigger.1000=Exception in thread "*" java.lang.OutOfMemoryError
#wrapper.filter.allow_wildcards.1000=TRUE
wrapper.filter.action.1000=RESTART
wrapper.filter.message.1000=The JVM has run out of memory.

#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
#  using this configuration file has been installed as a service.
#  Please uninstall the service before modifying this section.  The
#  service can then be reinstalled.

# Name of the service
wrapper.name=CouchDB Lucene 0.7.0

# Display name of the service
wrapper.displayname=CouchDB Lucene 0.7.0

# Description of the service
wrapper.description=CouchDB Lucene 0.7.0

# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed.  AUTO_START, DELAY_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false

If you followed the steps, running Installcouchdblucene.bat from the bin folder would install couchdb-lucene as a windows service on your machine.

The next step is to tell our couchDB installation about the new buddy in town, couchdb-lucene.  Open the local.ini file in couchDB server’s installation directory. The path is %couchhome%\etc\couchdb\local.ini and add the following:

[couchdb]
timeout = 60000
[httpd_global_handlers]
_fti = {couch_httpd_proxy, handle_proxy_req, <<"http://localhost:5985">>}

Take note of the http://localhost:5985 url. That is the url of couchdb-lucene.

Restart couchDB and couchdblucene services and you should have both of them integrated on start up. The actual indexing technique is a topic for another blog post.

References:
https://github.com/rnewson/couchdb-lucene
http://wrapper.tanukisoftware.com/doc/english/integrate-simple-win.html
http://blog.foaa.de/2011/05/squeeze-couchdb-lucene/

Running CouchDB and JBoss Application Server in Reverse Proxy mode

In my previous post, Transforming XML Data into JSON documents using JQuery, I had to parse KJV.xml, using  jQuery, to retrive all the verses of the bible in a separate JSON document. There were 31,102 documents in total. What I left out of that post was that I had to move all these documents into CouchDB. Preferably, also using jQuery AJAX. Before I continue, I’d like to say a few words about CouchDB.

CouchDB is a robust, scalable and high performance document oriented database server which is accessible over a RESTful JSON API. It is schemaless and ad hoc which allows your domain objects to evolve independently of one another. It implements incremental replication with bidirectional conflict detection. It is also indexable and queryable. Just like replication, indexing is also incremental. Which means as your data gets bigger, the time to access particular indexes takes roughly the same time. CouchDB uses a table oriented reporting engine, MapReduce for CouchDB, which uses javascript as the query engine.

If you are like me, and running a Windows machine, then you can find an exe build of CouchDB 1.1.0 with all of its dependencies, Erlang and so on, here.

After installing, go to http://localhost:5984 and you should see the welcome message

        {"couchdb":"Welcome","version":"1.1.0"}

Go to  http://localhost:5984/_utils/index.html to visit Futon, the administration interface for CouchDB.

Now fast forward to the AJAX part. In my javascript, I have just created a javascript object containing the text, verse number, chapter, book and testament of a particular verse of the bible. Now I would like to save this object as a document in CouchDB. For this, you can use the jQuery.Couch plugin.

The entire javascript for this parsing and couchdb initializing with the data from KJV.xml is in the code snippet below.

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script src="http://localhost:5984/_utils/script/json2.js"></script>
    <script src="http://localhost:5984/_utils/script/sha1.js"></script>
    <script src="http://localhost:5984/_utils/script/jquery.js?1.4.2"></script>
    <script src="http://localhost:5984/_utils/script/jquery.couch.js?0.11.0"></script>
    <script src="http://localhost:5984/_utils/script/jquery.dialog.js?0.11.0"></script>

</head>

<body>

	<script type="text/javascript">

	jQuery(window).load( function() {

	});

	jQuery(document).ready( function(){

		$.couch.urlPrefix = "http://localhost:5984";

		$.couch.login({
		    name: "yourusername",
		    password: "yourpassword",
		    success: function(data) {

		    },
		    error: function(status) {

		    }
		});

       $.ajax({
	        type: "GET",
			url: "KJV.xml",
			dataType: "xml",
			success: function(xml) {
				var count = 0;
				var doc = {};

				$(xml).find('bible').each(function(){
					var translation = $(this).attr('translation');

					$(this).find('testament').each( function(){
						var testament = $(this).attr( 'name');

						$(this).find('book').each( function() {
							var book = $(this).attr('name');

							$(this).find('chapter').each( function(){
								var chapternumber = $(this).attr('number');

								$(this).find('verse').each( function(){
									var versenumber = $(this).attr('number');

									var versetext = $(this).text();
									count++;

									var doc = {};
									doc["_id"] = count.toString();
									doc["translation"] = translation;
									doc["testament"] = testament;
									doc["book"] = book;
									doc["chapter"] = parseInt(chapternumber);
									doc["versenumber"] = parseInt(versenumber);
									doc["versetext"] = versetext;

									$.couch.db("bibleverses").saveDoc(doc, {
									    success: function(data) {

									    },
									    error: function(status) {

									    }
									});

								});
							});
						});

					});
				});
	}
		});

	});
	</script>
</body>
</html>

But now there is a problem. The html file containing the javascript xml parser, is in a web app running on JBoss Application Server 6. The html file is accessible on my local machine at http://localhost:8080/bibleverses/index.html. But browsers enforce the Same-Origin Policy for AJAX requests. This means that to perform an AJAX request, the page from which the request is made and the target of the request must be within the same domain. So since our couchdb resdes on localhost:5984 and jboss on localhost:8080, AJAX requests are not successful.

This problem can be solved using the mod_proxy module of Apache httpd to enable Reverse Proxying for CouchDB and JBoss. This means we will be able to access our jboss web app under, for example, http://www.bibleverses.org/site and couchdb under http://www.bibleverses.org/couch. Both of them would have the same origin and thus ajax requests from the web app would be consumed successfully by the couchdb server.

The names you choose to use must either be registered as a domain name and have requests for www cname forwarded to the IP of your server or you can do local dns mapping if you are on windows.

Just add

192.168.2.123  www.bibleverses.org

to your %SYSTEMROOT%\System32\drivers\etc\hosts file. Of course you can choose any name here but whatever name you choose is what you must use when the time for the reverse proxy configuration arises.

Now you need to install Apache Http and make sure it listens on port 80.

The next step is the installation of the mod_proxy, mod_proxy_http and mod_proxy_ajp modules of apache. To do that, open the config file for Apache, %APACHEHOME%\conf\httpd.conf. By the way I am using version 2.2.19 of apache for my tests.

Make sure the following lines are not commented out in the configuration file:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Make sure Apache is listening on port 80 of the external network interface and create a named virtual host with the same values

Listen 192.168.2.123:80
NameVirtualHost 192.168.2.123:80

For security, make sure that the proxy is accessible by only IPs in my local area network. This can be adjusted later in a production environment. In addition, I create a VirtualHost directive, specifying the value of the NameVirtualHost we talked about earlier. A server name is the minimum requirement for a Virtual Host directive and in my example, http://www.bibleverses.org was used. This means that when a request is sent to http://www.bibleverses.org, use the virtual hosting information defined in this directive. The ProxyPass just means that when /site subfolder of the ServerName is requested, forward that to the web app on JBoss and when /couch is requested, forward that to couchdb.

<Proxy *>
	Order Deny,Allow
	Deny from all
	Allow from 192.168.2
</Proxy>

<VirtualHost 192.168.2.123:80>
    ServerName www.bibleverses.org
    ProxyPass /site http://127.0.0.1:8080/bibleverses
    ProxyPass /couch http://127.0.0.1:5984
</VirtualHost>

This means we can access couchdb as http://www.bibleverses.org/couch and the site with the javascript at http://www.bibleverses.org/site/index.html. The AJAX requests will now work from the web app to couchdb.

An added advantage of the Reverse Proxy setup is that now, we only need to open one port 80 on our NAT device. No need anymore to open 5984 and 8080 to direct access to the internet. All requests for couchdb and jboss stuff will come through port 80 of apache httpd. In addition, it can be used as a load balancer to balance load among several back-end servers such as jboss servers (in conjunction with JBoss mod_cluster), or to provide caching for a back-end server such as couchdb.

Transforming XML Data into JSON documents using JQuery

Recently, someone very close to me, asked me to develop an app that would be useful in the religious scene. I am not exactly the religious type but I figured it could be fun to use technology in doing something boring in a new and exciting way. I immediately thought about doing something with the Bible. I remember, years and years ago, trying to read the bible. It all seemed so monotonous. So many pages, very cramped words. Finding a new verse as the priest told his sermon seemed to take quite a few seconds. It was all basically a boring process.

So why not create something which enables high-performance, full text, instant search of the Bible, with the ability to use Audio input (in some browsers like chrome). Something that can find exact phrase matches in the bible in a few milliseconds. Something that can answer statistical questions based on the bible. How many times was the word ‘Lord’ used in the bible. What about ‘Jesus’? What about any other word? In a few milliseconds! All of this, from the browser! Why not go one step further and make this service into a programming interface (API) for the bible? An API upon which other apps could be built: apps for the browser, mobile phone, iPad, whatever! An API built on RESTful principles of the web, accessible ubiquitously via the HTTP protocol.

My first idea was to split a digital version of the bible into the smallest meaningful unit: verses. But I was confronted with the problem of finding a digital version of the bible. I set about searching the web, googling. I luckily came across an XML data dump of the bible at believersresource.com. I downloaded the data and decided to use the ‘King James Version’. By opening KJV.xml, I was happy with the xml schema used in describing their data. Below is a snippet of the data contained in KJV.xml.

<bible translation="KJV">
	<testament name="Old">
		<book name="Genesis">
			<chapter number="1">
				<verse number="1">In the beginning God ....</verse>
				<verse number="2">And the earth was without .... </verse>
				<verse number="3">And God said, Let there .....</verse>
                        </chapter>
                 </book>
        </testament>
        <testament name="New">
                 <book name="Matthew">
                         <chapter number="1">
                               <verse number="1"> .... </verse>
                         </chapter>
                 </book>
        </testament>
</bible>

Now I just had to parse this file to extract the verses into separate JSON documents. I wanted the verses to have a JSON like the one shown below:

{
   "translation": "KJV",
   "testament": "Old",
   "book": "Genesis",
   "chapter": 1,
   "versenumber": 1,
   "versetext": "In the beginning God created the heaven and the earth."
}

I did not feel like having to wire up some STAX xml parser in java so I decided to go with doing it all in jQuery/javascript. I know that JQuery is very good at parsing xml. Web developers usually employ jQuery for the manipulation of HTML but the fact is that HTML is XML. So jQuery shines on arbitrary node travel in arbitrary XML. Furthermore, we are trying to create new JSON documents from the xml we read in. Well….JSON is basically javascript object notation, just abbreviated. So we can read our xml using javascript (in the form of jQuery) and create our javascript objects using plain old javascript too! Dream combo.

Below is the jQuery code I wrote to do the parsing.

$.ajax({
	type: "GET",
	url: "KJV.xml",
	dataType: "xml",
	success: function(xml) {

	var doc = null;

	$(xml).find('bible').each(function(){
		var translation = $(this).attr('translation');

		$(this).find('testament').each( function(){
			var testament = $(this).attr( 'name');

			$(this).find('book').each( function() {
				var book = $(this).attr('name');

				$(this).find('chapter').each( function(){
					var chapternumber = $(this).attr('number');

					$(this).find('verse').each( function(){

						var versenumber = $(this).attr('number');
						var versetext = $(this).text();

						doc = {};
						doc["translation"] = translation;
						doc["testament"] = testament;
						doc["book"] = book;
						doc["chapter"] = parseInt(chapternumber);
						doc["versenumber"] = parseInt(versenumber);
						doc["versetext"] = versetext;

					});
				});
			});

		});
	});
    }
});

So there it is. In the innermost loop in the code snippet above, a new doc object is created and various properties are set inside it. These properties were read and saved at different points during the xml traversal. Now that we have the doc objects, we can do something interesting with them. I will talk about that in the next blog posts. Oh btw. I think there are 31,102 verses in the bible😉

Max memory limits for 64-bit Windows 7

While the maximum RAM limit for 32-bit Windows 7 editions is 4GB, when it comes to the 64-bit editions, the amount of memory that the OS can address depends on which edition you are running.

Here are the upper RAM limits for the different editions of Windows 7:

Starter: 8GB
Home Basic: 8GB
Home Premium: 16GB
Professional: 192GB
Enterprise: 192GB
Ultimate: 192GB
These limits are similar to those for Vista editions, expect that Vista Enterprise and Vista Ultimate have had their upper limits raised from 128GB to 192GB.

The one to look out for there is the 16GB limit on Home Premium. If you’re building a Core i7 system then it’s quite easy (if you have the cash!) to exceed this limit. As long as you’re aware of the limit and plan your OS accordingly you’ll be OK.

Solution to Tuckey’s UrlRewriteFilter 3.2 DTD Validation Failure

What is UrlRewriteFilter?

 

Based on the popular and very useful mod_rewrite for apache, UrlRewriteFilter is a Java Web Filter for any J2EE compliant web application server (such as ResinOrion or Tomcat), which allows you to rewrite URLs before they get to your code. It is a very powerful tool just like Apache’s mod_rewrite.

URL rewriting is very common with Apache Web Server (see mod_rewrite’s rewriting guide) but has not been possible in most java web application servers. The main things it is used for are:

  • URL Tidyness / URL Abstraction – keep URLs tidy irrespective of the underlying technology or framework (JSP, Servlet, Struts etc).
  • Browser Detection – Allows you to rewrite URLs based on request HTTP headers (such as user-agent or charset).
  • Date based rewriting – Allows you to forward or redirect to other URL’s based on the date/time (good for planned outages).
  • Moved content – enable a graceful move of content or even a change in CMS.
  • Tiny/Friendly URL’s (i.e. blah.com/latest can be redirected to blah.com/download/ver1.2.46.2/setup.exe)
  • A Servlet mapping engine (see Method Invocation)

UrlRewriteFilter uses an xml file, called urlrewrite.xml (it goes into the WEB-INF directory), for configuration. Most parameters can be Perl5 style Regular Expressions or Wildcard Expressions. This makes it very powerful indeed.

 

What is the Problem?

 

The configuration file for the 3.2 version of the filter, urlrewrite.xml, fails validation in the Eclipse IDE. Particularly the following line.

<!DOCTYPE urlrewrite PUBLIC “-//tuckey.org//DTD UrlRewrite 3.2//EN”
http://tuckey.org/res/dtds/urlrewrite3.2.dtd”&gt;

This is the default document type declaration (DTD) for the file. Copying the url, http://tuckey.org/res/dtds/urlrewrite3.2.dtd, into your browser, you’ll realize that the url is redirected to the Tuckey home page, http://www.tuckey.org, instead of displaying the DTD.

 

What is the Solution?

 

By adding ‘www’ to the url, the problem seems to be solved. The new url, http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd seems to correctly display the DTD and furthermore, validation is successful in eclipse.

Therefore, if you use version 3.2 of the urlrewrite filter, your new DTD declaration in urlrewrite.xml should be:

<!DOCTYPE urlrewrite PUBLIC “-//tuckey.org//DTD UrlRewrite 3.2//EN”
http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd”&gt;

I hope it works for you.

 

References

 

http://code.google.com/p/urlrewritefilter/
https://groups.google.com/forum/#!topic/urlrewrite/COEdoePM0mU
http://gamerprospersonalblog.blogspot.com/2011/08/solved-urlrewritexml-validation-issue.html