20 December 2007

My fNotebook: Apache Tomcat / Bioinformatics

Hi all,
here is how I installed created and installed today a web application based on JSP (Java Server Page) and running on tomcat.



A prior knowledge on how deploying a web application with tomcat is required so this post is more a notebook than a tutorial.

First download tomcat 6.0, extract it:
wget -q "http://apache.cict.fr/tomcat/tomcat-6/v6.0.14/bin/apache-tomcat-6.0.14.tar.gz"
tar xfz apache-tomcat-6.0.14.tar.gz


Fetch the mysql java connector, extract it, and move in into the tomcat 'lib' folder
wget -q "ftp://ftp.inria.fr/pub/MySQL/Downloads/Connector-J/mysql-connector-java-5.1.5.tar.gz"
tar xfz mysql-connector-java-5.1.5.tar.gz
mv mysql-connector-java-5.1.5/mysql-connector-java-5.1.5-bin.jar apache-tomcat-6.0.14/lib/


I need the java standard template library JSTL library. I fetch and extract it.
wget "http://people.apache.org/builds/jakarta-taglibs/nightly/projects/standard/jakarta-taglibs-standard-20060823.tar.gz"
tar xfz jakarta-taglibs-standard-20060823.tar.gz


I create a database of snp.
mysql -u root -p -D test -e 'create table snp(chrom varchar(10) ,chromStart int not null,chromEnd int not null,name varchar(20) unique not null)'

I fill this database with a few snp from dbsnp@ucsc
mysql -N --user=genome --host=genome-mysql.cse.ucsc.edu -A -D hg18 -e 'select chrom,chromStart,chromEnd,name from snp126 where chrom="chrM" ' |\
gawk -F ' ' '{printf("insert into test.snp(chrom,chromStart,chromEnd,name) values (\"%s\",%s,%s,\"%s\");\n",$1,$2,$3,$4);}' |\
mysql -u login -p


I add a mysql connection pool in apache. In apache-tomcat-6.0.14/conf/context.xml , I add the following code just before the last tag </Context>
<Resource name="jdbc/MYSQL" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="login" password="yourpassword" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test?autoReconnect=true"/>


we also need to setup a few properties before running tomcat:

export JAVA_HOME /usr/your-path/java1.6
export CATALINA_HOME=${PWD}/apache-tomcat-6.0.14
export CATALINA_BASE=${PWD}/apache-tomcat-6.0.14


we can now run tomcat.
./apache-tomcat-6.0.14/bin/startup.sh
Using CATALINA_BASE: /home/pierre/tmp/TOMCAT/apache-tomcat-6.0.14
Using CATALINA_HOME: /home/pierre/tmp/TOMCAT/apache-tomcat-6.0.14
Using CATALINA_TMPDIR: /home/pierre/tmp/TOMCAT/apache-tomcat-6.0.14/temp
Using JRE_HOME: /usr/your-path/java1.6/jre


we then create a few new directories

mkdir -p ./src/jsp
mkdir -p ./src/org/lindenb/jsp


We create a first JSP Custom TAG in src/org/lindenb/jsp/Anchor2DbSNP.java. This custom JSP tag will be used to create a automatic anchor to dbSNP.
package org.lindenb.jsp;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.util.regex.*;

/**
* This is a simple printing a link to dbSNP.
*/
public class Anchor2DbSNP extends BodyTagSupport
{
static private final Pattern RS_PATTERN=Pattern.compile("rs[0-9]+");

public int doEndTag() throws JspException
{
try
{
BodyContent bodyContent= getBodyContent();
if(bodyContent==null) return EVAL_PAGE;
String input=bodyContent.getString().trim().toLowerCase();
if(RS_PATTERN.matcher(input).matches())
{
getPreviousOut().print(
"<a href='http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?rs="+
input.substring(2)+
"'>"+
input+
"</a>"
);
}
else
{
getPreviousOut().print(input);
}
} catch(java.io.IOException err)
{
throw new JspException(err);
}
return EVAL_PAGE;
}
}


