/* $Log$ Revision 1.16 2005/02/08 16:03:21 heto DbIndividual is now complete. Some bug tests are done. DbSamplingunit is converted. No bugtest. All transactions should now be handled in the GUI (yuck..) Revision 1.15 2005/02/07 15:54:01 heto Converted DbIndividual to PostgreSQL Now some transaction problem occures with Groupings (update) Revision 1.14 2004/03/25 17:04:43 heto Fixing debug messages. Removed dead code Revision 1.13 2004/03/15 13:56:20 heto Removed border on statistics page Revision 1.12 2004/03/02 08:44:54 wali Improved writeIndividual to include different date formats. createResults fgid handling improved Revision 1.11 2004/03/01 08:26:34 wali Renamed retrieveString to retrieveSymbol and retrieveApostrophe to retrieveSym. Added some symbols. Revision 1.10 2004/02/13 13:23:31 wali Extended with retrieveString. Changes ¤ to '. Revision 1.9 2003/05/02 07:58:45 heto Changed the package structure from se.prevas.arexis.XYZ to se.arexis.agdb.XYZ Modified configuration and source files according to package change. Revision 1.8 2003/04/25 12:14:45 heto Changed all references to axDefault.css Source layout fixes. Revision 1.7 2003/04/25 08:58:21 heto Added a function to print the default stylesheet. Revision 1.6 2002/12/20 09:19:21 heto Added a simple error page method. Revision 1.5 2002/12/13 15:00:57 heto Comments added Revision 1.4 2002/11/21 10:49:40 heto Changed to specification 1.3 or 1.4. session attributes has changed. Moved functions from other parts Revision 1.3 2002/10/22 06:08:07 heto rebuilt the "back-buttons". Dont save the request object, save the URL instead. New function. Revision 1.2 2002/10/18 14:32:24 heto No particular change. Revision 1.1.1.1 2002/10/16 18:14:04 heto Import of aGDB 1.5 L3 from Prevas CVS-tree. This version of aGDB is migrated to Tomcat from JServ by Tobias Hermansson Revision 1.26 2001/06/18 09:07:39 frob Several new, common methods added. Revision 1.25 2001/06/13 06:06:22 frob Changed the structure of the header table produced in HTMLWriter. From now, the table has only two rows. Any other stuff has to be placed within a content table (also produced byt the HTMLWriter). This modification caused updates in several servlets. Revision 1.24 2001/05/30 13:45:06 frob Moved writeStatisticsPage to ArexisServlet. Revision 1.23 2001/05/28 13:50:12 frob Removed logError method, use Errors.logError instead. Revision 1.22 2001/05/28 06:34:07 frob Adoption to changes in HTMLWriter. Revision 1.21 2001/05/23 12:32:32 roca fixed choice of chromosome for markerset membership changed order of links in adminProj. "Order by name" added it adm species & SU's Revision 1.20 2001/05/23 11:52:38 frob New method: logError Revision 1.19 2001/05/22 12:17:56 frob Minor fix in commitOrRollback. Revision 1.18 2001/05/22 06:16:49 roca Backfuncktionality fixed for all (?) servlets/subpages Revision 1.17 2001/05/21 08:17:06 roca Roca fixed nullreplacement for files, privs not displayed and counter in phenotypes Revision 1.16 2001/05/21 06:50:42 frob Minor update caused by update in HTMLWriter. Revision 1.15 2001/05/18 06:16:50 frob Restructured the file. Added code for getting/setting the application version. Revision 1.14 2001/05/16 08:55:26 frob Minor fix. Revision 1.13 2001/05/15 12:13:13 frob Added call to defaultCSS() in writeErrorPage() to as the css part is moved to a separate method. Revision 1.12 2001/05/14 12:32:05 frob Bugfix in writeErrorPage(), back button path were incorrect created. Revision 1.11 2001/05/09 12:51:36 frob Added new method: commitOrRollback() Revision 1.10 2001/05/04 11:14:45 frob Modified to use Errors class to find text to display on page. Interface changed. Revision 1.9 2001/05/03 13:18:09 frob New method: errorQueryString, returns query string to use when going back from error page. Revision 1.8 2001/05/03 07:55:10 frob Minor fix in removeQSParameter. Added methods for removing common parameters. */ package se.arexis.agdb.servlet; import java.io.*; import java.util.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; import se.arexis.agdb.util.*; /** * An abstract class that provides session control for the servlets * in the Arexis genetic database project. It extends the * <code>HttpServlet</code> which simplifies writing HTTP servlets. * This class overrides the <code>service</code> method and verifies * that the requesting client has the necessary information stored in * her/his session object. If not, the client is being redirected to * another location (redirectClass) * Because it is an abstract class, servlet writers must subclass it * and override at least one method. * The methods normally overridden are: * * <ul> * <li> <code>doGet</code>, if HTTP GET requests are supported. * Overriding the <code>doGet</code> method automatically also * provides support for the HEAD and conditional GET operations. * Where practical, the <code>getLastModified</code> method should * also be overridden, to facilitate caching the HTTP response * data. This improves performance by enabling smarter * conditional GET support. * * <li> <code>doPost</code>, if HTTP POST requests are supported. * <li> <code>doPut</code>, if HTTP PUT requests are supported. * <li> <code>doDelete</code>, if HTTP DELETE requests are supported. * * <li> The lifecycle methods <code>init</code> and * <code>destroy</code>, if the servlet writer needs to manage * resources that are held for the lifetime of the servlet. * Servlets that do not manage resources do not need to specialize * these methods. * * <li> <code>getServletInfo</code>, to provide descriptive * information through a service's administrative interfaces. * </ul> * * <P>Notice that the <code>service</code> method is not typically * overridden. The <code>service</code> method, as provided, supports * standard HTTP requests by dispatching them to appropriate methods, * such as the methods listed above that have the prefix "do". That is, * if the user has the necessary session data. Otherwise the servlet will * respond with the redirect HTTP-header. * In addition, the service method also supports the HTTP 1.1 protocol's * TRACE and OPTIONS methods by dispatching to the <code>doTrace</code> * and <code>doOptions</code> methods. The <code>doTrace</code> and * <code>doOptions</code> methods are not typically overridden. * * <P>Servlets typically run inside multi-threaded servers; servlets * must be written to handle multiple service requests simultaneously. * It is the servlet writer's responsibility to synchronize access to * any shared resources. Such resources include in-memory data such as * instance or class variables of the servlet, as well as external * components such as files, database and network connections. * Information on multithreaded programming in Java can be found in the * <a * href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html"> * Java Tutorial on Multithreaded Programming</a>. * * @version 1.0, 2000-10-05 */ public abstract class ArexisServlet extends HttpServlet { private String m_redirectPath; private boolean m_missingData; private String m_zone; private String m_rootPath; private String m_upFilePath; private String m_fileGeneratePath; private String m_nullReplacement; private int m_maxRows; private int m_maxDeviations; private String m_dateFormat; /** The version of the application */ private String mApplicationVersion = null; ////////////////////////////////////////////////////////////////////// // // Constructors // ////////////////////////////////////////////////////////////////////// public ArexisServlet() { } ////////////////////////////////////////////////////////////////////// // // Public section // ////////////////////////////////////////////////////////////////////// /** Reads specific init-parameters using the ServletConfig object. If * init-parameters are missing a flag is set for later use in the * service method. Finally the inherited version of the method is * called. * * @throws ServletException */ public void init() throws ServletException { m_missingData = false; ServletContext config = this.getServletContext(); // Get init parameters m_nullReplacement = config.getInitParameter("nullReplacement"); m_redirectPath = config.getInitParameter("redirectPath"); m_zone = config.getInitParameter("zone"); m_rootPath = config.getInitParameter("rootPath"); m_upFilePath = config.getInitParameter("upFilePath"); m_fileGeneratePath = config.getInitParameter("fileGeneratePath"); String maxRows = config.getInitParameter("maxRows"); m_dateFormat = config.getInitParameter("dateFormat"); String maxDev = config.getInitParameter("maxDeviations"); applicationVersion(config.getInitParameter("version")); // If any parameter is missing, set missing flag if (m_redirectPath == null || m_zone == null || m_rootPath == null || m_nullReplacement == null || m_upFilePath == null || m_fileGeneratePath == null || maxRows == null || m_dateFormat == null || maxDev == null || applicationVersion() == null) { m_missingData = true; } // if all parameters found, parse the integer values else { m_maxRows = Integer.parseInt(maxRows); m_maxDeviations = Integer.parseInt(maxDev); } //super.init(config); } public void destroy() { Errors.logInfo("ArexisServlet.destroy()"); super.destroy(); } /** A simple method that returns the value of the private variable zonePath * (i.e where the servlets should reside). * @param servletName * @return Returns a string of the path for the zone * */ public String getServletPath(String servletName) { return m_rootPath + m_zone + servletName ; } /** * A simple method that returns the value of the private variable upFilePath *(i.e where the uploaded files should be stored). * * @return Returns a string of the path to the upload directory. This value * is initiated in the configuration file. */ public String getUpFilePath() { return m_upFilePath ; } /** * A simple method that returns the value of the private variable FileGeneratePath *(i.e where the generated analyses files should be stored). */ public String getFileGeneratePath() { return m_fileGeneratePath; } /** * A simple method that returns the value of the private variable zonePath *(i.e where the servlets should reside). */ public boolean checkMissingData() { return m_missingData; } /** * A simple method that returns a complete URL consisting of the rootPath * given by inparameters and the desired extension given by "target" */ public String getURL(String target) { return m_rootPath + target; } /** * A simple method that returns the value to be used to replace NULL in HTML * output */ public String getNullReplacement(HttpSession session) { String nullR = null; if (session != null) nullR = (String) session.getAttribute("nullReplacement"); if (nullR == null) nullR = m_nullReplacement; return nullR; } /** * A simple method that returns the value to be used to replace NULL in FILE * output */ public String getFileNullReplacement(HttpSession session) { String nullR = null; if (session != null) nullR = (String) session.getAttribute("nullReplacement"); if (nullR == null) nullR = m_nullReplacement; if (nullR.equalsIgnoreCase(" ")) nullR = " "; return nullR; } /** * Sets the value that will be returned from the method <code> * getNullReplacement </code> */ public void setNullReplacement(HttpSession session, String newNR) { if (session != null ) session.putValue("nullReplacement", newNR); } /** * @param session * @return */ public String getDateFormat(HttpSession session) { String datef = null; if (session != null) datef = (String) session.getAttribute("dateFormat"); if (datef == null) datef = m_dateFormat; return datef; } /** * @param session * @param newDF */ public void setDateFormat(HttpSession session, String newDF) { if (session != null) session.putValue("dateFormat", newDF); } /** * @param session * @return */ public int getMaxRows(HttpSession session) { String maxRows = null; if (session != null) maxRows = (String) session.getAttribute("maxRows"); if (maxRows == null) maxRows = Integer.toString(m_maxRows); return Integer.parseInt(maxRows); } /** * @param session * @param newMR */ public void setMaxRows(HttpSession session, int newMR) { if (session != null) session.putValue("maxRows", Integer.toString(newMR) ); } /** * @return */ public int getMaxDeviations() { return m_maxDeviations; } /** * Returns the application version. * * @return The application version. */ public String applicationVersion() { return mApplicationVersion; } ////////////////////////////////////////////////////////////////////// // // Protected section // ////////////////////////////////////////////////////////////////////// /** * Writes the error page. * * @param request The request object to use. * @param response The response object to use. * @param rootKey The name of the root key to use when retrieving the * text to display on the page. * @param errorMessage The message from the database object. * @param servletName The name of the servled where error ocurred. * @exception ServletException If no PrintWriter could be created. * @exception IOException If no PrintWriter could be created. */ protected void writeErrorPage(HttpServletRequest request, HttpServletResponse response, String rootKey, String errorMessage, String servletName) throws ServletException, IOException { response.setContentType("text/html"); response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); PrintWriter out = response.getWriter(); try { HTMLWriter.doctype(out); HTMLWriter.openHTML(out); HTMLWriter.openHEAD(out, ""); HTMLWriter.defaultCSS(out); HTMLWriter.closeHEAD(out); HTMLWriter.openBODY(out, ""); HTMLWriter.headerTable(out, 0, Errors.keyValue(rootKey + ".Error")); // Start the content table and write the text to the page HTMLWriter.contentTableStart(out, 0); out.println("<TABLE border=0 cellspacing=0 cellpadding=0>\n"+ " <TR>\n" + " <TD>" + Errors.keyValue(rootKey + ".Error.Msg") + "</TD>\n" + " </TR>\n" + " <TR>\n" + " <TD> </TD>\n" + " </TR>\n" + " <TR>\n" + " <TD>Error message:</TD>\n" + " </TR>\n" + " <TR>\n" + " <TD> </TD>\n" + " </TR>\n" + " <TR>\n" + " <TD>" + errorMessage + "</TD>\n" + " </TR>\n" + " <TR>\n" + " <TD> </TD>\n" + " </TR>\n" + " <TR>\n" + " <TD>\n" + " <FORM action=\"\">\n" + HTMLWriter.backButton("JavaScript:location.href=\"" + getServletPath(servletName) + errorQueryString(request) + "\";") + "\n </FORM>\n" + " </TD>\n" + " </TR>\n" + "</TABLE>"); HTMLWriter.contentTableEnd(out); HTMLWriter.closeBODY(out); HTMLWriter.closeHTML(out); } catch (Exception e) { e.printStackTrace(System.err); } } /** * Writes the error page. This is a simpler variant with no predefined messages. * * @param request The request object to use. * @param response The response object to use. * @param rootKey The name of the root key to use when retrieving the * text to display on the page. * @param errorMessage The message from the database object. * @param servletName The name of the servled where error ocurred. * @exception ServletException If no PrintWriter could be created. * @exception IOException If no PrintWriter could be created. */ protected void writeErrorPage(HttpServletRequest request, HttpServletResponse response, String heading, String errorMessage) throws ServletException, IOException { response.setContentType("text/html"); response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); PrintWriter out = response.getWriter(); try { HTMLWriter.doctype(out); HTMLWriter.openHTML(out); HTMLWriter.openHEAD(out, ""); HTMLWriter.defaultCSS(out); HTMLWriter.closeHEAD(out); HTMLWriter.openBODY(out, ""); HTMLWriter.headerTable(out, 0, heading); // Start the content table and write the text to the page HTMLWriter.contentTableStart(out, 0); out.println("<TABLE border=0 cellspacing=0 cellpadding=0>\n"+ " <TR>\n" + " <TD>" + //heading + "</TD>\n" + " </TR>\n" + " <TR>\n" + " <TD> </TD>\n" + " </TR>\n" + " <TR>\n" + " <TD>Error message:</TD>\n" + " </TR>\n" + " <TR>\n" + " <TD> </TD>\n" + " </TR>\n" + " <TR>\n" + " <TD>" + errorMessage + "</TD>\n" + " </TR>\n" + " <TR>\n" + " <TD> </TD>\n" + " </TR>\n" + " <TR>\n" + " <TD>\n" + " <FORM action=\"\">\n" + "\n </FORM>\n" + " </TD>\n" + " </TR>\n" + "</TABLE>"); HTMLWriter.contentTableEnd(out); HTMLWriter.closeBODY(out); HTMLWriter.closeHTML(out); } catch (Exception e) { e.printStackTrace(System.err); } } /** * Removes a parameter from a query string. * * @param originalQS The query string to remove the paramter from. * @param parameterName The name of the parameter to remove. * @return The query string with the parameter removed. */ protected String removeQSParameter(String originalQS, String parameterName) { String returnQS; parameterName = parameterName + "="; // Find the start position of the parameter in the query string int startPos = originalQS.indexOf(parameterName); // If parameter not found, return the original string if (startPos < 0) { returnQS = originalQS; } // if found, remove parameter else { // Find the end position of the parameter by finding the // position of the following parameter, indicated by a '&' int endPos = originalQS.indexOf("&", startPos + parameterName.length()); // No additional parameter was found, means that the given // parameter is the last one. Return the part of the query string // that precedes the given parameter. if (endPos < 0) { returnQS = originalQS.substring(0, startPos); } // An additional parameter was found. Return the part of the query // string that precedes the given parameter as well as the part // that follows it else { returnQS = originalQS.substring(0, startPos) + originalQS.substring(endPos + 1); } } return returnQS; } /** * Removes the "oper" parameter from the query string * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterOper(String originalQS) { return removeQSParameter(originalQS, "oper"); } /** * Removes the "sid" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterSid(String originalQS) { return removeQSParameter(originalQS, "sid"); } /** * Removes the "cid" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterCid(String originalQS) { return removeQSParameter(originalQS, "cid"); } /** * Removes the "pid" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterPid(String originalQS) { return removeQSParameter(originalQS, "pid"); } /** * Removes the "id" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterId(String originalQS) { return removeQSParameter(originalQS, "id"); } /** * Removes the "mid" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterMid(String originalQS) { return removeQSParameter(originalQS, "mid"); } /** * Removes the "iid" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterIid(String originalQS) { return removeQSParameter(originalQS, "iid"); } /** * Removes the "suid" parameter from the query string. * * @param originalQS The query string to remove the parameter from. * @return The query string with the parameter removed. */ protected String removeQSParameterSuid(String originalQS) { return removeQSParameter(originalQS, "suid"); } /** * Returns the query string that should be used when going back from the * error page. Default an empty string is returned. * * @param request The request object to use when building the string. * @return The an empty string. */ protected String errorQueryString(HttpServletRequest request) { return ""; } /** * Commits or rollback a database operations. If operation is * rollbacked, an error page is written. * * @param connection The connection object to use. * @param request The request object to use. * @param response The response object to use. * @param rootKey The root key to use when finding error strings in * Errors.properties. * @param dbObjectMessage The error message from the database object. * @param servletPath The path to use on the back button on the error * page. * @param dbOperationOk Tells if the database operation was ok or not. * @return True if everyting is ok. * False if anything goes wrong. */ protected boolean commitOrRollback(Connection connection, HttpServletRequest request, HttpServletResponse response, String rootKey, String dbObjectMessage, String servletPath, boolean dbOperationOk) { boolean isOk = true; try { // If everything is OK, commit the transaction if (dbOperationOk) { connection.commit(); Errors.logDebug("commitOrRollback: commit"); } // Something is wrong, rollback and write error page else { // Ensure connection is initialized before use if (connection != null) { connection.rollback(); } Errors.logDebug("commitOrRollback: rollback"); // Write the error page writeErrorPage(request, response, rootKey, dbObjectMessage, servletPath + "?"); } } catch (Exception e) { isOk = false; e.printStackTrace(System.err); } return isOk; } /** * Writes the statistical page. If a backstring is given, a back button * is written on the page. * * @param out The PrintWriter to write to. * @param generalData The general data. * @param statisticData The statistical data. * @param backString The string to use as event for the back button. */ protected static void writeStatisticsPage(PrintWriter out, String[][] generalData, String[][] statisticData, String backString) { // Write the start of the page HTMLWriter.doctype(out); HTMLWriter.openHEAD(out, ""); HTMLWriter.defaultCSS(out); HTMLWriter.closeHEAD(out); // Open body, write header table and start content table HTMLWriter.openBODY(out, ""); HTMLWriter.headerTable(out, 0, Errors.keyValue("Projects.Statistics")); HTMLWriter.contentTableStart(out, 0); // Start general table and write the general data. out.println("<H3>General data</H3>"); out.println("<TABLE border=0 width=400>"); for (int row = 0; row < generalData.length; row++) { out.println("<TR>\n" + " <TD width=125>" + generalData[row][0] + ":</TD>\n" + " <TD>" + generalData[row][1] + "</TD>\n" + "</TR>"); } out.println("</TABLE>"); out.println("\n<HR>\n"); // Start statistical table and write statistics data. out.println("<H3>Statistics</H3>"); out.println("<TABLE border=0>"); for (int row = 0; row < statisticData.length; row++) { out.println("<TR>\n" + " <TD width=125>" + statisticData[row][0] + ":</TD>\n" + " <TD>" + statisticData[row][1] + "</TD>\n" + "</TR>"); } out.println("</TABLE>"); // If back string is given, write a back button if (backString != null && backString != "") { out.println("<FORM action=\"\">\n " + HTMLWriter.backButton(backString) + "\n" + "</FORM>"); } // Finish the page. HTMLWriter.contentTableEnd(out); HTMLWriter.closeBODY(out); HTMLWriter.closeHTML(out); } /** * A simple method used to send a redirect-response to client. * The redirect will include the name of the servlet to redirect to ("redirectClass") * and the path to that servlet given by the init-argumet "redirectPath." * * @param res HttpServletResponse that encapsulates the response * from the servlet * * @exception IOException if detected when handling the request * @exception ServletException if the request could not be handled * * @see javax.servlet.http#HttpServletResponse */ protected void redirect(HttpServletResponse res) throws ServletException, IOException { res.sendRedirect(m_redirectPath+"redirectClass"); } /** * @param session * @param inputString * @param maxLength * @return */ protected String formatOutput(HttpSession session, String inputString, int maxLength) { String output = null; if (inputString == null || inputString.trim().equalsIgnoreCase("")) { output=getNullReplacement(session); if (output==null || output.trim().equalsIgnoreCase("")) { output = "  "; } } else { if (inputString.length() <= maxLength) { output = inputString; } else { output = inputString.substring(0,maxLength-2) +".."; } } return output; } /** * @param in * @param nullSubst * @return */ protected String replaceNull(String in, String nullSubst) { return (in != null ? in : nullSubst); } /** * @return */ protected String getDateValidationScript() { String output = "<SCRIPT language=\"JavaScript\">\n" + "<!--\n" + "var valid = '0123456789';\n" + "\n" + "function isValid(string,allowed) {\n" + " for (var i=0; i< string.length; i++) {\n" + " if (allowed.indexOf(string.charAt(i)) == -1)\n" + " return false;\n" + " }\n" + " return true;\n" + "}\n" + "\n" + "//-->\n" + "</SCRIPT>\n" + "\n" + "\n" + "\n" + "<script language=\"javaScript\">\n" + "function valDate(control, allowEmpty) {\n" + " var value = trim(control.value);\n" + " var length;\n" + " var year;\n" + " var month;\n" + " var day;\n" + " var hour;\n" + " var minutes;\n" + " control.value = trim(control.value);\n" + " length = control.value.length;\n" + " if (allowEmpty && length == 0)\n" + " return true;\n" + " // The date must be in the format YYYY-MM-DD[ HH:MI]\n" + " if (length != 10 && length != 16) {\n" + " displayError('Date must be specified as \\'YYYY-MM-DD\\' or as\\n' +\n" + " '\\'YYYY-MM-DD HH:MI\\', where HH is the hour given as\\n' +\n" + " 'a number between 0 and 23 and MI is the minutes.');\n" + " return false;\n" + " }\n" + " if ((control.value.charAt(4) != '-' || control.value.charAt(7) != '-') ||\n" + " (length == 16 && control.value.charAt(13) != ':') ) {\n" + " displayError('Date must be specified as \\'YYYY-MM-DD\\' or as\\n' +\n" + " '\\'YYYY-MM-DD HH:MI\\', where HH is the hour given as\\n' +\n" + " 'a number between 0 and 23 and MI is the minutes.');\n" + " return false;\n" + " }\n" + "\n" + " year = control.value.substring(0, 4);\n" + " if (!checkDigits(year, 1900, 2102) ) {\n" + " displayError('Year must be in the range 1900 to 2102.');\n" + " return false;\n" + " }\n" + " month = control.value.substring(5, 7);\n" + " if (!checkDigits(month, 1, 12) ) {\n" + " displayError('Month must be in the range 01 to 12.');\n" + " return false;\n" + " }\n" + " day = control.value.substring(8, 10);\n" + " if (!checkDigits(day, 1, 31) ) {\n" + " displayError('Day must be in the range 01 to 31.');\n" + " return false;\n" + " }\n" + "\n" + " if (length == 16) {\n" + " hour = control.value.substring(11, 13);\n" + " if (!checkDigits(hour, 00, 23) ) {\n" + " displayError('Hour must be in the range 00 to 23.');\n" + " return false;\n" + " }\n" + " minutes = control.value.substring(14, 16);\n" + " if (!checkDigits(minutes, 00, 59)) {\n" + " displayError('Minutes must be in the range 00 to 59.');\n" + " return false;\n" + " }\n" + " }\n" + "\n" + " return true;\n" + "}\n" + "function checkDigits(num, min, max) {\n" + " var ret = true;\n" + " // First we make sure that the variable num only contains digits\n" + " if (!isValid(num, valid) ) {\n" + " ret = false;\n" + " }\n" + " if (max < num || num < min)\n" + " ret = false;\n" + " return ret;\n" + "}\n" + "\n" + "function displayError(str) {\n" + " alert(str);\n" + "}\n" + "</script>\n" + "<SCRIPT LANGUAGE=\"JavaScript\">\n" + "<!--\n" + "function trim(str) {\n" + " while (str.substring(0,1) == ' ') str = str.substring(1);\n" + " while (str.substring(str.length-1,str.length) == ' ') str = str.substring(0,str.length-1);\n" + " return str;\n" + "}\n" + "//-->\n" + "</SCRIPT>\n" + "\n"; return output; } /** This method saves the URL for later use the pressing * "back" buttons. Method getPrevURL gets the saved value for use in * links and buttons. * * This also have a migration function from the old way of adding attribute * "RETURNING=YES" to the QS. If attribute is set, redirect to the last * known URL. A faster way is to use the method "getPrevURL" directly on * the "back" button. * @param req The request object * * @param res The response object. * * @throws IOException Throws IOException * * @return Returns a servlet response object to use for redirection. */ protected HttpServletResponse checkRedirectStatus(HttpServletRequest req,HttpServletResponse res) throws IOException { String tmp = null; tmp = req.getParameter("RETURNING"); if (tmp == null) tmp = "NO"; if (tmp.equals("YES")) { //Redirect the user to the last known URL. Errors.logInfo("Redirecting="+req.getSession().getAttribute("prevRequest")); res.sendRedirect((String)req.getSession().getAttribute("prevRequest")); } else { // Save the url for possible redirection later. Errors.logInfo("Saving url="+req.getRequestURI()+"?"+req.getQueryString()); req.getSession().setAttribute("prevRequest",req.getRequestURI()+"?"+req.getQueryString()); } return res; } /** Return the last known URL. Use this method for buttons and links for * abort/back purposes. * @return Returns a String value for the latest known URL * @param req The HttpServletRequest object as input value. */ protected String getPrevURL(HttpServletRequest req) { return (String)req.getSession().getAttribute("prevRequest"); } /** * Sets the sampling unit id of the session object and returns a value * indicating whether the sampling unit id was changed or not. If the * query string of the given request contains a suid, the session object * is assigned this value. If no suid is found in the query string, the * suid in the session object is reused. If no suid found in neihter the * session or the request object, a default value is used. * * @param request a HttpServletRequest value * @return True if suid has changed * False if we are reusing a suid from session object. */ protected boolean setSessionSuid(HttpServletRequest request) { HttpSession session = request.getSession(true); // Get suids from session and request String sessionSuid = (String) session.getAttribute("SUID"); String requestSuid = request.getParameter("suid"); // Indicates if the suid is changed. boolean suidHasChanged = true; // The suid value to use. Initialize with default value. String newSuid = Defaults.DEFAULT_SUID; // If there is a suid in the request, use it if (Utils.assigned(requestSuid) && !Utils.blank(requestSuid)) { newSuid = requestSuid; // If the request suid is the same as in the session, the suid has // not really changed if (requestSuid.equals(sessionSuid)) { suidHasChanged = false; } } // if there is a suid in the session, use it. As we are reusing the // suid, the suid has not changed else if (Utils.assigned(sessionSuid) && !Utils.blank(sessionSuid)) { newSuid = sessionSuid; suidHasChanged = false; } // Set the suid of the session and exit session.putValue("SUID", newSuid); return suidHasChanged; } /** * Returns a value for the action parameter based on the given request * and given su state. If the sampling unit did changed, a default value * is used for the action parameter. If the suid did not change and * there is a action parameter in the request, reuse that value. * * @param request The request from client. * @param suidHasChanged Indicates wheter the suid has changed or not. * @return A valid value for the action parameter */ protected String getAction(HttpServletRequest request, boolean suidHasChanged) { // The current action. Initialize to default value. String action = Defaults.DEFAULT_ACTION; // If the suid has not changed, try to read the old action parameter // from the request if (!suidHasChanged) { String oldAction = request.getParameter("ACTION"); // If value found and it is not blank, us this value as return // value if (Utils.assigned(oldAction) && !Utils.blank(oldAction)) { action = oldAction; } } return action; } /** * Returns a valid value for the orderby parameter based on the given * request object and the given suid state. If the suid has changed, a * default value is returned. If the suid has not changed, and there is * a value in the request object, that value is returned. * * @param request The request from client. * @param suidHasChanged Indicates whether the suid did change or not. * @return A valid orderby value */ protected String getOrderBy(HttpServletRequest request, boolean suidHasChanged) { // Get the default value String orderBy = Defaults.DEFAULT_ORDERBY; // If suid has not changed, try to read the old orderBy value if (!suidHasChanged) { String oldOrderBy = request.getParameter("ORDERBY"); // If value found and it is not blank, use this value as return // value if (Utils.assigned(oldOrderBy) && !Utils.blank(oldOrderBy)) { orderBy = oldOrderBy; } } return orderBy; } /** * Returns a valid startindex parameter based on the state of the suid, * gsid, the request, the action and the number of elements. If any of * suid or gsid has changed, a default value is returned. If none is * changed, the startIndex is read from the request. Then the startIndex * value is recalculated depending on the value of the action * parameter. If startIndex is found but action is blank, the found * startIndex value is reused. If no startIndex value is found, a * default value will be used. * * @param request The request from the client. * @param elements Total number of elements to display. * @param suidHasChanged Indicates whethere the suid has changed or not. * @param gsidHasChanged Indicates whethere the gsid has changed or not. * @param action The current action. * @return A valid value for the action parameter. */ protected String getStartIndex(HttpServletRequest request, int elements, boolean suidHasChanged, boolean gsidHasChanged, String action) { HttpSession session = request.getSession(true); // The startIndex to use. Initialize with default value. String newStartIndex = Defaults.DEFAULT_STARTINDEX; // If suid and gsid has not changed, we might modify the start // index. If any id did change, ignore this if (!suidHasChanged && !gsidHasChanged) { // Get the startIndex parameter from the request. String requestStartIndex = request.getParameter("STARTINDEX"); if (Utils.assigned(requestStartIndex) && !Utils.blank(requestStartIndex)) { // startIndex was found. Convert it to integer to make it easier // to handle. int startIndex = Integer.parseInt(requestStartIndex); // Ensure the action parameter is given if (Utils.assigned(action) && !Utils.blank(action)) { // Get the preferred number of rows per page int maxRows = getMaxRows(session); /* * It might be necessary to adjust the startIndex depending on * the action. startIndex is adjusted when action is * Servlet.Action.First * Servlet.Action.Prev * Servlet.Action.Next * Servlet.Action.Last * Servlet.Action.Display */ // If action is "first", set startIndex to 1 if (action.equals(Defaults.ACTION_FIRST)) { startIndex = 1; } // If action is "previous", decrease current startIndex with the // number of rows displayed per page. If startIndex gets too low // there are too few items to display so start on item 1 instead. else if (action.equals(Defaults.ACTION_PREV)) { startIndex -= maxRows; if (startIndex < 1) { startIndex = 1; } } // If action is "next", increase current startIndex with the number // of rows displayed per page. If startIndex gets higher than // there are items to display, use old startIndex. else if (action.equals(Defaults.ACTION_NEXT)) { startIndex += maxRows; if (startIndex > elements) { startIndex -= maxRows; } } // If action is "last", calculate the startIndex. else if (action.equals(Defaults.ACTION_LAST)) { // First calculate number of required pages and any rest int pages = elements / maxRows; int rest = elements % maxRows; // If at least one page and no rest if (pages > 0 && rest == 0) { startIndex = ((pages - 1) * maxRows) + 1; } // If at least one page and some rest else if (pages > 0 && rest != 0) { startIndex = (pages * maxRows) + 1; } } // If action is "display", always use start index 1 else if(action.equals(Defaults.ACTION_DISPLAY)) { startIndex = 1; } newStartIndex = String.valueOf(startIndex); } } } return newStartIndex; } /** * Returns a string with single "'". Cannot handle "null" strings */ protected String retrieveSymbol(String str) { str.trim(); return retrieveSym(str); } ////////////////////////////////////////////////////////////////////// // // Private section // ////////////////////////////////////////////////////////////////////// /** * Sets the version of the application. * * @param version The version of the application. */ private void applicationVersion(String version) { mApplicationVersion = version; } private String retrieveSym(String searchString) { int index = 0; int sym = 0; String StrOut = ""; String symbol[] = {"#","'", "&"}; String replace[] = {"¤!", "¤%","¤£"}; int no = symbol.length; //number of symbols //account for the symbols in the parameter for (sym=0; sym < no; sym++){ for (index = searchString.indexOf(replace[sym]); index != -1; index = searchString.indexOf(replace[sym])) { // Copy up to the symbol StrOut += searchString.substring(0, index); StrOut += symbol[sym]; searchString = searchString.substring(index + 2); } StrOut += searchString; searchString = ""; searchString = StrOut; StrOut = ""; index=0; } return searchString; } /** * Deletes the file system object pointed out by the given string. * * @param deletePath The path to the object to remove. * @return True if object was removed. * False if object was not removed. */ protected boolean deleteFileObject(String deletePath) { try { // Ensure that the path to object to delete contains the path to // the directory with generated files. If not, we are trying to // delete something which is not a generated file which is an // error. if ((deletePath.indexOf(getFileGeneratePath()) < 0) && (deletePath.indexOf(getUpFilePath()) < 0)) { throw new Exception("Delete path (" + deletePath + ") does not contain the path to the " + "directory with generated files (" + getFileGeneratePath() + ")."); } // Build a file object based on the delete path and check its // existence. If it does not exist, exit with true to indicate the // item is deleted. File fileSystemObject = new File(deletePath); if (!fileSystemObject.exists()) { return true; } // If file object is a directory if (fileSystemObject.isDirectory()) { // Get the contents of the directory and call deleteFileObject // recursively for each item in the directory. If any item can // not be deleted, we will bail out. String[] directoryItems = fileSystemObject.list(); for (int i = 0; i < directoryItems.length; i++) { Assertion.assertMsg(deleteFileObject(deletePath + "/" + directoryItems[i]), "Failed to delete directory item " + deletePath + "/" + directoryItems[i]); } } // Try to delete the file system object itself Assertion.assertMsg(fileSystemObject.delete(), "Failed to delete the file system object " + fileSystemObject.getPath()); } catch (Exception e) { e.printStackTrace(System.err); return false; } return true; } /** Create a directory if it does not exist * @param path The path (directory) to create * @return Return true or false if the operation succeded. * */ protected boolean createPath(String path) { File file = null; boolean ret = true; try { file = new File(path); if (!file.isDirectory()) { if (!file.mkdirs()) ret = false; } } catch (Exception e) { e.printStackTrace(System.err); ret = false; } return ret; } }