320 likes | 333 Views
The Tao of the Zen of the Art of Java Servlet Maintenance. In the Beginning (circa 1990). Internet a vast untamed wilderness Static HTML pages Flashing text CGI programs written in C “Under construction” signs VCs: plastics and pork futures. Web-Based Applications.
E N D
In the Beginning (circa 1990) • Internet a vast untamed wilderness • Static HTML pages • Flashing text • CGI programs written in C • “Under construction” signs • VCs: plastics and pork futures
Web-Based Applications • Programs that generate web pages • CGI (Common Gateway Interface) • Fast CGI • ASP, Servlets, PHP, AOLServer, etc. • Jakarta Tomcat • Cookies - a way to maintain state • How a hack becomes a standard
Client Web server Program RDBMS The Next Step • Database-backed web sites • Philip and Alex's Guide to Web Publishing • by Philip Greenspun • http://www.arsdigita.com/books/panda/ • A contemporary example: Citibank
Privacy and the Lack Thereof • Big brother is watching you • Cookies • IP address • DoubleClick • Recent merger with Abacus Direct • “Opting out” • Tainted e-mail
The Web Application Dilemma • HTML fragments embedded in a program • e.g., CGI (Perl, C, etc.), FastCGI, Servlets • Program fragments embedded in HTML • e.g., ASP, PHP, JSP, AOLServer, etc. • Considerations • Speed of development, maintainability • Separation of programming & graphic design
Java Servlets • Java API for web applications • Various implementations • Sun’s servletrunner • JRun • Apache JServ (now “Tomcat”) • Several advantages over Java-CGI
The Request package javax.servlet.http; public interface HttpServletRequest extends ServletRequest { public Cookie[] getCookies(); public String getMethod(); public String getRequestURI(); public String getServletPath(); public String getPathInfo(); public String getPathTranslated(); public String getQueryString(); public String getRemoteUser(); public String getAuthType(); public String getHeader(String name); public int getIntHeader(String name); public long getDateHeader(String name); public Enumeration getHeaderNames(); public HttpSession getSession (boolean create); public String getRequestedSessionId (); public boolean isRequestedSessionIdValid (); public boolean isRequestedSessionIdFromCookie (); public boolean isRequestedSessionIdFromUrl (); }
The Response package javax.servlet.http; public interface HttpServletResponse extends ServletResponse { public void addCookie(Cookie cookie); public boolean containsHeader(String name); public void setStatus(int sc, String sm); public void setStatus(int sc); public void setHeader(String name, String value); public void setIntHeader(String name, int value); public void setDateHeader(String name, long date); public void sendError(int sc, String msg) throws IOException; public void sendError(int sc) throws IOException; public void sendRedirect(String location) throws IOException; public String encodeUrl (String url); public String encodeRedirectUrl (String url); }
Session Management package javax.servlet.http; public interface HttpSession { public String getId (); public HttpSessionContext getSessionContext (); public long getCreationTime (); public long getLastAccessedTime (); public void invalidate (); public void putValue (String name, Object value); public Object getValue (String name); public void removeValue (String name); public String [] getValueNames (); public boolean isNew (); }
cbil.gus.servlet.SiteServlet • An “HTML in code” approach • No separate graphic designer • Leverage knowledge of Java • JSP immature at the time • Goal: a customizable Java Servlet • Editing a web site configuration file • Writing/customizing Java classes
package cbil.gus.servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; /** * Interface to identify objects that can generate HTML pages. * A collection of such objects are managed by the SiteServlet * to form a dynamic web site. * * Created: Wed Feb 16 10:15:22 EST 2000 * * @author Jonathan Crabtree * @version $Revision: 1.2 $ $Date: 2001/02/14 22:25:34 $ $Author: crabtree $ */ public interface PageGeneratorI { public String getPageName(); public void setSiteServlet(SiteServlet url); /** * @param rp If null the unencoded URL is returned. */ public String getPageURL(HttpServletResponse rp); /** * Generate an HTML page in response to the raw request <code>rq</code>. * * @param currentSession The current HttpSession. Null if none. */ public void generatePage(PrintWriter pw, HttpServletRequest rq, HttpServletResponse rp, HttpSession currentSession); }
package cbil.gus.servlet; public class SiteServlet extends HttpServlet { public void init(ServletConfig config) throws ServletException {...} public void doGet(HttpServletRequest rq, HttpServletResponse rp) { // Decide which object the request was intended for // and dispatch appropriately. // String values[] = rq.getParameterValues("page"); if ((values == null) || (values.length == 0) || (values[0] == null)) { if (defaultPage != null) { rp.setContentType("text/html"); PrintWriter pw = rp.getWriter(); } else { if (log != null) { String msg = "No 'page' parameter in request, and no defaultPage set."; log.write(new LogRecord("SiteServlet", msg, null, LogRecordTypeV.MESSAGE)); } } } else { displayPage(values[0], rq, rp); } } protected void doPost (HttpServletRequest rq, HttpServletResponse rp) throws ServletException, IOException { doGet(rq, rp); }
# -------------------------------------------------------------------- # PlasmodiumDB servlet configuration file # # Created: Fri May 19 23:07:37 EDT 2000 # # $Revision: 1.12 $ $Date: 2001/02/14 15:25:41 $ $Author: crabtree $ # -------------------------------------------------------------------- SEARCH_PACKAGES=cbil.gus.servlet.pages,\ cbil.gus.servlet.db, \ cbil.gus.servlet.db.params, … # -------------------------------------------- # SiteServlet configuration # -------------------------------------------- # List of pages on the site # pages=news,blast,sequences,genes,gseq,genesb,history,gene,estlib # -------------------------------------------- # GUSdev login # -------------------------------------------- gusOraSql.class=cbil.gus.servlet.db.oracle.SQL gusLogin.class=cbil.gus.servlet.db.ConnectionPool gusLogin.Login=@ORACLE_LOGIN@ gusLogin.Password=@ORACLE_PASSWORD@ gusLogin.DBUrl=@ORACLE_JDBC_URL@ gusLogin.NumConnections=10 gusLogin.MaxQueryTime=600 gusLogin.CheckInterval=30 gusLogin.JDBCDrivers=oracle.jdbc.driver.OracleDriver gusLogin.Sql=gusOraSql
package cbil.gus.servlet.db; . public class ConnectionPool implements ConnectionPoolI, MandatoryPropertiesI { public void setLogin(String login) {…} public String getLogin() { return this.login; } . . . // ------------------------------ // MandatoryPropertiesI // ------------------------------ protected static String mProps[] = new String[] {"Login", "Password", "DBUrl", "NumConnections", "JDBCDrivers", "Sql"}; public String[] getMandatoryProperties() { return mProps; } protected static String nProps[] = new String[] {}; public String[] getNullableProperties() { return nProps; } . . . } gusLogin.class=cbil.gus.servlet.db.ConnectionPool gusLogin.Login=@ORACLE_LOGIN@ gusLogin.Password=@ORACLE_PASSWORD@ gusLogin.DBUrl=@ORACLE_JDBC_URL@ gusLogin.NumConnections=10 gusLogin.MaxQueryTime=600 gusLogin.CheckInterval=30 gusLogin.JDBCDrivers=oracle.jdbc.driver.OracleDriver gusLogin.Sql=gusOraSql
EGAD Cellular Role Query genesByEGAD.DisplayName=EGAD cellular role genesByEGAD.Name=genesByEGAD genesByEGAD.Abbrev=genes by EGAD cell role genesByEGAD.SQL=select gf.na_feature_id \ from gusdev.GeneFeature gf, gusdev.AASequenceCellRole acr, \ gusdev.TranslatedAAFeature taf, gusdev.RNAFeature rf, gusdev.ExternalNASequence ena, \ gusdev.NALocation nal, gusdev.Algorithm a, gusdev.ProjectLink pl \ where acr.cell_role_id = $$1$$ \ and acr.aa_sequence_id = taf.aa_sequence_id \ and taf.na_feature_id = rf.na_feature_id \ and rf.parent_id = gf.na_feature_id \ and pl.id = gf.na_feature_id \ and pl.table_id = 108 \ and pl.project_id = 8 \ and ena.na_sequence_id = gf.na_sequence_id \ and ena.source_id like '$$0$$' ESCAPE '\' \ and gf.na_feature_id = nal.na_feature_id \ and gf.prediction_algorithm_id = a.algorithm_id (+) \ order by ena.na_sequence_id, a.name, nal.start_min genesByEGAD.HtmlBrief=Genes on chr. <!--ST0--> predicted to have EGAD cellular role '<!--ST1-->' genesByEGAD.HtmlLong=This query retrieves all predicted genes that have been assigned to a \ specified TIGR cellular role. The assignment of cellular roles to genes was performed using a \ machine-learning algorithm (C5.0) and was such that not every gene was assigned a cell \ role.<BR><BR> \ <B>WARNING:</B> <I>This prediction method was originally developed for mouse and human \ genes and has not yet been validated for <I>plasmodium</I>; we are the process of doing so now.</I> genesByEGAD.Params=chromP,tigrCellRoleNewP genesByEGAD.ResultFormatter=geneFeatureIdListF
Parameters (input) chromP.class=EnumParam chromP.Prompt=Chromosome: chromP.Description=Chromosome chromP.Values=%,chr1\_%,NC_000910,chr3\_%,chr4\_%,chr5\_%,chrBLOB\_%,chr9\_%,chr10\_%,chr11\_%,chr12\_%,chr13\_%,chr14\_% chromP.Labels=all,1,2 (finished),3 (finished),4,5,BLOB (6-8),9,10,11,12,13,14 chromP.Help=Select a <I>Plasmodium falciparum</I> chromosome. tigrCellRoleNewP.class=SQLTreeEnumParam tigrCellRoleNewP.Prompt=Cell role: tigrCellRoleNewP.Description=Cellular role tigrCellRoleNewP.Query=select cell_role_id, parent_id, name, cell_role_id \ from gusdev.CellRole where source = 'TIGR' tigrCellRoleNewP.RootID=-1 tigrCellRoleNewP.DBConnection=gusLogin tigrCellRoleNewP.Help=Please select a TIGR cellular role from those listed. Since \ TIGR's controlled vocabulary for cellular roles is hierarchical we are using \ JavaScript to display the structure of the blah blah blah...
Formatting (output) geneFeatureIdListF.class=SQLTableFormatter geneFeatureIdListF.DBConnection=gusLogin geneFeatureIdListF.Navbar=navbar geneFeatureIdListF.TableFormatter=geneFeatureIdListFT geneFeatureIdListF.RowQuery=geneRowQuery geneFeatureIdListF.QueryCache=queryCache geneFeatureIdListF.IdCols=na_feature_id geneRowQuery.class=SqlQuery geneRowQuery.DisplayName=Gene row query geneRowQuery.Name=geneRow geneRowQuery.Abbrev=gene geneRowQuery.SQL=select /*+ RULE */ gf.source_id, gf.number_of_exons, gf.gene_type, \ a.name as algorithm, ena.source_id, gf.product \ from gusdev.GeneFeature gf, gusdev.NALocation nal, gusdev.ExternalDatabase ed, \ gusdev.Algorithm a, $$0$$ ids, gusdev.ExternalNASequence ena \ where gf.na_feature_id = ids.na_feature_id \ and gf.na_feature_id = nal.na_feature_id \ and gf.prediction_algorithm_id = a.algorithm_id (+) \ and gf.external_db_id = ed.external_db_id \ and ena.na_sequence_id = gf.na_sequence_id \ and ids.i >= $$1$$ and ids.i <= $$2$$ geneRowQuery.HtmlBrief=Display information on a gene or set of genes (or gene predictions.) geneRowQuery.Params=naFeatIdP,intP,intP geneRowQuery.ResultFormatter=geneFeatureIdListF geneFeatureIdListFT.class=TableFormatter geneFeatureIdListFT.ColumnHeadings=gene prediction,exons,type,predicted by,contig,description geneFeatureIdListFT.ColumnFormats=geneFormat,cFormat,typeFormat,predbyFormat,contigFormat,productFormat geneFeatureIdListFT.HeadingFormats=HFL,HFC,HFC,HFC,HFC,HFC,HFC,HFC,HFC geneFeatureIdListFT.InnerTableAtts=border,1,cellspacing,0,cellpadding,1,width,100%
Cached Query Results create table guswww.Queries ( query_id number(12) not null, constraint PK_QUERIES primary key (query_id), servlet_name varchar2(30) not null, query_name varchar2(100) not null, param0 varchar2(25) null, param1 varchar2(25) null, param2 varchar2(25) null, param3 varchar2(25) null, param4 varchar2(25) null, param5 varchar2(25) null, param6 varchar2(25) null, param7 varchar2(25) null, param8 varchar2(25) null, param9 varchar2(25) null, . . . result_table varchar2(30) not null, start_time date not null, end_time date null );
CSP: CBIL Style Police/Policy • Ease the task of generating HTML from Perl and Java programs
Conclusions/Future Directions • The need for speed • ECS as a replacement for CSP? • Move towards a JSP implementation?
Further Reading • www.apache.org • www.cookiecentral.com • www.arsdigita.com/books/panda/ • www.doubleclick.net