Another two custom tags will be used to display a simple genomic map in SVG.

Here is src/org/lindenb/jsp/ChromosomeTag.java

package org.lindenb.jsp;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.util.regex.*;
import java.util.*;

public class ChromosomeTag extends BodyTagSupport
{
private static class Position
{
int position=0;
String name=null;
public Position(int position,String name)
{
this.position=position;
this.name=name;
}
}

private Vector<Position> items= null;
private int svgWidth=500;
private int itemHeight=20;


public int doStartTag() throws JspException
{
items= new Vector<Position>();
return EVAL_BODY_INCLUDE;
}

public void addPosition(int position,String name)
{
if(position<0 || name==null) return;
this.items.addElement(new Position(position,name));
}

public int doEndTag() throws JspException
{
//if(this.items.isEmpty()) return EVAL_PAGE;
int max=0;
int min=Integer.MAX_VALUE;
for(Position p:this.items)
{
max=Math.max(p.position,max);
min=Math.min(p.position,min);
}
try
{
JspWriter out= pageContext.getOut();
out.write("<svg xmlns:xlink='http://www.w3.org/1999/xlink' xmlns='http://www.w3.org/2000/svg' width='"+svgWidth+"' height='"+ (this.items.size()*itemHeight)+"' style='font-size:"+(itemHeight-10)+"pt;stroke-width:1;'>");
out.write("<rect x='0' y='0' width='"+svgWidth+"' height='"+ (this.items.size()*itemHeight)+"' style='fill:white; stroke:gray;'/>");
int y=0;
for(Position p:this.items)
{
int x= (int)(((p.position-min)/(float)(max-min))*(svgWidth-200))+100;
out.write("<line x1='"+x+"' y1='"+y+"' x2='"+x+"' y2='"+(y+itemHeight)+"' style='stroke:blue;'/>");

out.write("<line x1='0' y1='"+y+"' x2='"+svgWidth+"' y2='"+(y)+"' style='stroke:gray;'/>");

out.write("<text x='"+(x+4)+"' y='"+(y+5+itemHeight/2)+"' >"+p.name+"</text>");
y+=itemHeight;
}

out.write("</svg>");

}
catch(java.io.IOException err)
{
throw new JspException(err);
}
items=null;
return EVAL_PAGE;
}

public void release()
{
items=null;
}
}


and

src/org/lindenb/jsp/ChromItemTag.java
package org.lindenb.jsp;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.util.regex.*;


public class ChromItemTag extends BodyTagSupport
{
private int position=-1;
private String name="";

public void setPosition(int position) { this.position= position;}


public int doEndTag() throws JspException
{
BodyContent bodyContent= getBodyContent();
if(bodyContent!=null) this.name =bodyContent.getString().trim();
if(this.name==null || name.length()==0) this.name=String.valueOf(this.position);
Tag parent= findAncestorWithClass(this,ChromosomeTag.class);
if(parent==null) return EVAL_PAGE;
ChromosomeTag ct= ChromosomeTag.class.cast(parent);
ct.addPosition(this.position+20,this.name);
return EVAL_PAGE;
}

public void release()
{
name=null;
position=-1;
}
}



the file src/bio.tld is the file used to declare the three custom tags.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">

<description>Bioinfo JSP TAG library</description>
<display-name>Bioinfo</display-name>
<tlib-version>1.1</tlib-version>
<short-name>bio</short-name>
<uri>http://jsp.lindenb.org</uri>

<tag>
<name>rs</name>
<tag-class>org.lindenb.jsp.Anchor2DbSNP</tag-class>
<body-content>JSP</body-content>
<info>display a link to dbSNP</info>
</tag>

<tag>
<name>chrom</name>
<tag-class>org.lindenb.jsp.ChromosomeTag</tag-class>
<body-content>JSP</body-content>
<info>svg map</info>
</tag>

