The example described in this chapter uses the framework to build a server-side image map. It also shows how to do application-specific validation of the form data.
ClockBean is a Java bean that contains two standard properties (min and max), a read only property (hour) and a PointBean (clock). The read only property cannot participate to the mapping process and its value is computed using the x and y properties of clock.
All three setters of ClockBean do some validation. The setMin() methods verifies if the value is between 0 and 12, setMax() verifies if the value is between min and 12 and setClock() verifies if the user clicked inside the clock between min and max. If the validation fails the setter methods throw IllegalArgumentException and the framework will report the errors to the user.
Note: The throwing of any other exception than IllegalArgumentException would be interpreted as an application error.
ClockBean.java:
package com.devsphere.examples.mapping.imagemap;
import com.devsphere.mapping.PointBean;
/**
* Clock bean
*/
public class ClockBean implements java.io.Serializable {
public static final int MIN_VALUE = 0;
public static final int MAX_VALUE = 12;
public static final int RADIUS = 57;
public static final int XCENTER = 84;
public static final int YCENTER = 84;
private int min, max;
private PointBean clock;
/**
* No-arg constructor
*/
public ClockBean() {
}
/**
* Sets the min property
*/
public void setMin(int min) {
if (min < MIN_VALUE || min > MAX_VALUE)
throw new IllegalArgumentException();
if (min == MAX_VALUE)
min = MIN_VALUE;
this.min = min;
}
/**
* Gets the min property
*/
public int getMin() {
return min;
}
/**
* Sets the max property
*/
public void setMax(int max) {
if (max < min || max > MAX_VALUE)
throw new IllegalArgumentException();
this.max = max;
}
/**
* Gets the max property
*/
public int getMax() {
return max;
}
/**
* Sets the clock property
*/
public void setClock(PointBean clock) {
this.clock = clock;
int hour = getHour();
if (hour == -1 || hour < min || hour+1 > max) {
this.clock = null;
throw new IllegalArgumentException();
}
}
/**
* Gets the clock property
*/
public PointBean getClock() {
return clock;
}
/**
* Gets the hour property (read only)
*/
public int getHour() {
if (clock == null)
return -1;
int x = clock.getX() - XCENTER;
int y = YCENTER - clock.getY();
int rr = x * x + y * y;
if (rr > RADIUS * RADIUS)
return -1; // Outside the clock
if (rr == 0)
return min; // (x, y) == (0, 0)
double s = y / Math.sqrt(rr);
if (x >= 0) {
for (int hour = 0; hour < 5; hour++)
if (s > Math.sin(Math.PI/2 - Math.PI/6*(hour+1)))
return hour;
return 5;
} else {
for (int hour = 6; hour < 11; hour++)
if (s < Math.sin(-Math.PI/2 + Math.PI/6*(hour-5)))
return hour;
return 11;
}
}
}
The properties of ClockBean are mapped to the form elements of ClockForm.html:
Name |
Property type |
Element type |
|
|
|
min |
int |
text |
max |
int |
text |
clock |
PointBean |
image map |
When the user clicks on the clock image, the browser will submit the min and max values along with two other parameters (clock.x and clock.y) that contain the coordinates of the mouse click. The framework will take the coordinates and create a new PointBean object whose reference is stored to the clock property of the ClockBean object.
Note: Only com.devsphere.mapping.PointBean objects should be mapped to image maps.
The way the mapping between JavaBeans and HTML forms works was explained in a previous chapter.
ClockForm.html:
<HTML>
<HEAD><TITLE>Clock Form</TITLE></HEAD>
<BODY>
<H3>Image Map Example</H3>
<FORM METHOD="POST">
<P> Min <BR>
<INPUT TYPE="TEXT" SIZE="20" NAME="min">
<P> Max <BR>
<INPUT TYPE="TEXT" SIZE="20" NAME="max">
<P> Clock
<BR><INPUT TYPE="IMAGE" NAME="clock" SRC="clock.gif">
</FORM>
</BODY>
</HTML>
The ClockBeanResources class is a resource bundle containing default values, error messages, the processing order, the form's name and the processor's name.
The default values are defined for min and max. The clock property cannot have a default value due to its nature.
There are three error messages. Their role is to help the users to correct the input errors.
The processing order is very important to this example because the validation of max uses the value of min and the validation of clock uses the two values of min and max.
ClockBeanResources.java:
package com.devsphere.examples.mapping.imagemap;
import java.util.ListResourceBundle;
public class ClockBeanResources extends ListResourceBundle {
static final Object[][] contents = {
{ "[DEFAULT_VALUE.min]", new Integer(3) },
{ "[DEFAULT_VALUE.max]", new Integer(9) },
{ "[ERROR_MESSAGE.min]",
"Must be a number greater than 0 and less than 12" },
{ "[ERROR_MESSAGE.max]",
"Must be a number greater than 'Min' and less than 12" },
{ "[ERROR_MESSAGE.clock]",
"You must click inside the circle, between 'Min' and 'Max'" },
{
"[PROCESSING_ORDER]",
new String[] {
"min",
"max",
"clock"
}
},
{ "[FORM_NAME]", "ClockForm.html" },
{ "[PROC_NAME]", "ClockProc.jsp" }
};
public Object[][] getContents() {
return contents;
}
}
The ClockHndl.jsp handler is based on a template that was described in a previous chapter and is almost identical to the handler of the first example (SimpleHndl.jsp).
ClockHndl.jsp:
<%@ page language="java" %>
<%@ page import="com.devsphere.mapping.*, com.devsphere.logging.*" %>
<jsp:useBean id="clockBean" scope="request"
class="com.devsphere.examples.mapping.imagemap.ClockBean"/>
<%
// Get the bean resources
java.util.ResourceBundle beanRes
= HandlerUtils.getBeanResources(clockBean.getClass());
// Construct the base path
String basePath = request.getServletPath();
int slashIndex = basePath.lastIndexOf('/');
basePath = slashIndex != -1 ? basePath.substring(0, slashIndex+1) : "";
// Determine the HTTP method
boolean isPostMethod = request.getMethod().equals("POST");
// Create a logger that wraps the servlet context
ServletLogger logger = new ServletLogger(application);
// Wrap the form data
FormData formData = new ServletFormData(request);
// Form-to-bean mapping: request parameters are mapped to bean properties
java.util.Hashtable errorTable
= FormUtils.formToBean(formData, clockBean, logger);
if (isPostMethod && errorTable == null) {
// Construct the processor's path
String procPath = basePath + beanRes.getString("[PROC_NAME]").trim();
// Process the valid data bean instance
application.getRequestDispatcher(procPath).forward(request, response);
} else {
if (!isPostMethod)
// Ignore the user errors if the form is requested with GET.
errorTable = HandlerUtils.removeUserErrors(errorTable);
// Construct the form's path
String formPath = basePath + beanRes.getString("[FORM_NAME]").trim();
formPath = application.getRealPath(formPath);
// Get the form template
FormTemplate template = FormUtils.getTemplate(new java.io.File(formPath));
// Get a new document
FormDocument document = template.getDocument();
// Bean-to-form mapping: bean properties are mapped to form elements
FormUtils.beanToForm(clockBean, errorTable, document, logger);
// Send the form document
document.send(out);
}
%>
The ClockProc.jsp processor gets only valid bean objects and outputs the values of their properties.
ClockProc.jsp:
<%@ page language="java" %>
<jsp:useBean id="clockBean" scope="request"
class="com.devsphere.examples.mapping.imagemap.ClockBean"/>
<HTML>
<HEAD><TITLE>ClockBean Processor</TITLE></HEAD>
<BODY>
<H3>Image Map Example</H3>
<%
int hour = clockBean.getHour();
int nextHour = hour + 1;
if (hour == 0)
hour = 12;
%>
<P> You clicked between <%=hour%> and <%=nextHour%>
<P><B>ClockBean properties:</B>
<P> Min = <jsp:getProperty name="clockBean" property="min"/>
<P> Max = <jsp:getProperty name="clockBean" property="max"/>
<P> Hour = <jsp:getProperty name="clockBean" property="hour"/>
</BODY>
</HTML>
You may use the Java2D API on the server side to work with the (x, y) coordinates. For example you could load the image and get the color of a point. You may also verify if the (x, y) coordinates are inside a polygon, a rectangle or another area.
|