I like form-login approach in servlets specification. It's easy to use and is supported by all servlet containers almost the same way. We use tomcat enginge in our development and met one small problem regarding form-login.
Everything works as expected excepting case when user session is timed out and you have to deal with other than Latin encoding (UTF-8 for example).
Forcing Tomcat to use UTF-8 for request data processing is a different long story... In short we use a filter which calls requiest.
setCharacterEncoding("UTF-8") for each request. This solution works great in 99,9% cases, exept this one:
If user tries to POST form data when HttpSession is timed out, posted data apears completely wrong decoded after successful user authorization. In this case servlet data is processed using default Latin charset instead of UTF-8 which is used by browser and which is set in our filter.
What should we do to avoid the situation? I tried to discover the problem i Tomcat source code: when user tries to access to a location he doesn't (yet) authorized, tomcat prcesses such request omitting all configured in web.xml filters. So request's charset encoding remains default which seems correct by security reasons. So I decided just didn't let HttpSession die.
Each page in protected area now contains following javascript:
function execRefresh() {
getXMLDOM("/xml/refresh", emptyFunc);
setTimeout("execRefresh()", 300000);
}
setTimeout("execRefresh()", 300000);
getXMLDOM - is a library function which fetches url data using XMLHttpRequest.
servlet mapped to /xml/refresh does nothing, it just doesn't let HttpSession object die.
As result we don't have to make session timeout too long, but if user closes browser window, session stored resources will be freed by time out.
Monday, July 30, 2007
Sunday, February 11, 2007
JSP precompiling in NetBeans
Precoplides JSPs can increase productivity a lot. As soon as all pages are precompiled in one step, it can be a good time saver.
There is a lot of information about how to precompile JSPs during building phase, but no complete solution. Ones write how to make JSPs precompiled, but don't how to get a working web.xml file. I even seen a statement like this one: you can get output of webXmlFragment and put it in your web.xml by hand. Sounds great. Doesn't fit our need at all.
So, the task is:
- you have web.xml that already contains all necessary settings for your application
- you have a lot of JSPs
- you'd like to get .class files for all of your JPSs
- you'd like to get jsp's servlets mapping added to your present web.xml
I use NetBeans prepared project structure here, but this solution can be used in plain build files with different project structure after some tuning.
You have to make 3 things:
1) setup following properties
libs.jasper.classpath - to jasper* jars located inside your tomcat / jboss installation
libs.javax.servlet.classpath - to javax.servlet.jar and javax.servlet.jsp.jar
jboss.home - to your jboss configuration (for ex. /usr/local/jboss/server/default)
2) add following code to your build.xml
======
<target name="-post-compile" depends="jspc, compile-jsp, merge-web.xml"/>
<target name="jspc">
<mkdir dir="${basedir}/${build.generated.dir}/etc"/>
<taskdef classname="org.apache.jasper.JspC" name="jasper2" >
<classpath id="jspc.classpath">
<path path="${libs.jasper.classpath}"/>
<path path="${libs.javax.servlet.classpath}"/>
<path path="${libs.struts.classpath}"/>
<pathelement location="${java.home}/../lib/tools.jar"/>
<pathelement location="classes"/>
</classpath>
</taskdef>
<mkdir dir="etc"/>
<jasper2
package="com.mawisoft.jsp"
validateXml="false"
uriroot="${build.web.dir.real}"
webxml="${basedir}/${build.generated.dir}/etc/web.xml"
outputDir="${basedir}/${build.generated.dir}/src"/>
</target>
<target name="compile-jsp">
<javac srcdir="${basedir}/${build.generated.dir}/src" destdir="${build.web.dir}/WEB-INF/classes">
<classpath>
<path path="${libs.jasper.classpath}"/>
<path path="${libs.javax.servlet.classpath}"/>
<path path="${javac.classpath}"/>
<pathelement location="classes"/>
<pathelement location="${jboss.home}/lib/commons-logging.jar"/>
</classpath>
</javac>
</target>
<target name="merge-web.xml">
<xslt basedir="." in="${web.docbase.dir}/WEB-INF/web.xml"
out="${build.web.dir}/WEB-INF/web.xml"
style="src/xsl/webxml-merge.xsl" force="true"><!-- force="${xsl.struts.force}"-->
<param name="file" expression="${basedir}/${build.generated.dir}/etc/web.xml"/>
</xslt>
</target>
===============
3) put following webxml-merge.xsl to src/xsl inside your war module
================
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:webapp="http://java.sun.com/xml/ns/j2ee" >
<xsl:namespace-alias stylesheet-prefix="webapp" result-prefix="#default" />
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<xsl:param name="file"/>
<xsl:template match="/" >
<web-app version="2.4" 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-app_2_4.xsd">
<xsl:copy-of select="webapp:web-app/webapp:servlet"/>
<xsl:copy-of select="document($file)/web-app/servlet"/>
<xsl:copy-of select="webapp:web-app/webapp:servlet-mapping"/>
<xsl:copy-of select="document($file)/web-app/servlet-mapping"/>
<xsl:copy-of select="webapp:web-app/webapp:session-config"/>
<xsl:copy-of select="webapp:web-app/webapp:welcome-file-list"/>
<xsl:copy-of select="webapp:web-app/webapp:jsp-config"/>
</web-app>
</xsl:template>
</xsl:stylesheet>
================
There is a lot of information about how to precompile JSPs during building phase, but no complete solution. Ones write how to make JSPs precompiled, but don't how to get a working web.xml file. I even seen a statement like this one: you can get output of webXmlFragment and put it in your web.xml by hand. Sounds great. Doesn't fit our need at all.
So, the task is:
- you have web.xml that already contains all necessary settings for your application
- you have a lot of JSPs
- you'd like to get .class files for all of your JPSs
- you'd like to get jsp's servlets mapping added to your present web.xml
I use NetBeans prepared project structure here, but this solution can be used in plain build files with different project structure after some tuning.
You have to make 3 things:
1) setup following properties
libs.jasper.classpath - to jasper* jars located inside your tomcat / jboss installation
libs.javax.servlet.classpath - to javax.servlet.jar and javax.servlet.jsp.jar
jboss.home - to your jboss configuration (for ex. /usr/local/jboss/server/default)
2) add following code to your build.xml
======
<target name="-post-compile" depends="jspc, compile-jsp, merge-web.xml"/>
<target name="jspc">
<mkdir dir="${basedir}/${build.generated.dir}/etc"/>
<taskdef classname="org.apache.jasper.JspC" name="jasper2" >
<classpath id="jspc.classpath">
<path path="${libs.jasper.classpath}"/>
<path path="${libs.javax.servlet.classpath}"/>
<path path="${libs.struts.classpath}"/>
<pathelement location="${java.home}/../lib/tools.jar"/>
<pathelement location="classes"/>
</classpath>
</taskdef>
<mkdir dir="etc"/>
<jasper2
package="com.mawisoft.jsp"
validateXml="false"
uriroot="${build.web.dir.real}"
webxml="${basedir}/${build.generated.dir}/etc/web.xml"
outputDir="${basedir}/${build.generated.dir}/src"/>
</target>
<target name="compile-jsp">
<javac srcdir="${basedir}/${build.generated.dir}/src" destdir="${build.web.dir}/WEB-INF/classes">
<classpath>
<path path="${libs.jasper.classpath}"/>
<path path="${libs.javax.servlet.classpath}"/>
<path path="${javac.classpath}"/>
<pathelement location="classes"/>
<pathelement location="${jboss.home}/lib/commons-logging.jar"/>
</classpath>
</javac>
</target>
<target name="merge-web.xml">
<xslt basedir="." in="${web.docbase.dir}/WEB-INF/web.xml"
out="${build.web.dir}/WEB-INF/web.xml"
style="src/xsl/webxml-merge.xsl" force="true"><!-- force="${xsl.struts.force}"-->
<param name="file" expression="${basedir}/${build.generated.dir}/etc/web.xml"/>
</xslt>
</target>
===============
3) put following webxml-merge.xsl to src/xsl inside your war module
================
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:webapp="http://java.sun.com/xml/ns/j2ee" >
<xsl:namespace-alias stylesheet-prefix="webapp" result-prefix="#default" />
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<xsl:param name="file"/>
<xsl:template match="/" >
<web-app version="2.4" 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-app_2_4.xsd">
<xsl:copy-of select="webapp:web-app/webapp:servlet"/>
<xsl:copy-of select="document($file)/web-app/servlet"/>
<xsl:copy-of select="webapp:web-app/webapp:servlet-mapping"/>
<xsl:copy-of select="document($file)/web-app/servlet-mapping"/>
<xsl:copy-of select="webapp:web-app/webapp:session-config"/>
<xsl:copy-of select="webapp:web-app/webapp:welcome-file-list"/>
<xsl:copy-of select="webapp:web-app/webapp:jsp-config"/>
</web-app>
</xsl:template>
</xsl:stylesheet>
================
Wednesday, December 27, 2006
building rich web application
New features like AJAX brought new generation of web applications, some great, some not so much. I personaly am a kind of old school web surfer. I don't like when I can't use back / forward /refresh buttons. I'm bored guessing if I can back to prevoius page or not, or what will happen if I click 'refresh' after posting some form data.
Meanwhile such broken design can be easily fixed. We've been using post-redirect-get for all form processing routines. It works like this: user fills form data, presses submit button then input data is sending by POST request to web application. The application sends REDIRECT to a page with a result immediately after processing POSTed data.
The result design is very clean and predictable. No more guessing: users can use back/forward/refresh/bookmark features and will get expected results.
Meanwhile such broken design can be easily fixed. We've been using post-redirect-get for all form processing routines. It works like this: user fills form data, presses submit button then input data is sending by POST request to web application. The application sends REDIRECT to a page with a result immediately after processing POSTed data.
The result design is very clean and predictable. No more guessing: users can use back/forward/refresh/bookmark features and will get expected results.
Subscribe to:
Posts (Atom)