<tag>
<name>item</name>
<tag-class>org.lindenb.jsp.ChromItemTag</tag-class>
<body-content>JSP</body-content>
<info>svg item</info>
<attribute>
<name>position</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>


</taglib>



the file cat src/jsp/page.jsp is our JSP. It displays a SVG map and a table of a few SNP. It uses the JSTL and our custom tags.
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:sql="http://java.sun.com/jsp/jstl/sql"
xmlns:bio="http://jsp.lindenb.org"

version="2.0">
<jsp:directive.page contentType="text/xml; charset=iso-8859-1"/>
<jsp:output doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
omit-xml-declaration="true"
/>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JSP Tutorial For Bioinformatics</title>
<!-- <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1" /> -->
</head>
<body>
<sql:query var="snps" dataSource="jdbc/MYSQL">select * from snp limit 10</sql:query>
<bio:chrom>
<c:forEach var="row" items="${snps.rows}">

<bio:item position="${row.chromStart}"><c:out value="${row.name}"/></bio:item>
</c:forEach>
</bio:chrom>

<sql:query var="snps" dataSource="jdbc/MYSQL">select * from snp limit 10</sql:query>
<table>
<tr><th>Position</th><th>Name</th></tr>
<c:forEach var="row" items="${snps.rows}">
<tr>
<td><c:out value="${row.chrom}"/>:<c:out value="${row.chromStart}"/>-<c:out value="${row.chromEnd}"/></td>
<td><bio:rs><c:out value="${row.name}"/></bio:rs></td>
</tr>
</c:forEach>
</table>
</body>
</html>
</jsp:root>


Tomcat needs src/web.xml as a descriptor to learn how to deploy this web application.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Application Name</display-name>
<description>Application Description</description>


<taglib>
<taglib-uri>http://jsp.lindenb.org</taglib-uri>
<taglib-location>/WEB-INF/bio.tld</taglib-location>
</taglib>

<!-- see http://www.developer.com/java/ejb/article.php/1447551 -->
<taglib>
<taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/fmt.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/fmt-rt</taglib-uri>
<taglib-location>/WEB-INF/fmt-rt.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/core-rt</taglib-uri>
<taglib-location>/WEB-INF/c-rt.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/sql</taglib-uri>
<taglib-location>/WEB-INF/sql.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/sql-rt</taglib-uri>
<taglib-location>/WEB-INF/sql-rt.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/x</taglib-uri>
<taglib-location>/WEB-INF/x.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/x-rt</taglib-uri>
<taglib-location>/WEB-INF/x-rt.tld</taglib-location>
</taglib>


</web-app>


and we finally need src/build.xml to build all this stuff with ant.
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Test" default="install" basedir=".">
<property name="tomcat.home" value="../apache-tomcat-6.0.14"/>
<property name="jstl.home" value="../jakarta-taglibs/standard"/>
<property name="webapps" value="${tomcat.home}/webapps"/>

<target name="compile">
<javac destdir="." srcdir="." debug="on">
<include name="org/lindenb/jsp/*.java"/>
<classpath>
<pathelement location="${jstl.home}/lib/jstl.jar"/>
<pathelement location="${jstl.home}/lib/standard.jar"/>
<pathelement location="${tomcat.home}/lib/servlet-api.jar"/>
<pathelement location="${tomcat.home}/lib/jsp-api.jar"/>
</classpath>
</javac>

<jar destfile="bio.jar"
basedir="."
includes="org/**"

/>

</target>

<target name="install" depends="compile">
<!-- yes, I know there is also war task... -->
<zip destfile="${webapps}/test.war">
<zipfileset dir="jsp" includes="*.jsp"/>
<zipfileset dir="." includes="web.xml" prefix="WEB-INF"/>
<zipfileset dir="${jstl.home}/tld" includes="*.tld" prefix="WEB-INF"/>
<zipfileset dir="." includes="*.tld" prefix="WEB-INF"/>
<zipfileset dir="${jstl.home}/lib" includes="*.jar" prefix="WEB-INF/lib"/>
<zipfileset dir="." includes="bio.jar" prefix="WEB-INF/lib"/>
</zip>
</target>

