JavaServer Pages

The following is some prototype (throwaway) code, written to demonstrate how front-end developers can interact with my stateless session beans.

<%@ page import="javax.ejb.*,
javax.naming.*,
javax.rmi.*,
com.topcoder.web.TCES.ejb.*,
java.rmi.*,
java.util.*" %>
<%!

	/*
	 * declare the handles to the EJBs
	 */

	private ProfileSkillXref	xrefBean = null;
	private Skill			skillBean = null;

	public void jspInit() {

		/*
		 * obtain EJB references
		 */

		try {
			InitialContext	context = new InitialContext();
			ProfileSkillXrefHome	xrefHome = (ProfileSkillXrefHome)
			  context.lookup( "java:comp/env/ejb/ProfileSkillXref" );
			xrefBean = xrefHome.create();
			SkillHome	skillHome = (SkillHome)
			  context.lookup( "java:comp/env/ejb/Skill" );
			skillBean = skillHome.create();
		}
		catch( Exception e ) {
			e.printStackTrace();
		}
	}

	public void jspDestroy() {

		/*
		 * setting the references to null permits
		 * garbage collection (not really necessary)
		 */

		xrefBean = null;
		skillBean = null;
	}
%>
<head>
<title>Test Page</title>
</head>
<body>
<script language="JavaScript">
function doDelete( skill ) {
	document.testForm.skillToDelete.value = skill
	return true
}
</script>
<%

	/*
	 * variable definitions
	 */

	Hashtable	skills = new Hashtable();
	Enumeration	list = request.getParameterNames();
	Integer		skill = null;
	Integer		level = null;

	/*
	 * get the current list of skills
	 */

	while( list.hasMoreElements() ) {
		String	key = (String) list.nextElement();
		String	value = (String) request.getParameter( key );
		if( key.startsWith( "skill_" ) ) {
			try {
				skill = new Integer( key.substring(
				  key.indexOf( '_' ) + 1 ) );
				level = new Integer( value );
				skills.put( skill, level );
			}
			catch( NumberFormatException e ) {
				e.printStackTrace();
			}
		}
	}

	/*
	 * update the skills in the database
	 */

	ProfileSkillXrefObject	skillXrefObj = null;
	Long		profileId = new Long( 1 );
	list = skills.keys();
	while( list.hasMoreElements() ) {
		skill = (Integer) list.nextElement();
		level = (Integer) skills.get( skill );
		if( skillXrefObj == null ) {
			skillXrefObj = new ProfileSkillXrefObject();
			skillXrefObj.profile_id = profileId;
		}
		skillXrefObj.skill_id = skill;
		try {
			skillXrefObj = xrefBean.request( ProfileSkillXref.SELECT, skillXrefObj );
			if( ! level.equals( skillXrefObj.skill_level_id ) ) {
				skillXrefObj.skill_level_id = level;
				skillXrefObj = xrefBean.request( ProfileSkillXref.UPDATE, skillXrefObj );
			}
		}
		catch( Exception e ) {
			e.printStackTrace();
			try {
				xrefBean.create( profileId, skill, level );
			}
			catch( Exception f ) {
				// serious problems here
			}
		}
	}

	/*
	 * get the action command
	 */

	String	button = request.getParameter( "submit" );
	if( button != null ) {
		if( button.equals( "Add" ) ) {

			/*
			 * add a new skill and set default level
			 */

			skill = new Integer( request.getParameter( "skill" ) );
			level = new Integer( 2 );
			skills.put( skill, level );
		}
		if( button.equals( "Delete" ) ) {

			/*
			 * delete a skill
			 */

			String	skillToDelete = request.getParameter( "skillToDelete" );
			skill = new Integer( skillToDelete.substring(
			  skillToDelete.indexOf( '_' ) + 1 ) );
			skills.remove( skill );
			skillXrefObj = new ProfileSkillXrefObject();
			skillXrefObj.profile_id = profileId;
			skillXrefObj.skill_id = skill;
			xrefBean.request( ProfileSkillXref.DELETE, skillXrefObj );
		}
		if( button.equals( ">>" ) ) {

			/*
			 * move on to next page
			 */

			response.sendRedirect( "NextPage.jsp" );
			return;
		}
	}

	/*
	 * now use the database to populate the hashtable, e.g. if
	 * this is our first visit to the page
	 */

	Hashtable ht = xrefBean.listSkillIdSkillLevelIdByProfileId( profileId );
	if( ht != null ) {
		list = ht.keys();
		while( list.hasMoreElements() ) {
			skill = (Integer) list.nextElement();
			level = (Integer) ht.get( skill );
			skills.put( skill, level );
		}
	}
%>
<form name="testForm" method="POST" action="getSkill.jsp">
<p>
<h2>Select skill</h2>
<p>
<select name="skill">
<%

	/*
	 * build the select options
	 */

	StringTokenizer	st = new StringTokenizer( skillBean.list() );
	Integer		key = null;
	String		value = null;

	while( st.hasMoreTokens() ) {
		key = null;
		try {
			key = new Integer( st.nextToken() );
		}
		catch( NumberFormatException e ) {
			e.printStackTrace();
		}

		/*
		 * don't put up skills already selected
		 */

		if( skills.get( key ) != null )
			continue;
		value = skillBean.getSkillDesc( key );
		out.println( "<option value=\"" + key.intValue() +
		  "\">" + value + "</option>" );
	}
%>
</select>
<input type="submit" name="submit" value="Add">
<p>
<h2>Select skill level</h2>
<p>
<%

	/*
	 * build skill level radio buttons
	 */

	if( skills.size() > 0 ) {
		out.println( "<table>" );
		list = skills.keys();
		while( list.hasMoreElements() ) {
			skill = (Integer) list.nextElement();
			level = (Integer) skills.get( skill );
			String	cbname = "skill_" + skill.toString();
			out.println( "<tr>" );
			out.println( "<th>" + skillBean.getSkillDesc( skill ) );
			for( int i = 0; i < 5; i++ ) {
				out.println( "<td>" );
				out.print( "<input name=\"" + cbname +
				  "\" type=\"RADIO\" value=\"" + i + "\"" );
				if( i == level.intValue() )
					out.print( " checked" );
				out.println( ">" );
			}

			/*
			 * build the skill delete button
			 */

			out.println( "<td>" );
			out.print( "<input type=\"submit\" name=\"submit\" value=\"Delete\" " );
			out.println( "onClick=\"return doDelete( '" +
			  cbname + "' )\">" );
			out.println( "</tr>" );
		}
		out.println( "</table>" );
	}
	else
		out.println( "NO SKILLS SELECTED" );
%>
<p>
<input type="hidden" name="skillToDelete">
Click <input type="submit" name="submit" value=">>"> to go to next page.
</form>
</body>
This is a re-entrant page with a dummy value used for profile_id. In the real world we would have had the user perform a login and maintained the profile_id in the session object. Here's what the rendered page looks like:

It's a nice, straightforward interface which is fairly intuitive. Select a skill and click the add button to include in your profile. The form will get POSTed, the selected skill and a default level added to the database, and the form redisplayed. Select the level (0-4) of familiarity with a particular skill or click on one of the delete buttons to remove the skill from your profile.

It's actually a fairly simple page, once you discount the EJB interface code, but it uses three JSP elements: directives, declarations and scriptlets. The directives are at the top of the file, enclosed by <%@ and %>. The page directive in this case indicates which classes the generated servlet will require. The declarations are enclosed by <%! and %> and exist at the class level, i.e. they are not included in the generated _jspService (per-call) method. The scriptlet code (enclosed by <& and &>) is included in the _jspService method.

We override the jspInit and jspDestroy methods in in our declarations section in order to obtain and release references to EJBs. It's more efficient to do this at the class level since we incur the overhead of the lookups only once. The first person to access the page will likely notice a slight delay but certainly not as much as the one which results from modification of the source. In that case the server has to compile the source down to a servlet.

There are three scriptlets in this code. The first one is executed as soon as the _jspService routine is entered and is responsible for processing the form contents, if any. It interacts with the stateless session EJB to maintain user information in the back-end database. If a user adds a skill, deletes a skill or modifies a skill level, the information is both reflected to the database and maintained locally in a Hashtable. It's important to note that all of the submit buttons in the form have the name attribute defined. That way the value of the element is passed as a parameter so that we can access it using the request.getParameter() method.

The second scriptlet generates a select element with a list of possible skills. We use the previously populated Hashtable to avoid displaying those skills which the user has already selected. Not absolutely necessary but it doesn't seem right to be permitted to add a skill which is already displayed in the table below. That table is generated by the third scriptlet which also sets the appropriate radio button to the checked state. The delete button associated with each skill calls the doDelete JavaScript function with the skill identifier. The function merely stuffs the argument into a hidden form field for processing by the first scriptlet.

I didn't get around to programming the JSP error page as this was never meant for production. Still, it does illustrate some of the basic concepts and works quite well. Those of you familiar with servlet programming will observe how I use the response.sendRedirect() method to move to the next page. I simply prefer this approach to one which uses all kinds of intermediate pages, such as in the Sun examples. So whether you write servlets and import the HTML or write JSPs and include the Java source, the end-result is the same. Six of one, half-dozen of the other.

Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 by Phil Selby. All rights reserved.