</project>


let's build this application. It creates a web archive (war) in the webapps folder of tomcat.
ant
Buildfile: build.xml

compile:
[jar] Building jar: /home/pierre/tmp/TOMCAT/src/bio.jar

install:
[zip] Building zip: /home/pierre/tmp/TOMCAT/apache-tomcat-6.0.14/webapps/test.war

BUILD SUCCESSFUL
Total time: 1 second


When you open "http://localhost:8080/test/page.jsp" you should get the following screen:



Pierre

17 December 2007

ShiftHappens

A great presentation about the future of eductation (somehow disheartening...)





see also: http://shifthappens.wikispaces.com/

13 December 2007

Embedded "ManyEyes" interactive visualization

Today ManyEyes launched the ability to embed an interactive visualization into your own blog, personal webpage or any other page you think makes sense: see http://blog.many-eyes.com/2007/12/12/embeddable-visualizations-have-arrived/.



Pierre

12 December 2007

IBD Status applet

I've just released an applet called IBDStatus. This applet (java 6 is required) is freely available at:




This applet takes as input the breakpoint analysis data (Nature. Dib et al.(1996); 380:152-154) from the 'Fondation Jean-Dausset' (CEPH) and display the Identical By Descent (IBD) regions between a pair of related individuals. Two people share an allele identical by descent if the two copies of the allele were inherited from a common ancestor. A pair of siblings can share 0, 1, or 2 alleles:
  • 0: not the same alleles

  • 1: only one allele in common

  • 2: both same alleles





Picture from Abel & Dessein


As an example, this IBD status can be used to design the controls of a CGH assay.







  • Top left pane: a linkage table with genotype=f(individual,marker)

  • Middle left pane: the list of individual: using the Ctrl-key select
    two related
    individuals an press the Add sib button. Your new pair is added in
    the bottom left table.

  • Bottom left pane: the list of sib-pairs: for each pair, the IBD status
    is displayed in the right table


  • Right table:

    • Marker index

    • chromosome

    • STS D-Number

    • Start-position (build 36)

    • End-position (build 36)

    • IBD status of each sib-pair(if any)

    • Count IBD with unknown status

    • Count IBD. 0


    • Count IBD. 1

    • Count IBD. 2






I wrote this software a few monthes ago but it was not much used, so I
was given the permission to release this version to the community.
Enjoy.

Pierre

06 December 2007

Google Chart API Launched

Today Google the Google Chart API a simple URL based tool for creating charts and graphs for websites.

For example the following url:


http://chart.apis.google.com/chart?
chco=ff0000,00ff00,0000ff /* colors */
&cht=p3 /* Chart Type= Pie */
&chd=t:1,2,3,4 /* Values */
&chs=400x200 /* Dimension */
&chl=Nature|PNAS|Science|EMBO|Virology /* LABELS */


will display this image:




Pierre

02 December 2007

PIvot

FYI: I put 'pivot' in the project hosted at http://code.google.com/ where I put some of my (open) source codes. Pivot is a java command-line tool, it digests a tabular source and prints a summary of the data. See the wiki page for more information http://code.google.com/p/lindenb/wiki/Pivot.

Pierre

01 December 2007

Women in Science 2

Maud

Maud came from Genethon where she took part of the creation of the first genetic map of the human genome. After several years at the National Center Of Genotyping, she became our engineer responsible for the production of the genotypes with the Illumina plateform at Integragen (this technology is the same as the one used by 23andMe).

Pierre

Women in Science 1

AS I said after Scifoo 2007, I should take some time to draw. So here it is...

Christine K.

A portrait of my former colleague Chistine, a biostatistician, who was in charge of the analysis of the genotypes produced at Integragen. She now works in an Inserm unit with Dr Florence Demenais on genetic epidemiology and multifactorial diseases.


Pierre