/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/basiclti/trunk/basiclti-impl/src/java/org/sakaiproject/util/foorm/Foorm.java $
* $Id: Foorm.java 132601 2013-12-15 21:41:15Z csev@umich.edu $
***********************************************************************************
*
* Copyright (c) 2011 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.util.foorm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.SortedMap;
import java.util.Properties;
import java.util.logging.Logger;
import java.lang.Number;
import java.sql.ResultSetMetaData;
/**
*
*/
public class Foorm {
private static Logger logger = Logger.getLogger("org.sakaiproject.util.foorm.Foorm");
/**
*
*/
public static String[] positional = { "field", "type" };
public static String NUMBER_TYPE = "java.lang.Number";
public static String STRING_TYPE = "java.lang.String";
// Parse a form field description
// field:type:key=value:key2=value2
/**
*
*/
public Properties parseFormString(String str) {
Properties op = new Properties();
String[] pairs = str.split(":");
int i = 0;
for (String s : pairs) {
String[] kv = s.split("=");
if (kv.length == 2) {
op.setProperty(kv[0], kv[1]);
} else if (kv.length == 1 && i < positional.length) {
op.setProperty(positional[i++], kv[0]);
} else {
// TODO : Log something here
}
}
return op;
}
// Returns -1 on failure
/**
*
*/
public Long getLongKey(Object key) {
return getLong(key);
}
/**
*
* @param key
* @return
*/
public Long getLong(Object key) {
Long retval = getLongNull(key);
if (retval != null)
return retval;
return new Long(-1);
}
/**
*
* @param key
* @return
*/
public Long getLongNull(Object key) {
if (key == null)
return null;
if (key instanceof Number)
return new Long(((Number) key).longValue());
if (key instanceof String) {
try {
return new Long((String) key);
} catch (Exception e) {
return null;
}
}
return null;
}
/**
*
* @param o
* @return
*/
public static int getInt(Object o) {
if (o instanceof String) {
try {
return (new Integer((String) o)).intValue();
} catch (Exception e) {
return -1;
}
}
if (o instanceof Number)
return ((Number) o).intValue();
return -1;
}
// Abstract this away for testing purposes
/**
*
*/
public Object getField(Object row, String column) {
if (row instanceof java.util.Properties) {
return ((java.util.Properties) row).getProperty(column);
}
if (row instanceof java.util.Map) {
return ((java.util.Map) row).get(column);
}
if (row instanceof java.sql.ResultSet) {
try {
return ((java.sql.ResultSet) row).getObject(column);
} catch (Exception e) {
return null;
}
}
return null;
}
/**
*
* @param row
* @param column
* @return
*/
public boolean isFieldSet(Object row, String column) {
if (row instanceof java.util.Properties) {
return ((java.util.Properties) row).containsKey(column);
}
if (row instanceof java.util.Map) {
return ((java.util.Map) row).containsKey(column);
}
if (row instanceof java.sql.ResultSet) {
try {
Object x = ((java.sql.ResultSet) row).getObject(column);
return true;
} catch (Exception e) {
return false;
}
}
return false;
}
/**
*
* @param fieldInfo
* @return
*/
public String[] getFields(String fieldInfo[]) {
ArrayList<String> aa = new ArrayList<String>();
for (String line : fieldInfo) {
Properties info = parseFormString(line);
String field = info.getProperty("field");
if (field == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
aa.add(field);
}
String[] retval = new String[aa.size()];
return (String[]) aa.toArray(retval);
}
/**
*
* @param row
* @param key
* @param value
*/
public void setField(Object row, String key, Object value) {
if (row instanceof java.util.Properties) {
if (value == null) {
((java.util.Properties) row).setProperty(key, "");
} else {
((java.util.Properties) row).setProperty(key, value.toString());
}
}
if (row instanceof java.util.Map) {
((java.util.Map) row).put(key, value);
}
if (row instanceof java.sql.ResultSet) {
// TODO: Log message
}
}
// Expect to be overridden
/**
*
*/
public String htmlSpecialChars(String str) {
return str;
}
// Expect to be overridden
/**
*
*/
public String loadI18N(String str, Object loader) {
if (loader == null)
return null;
if (loader instanceof Properties) {
return ((Properties) loader).getProperty(str, null);
}
return null;
}
// Abstract this away for testing purposes
/**
*
*/
public String getI18N(String str, Object loader) {
return getI18N(str, str, loader);
}
/**
*
* @param str
* @param def
* @param loader
* @return
*/
public String getI18N(String str, String def, Object loader) {
if (loader == null)
return def;
if (str == null)
return def;
String retval = loadI18N(str, loader);
if (retval != null)
return retval;
return def;
}
/**
*
* @param row
* @param fieldinfo
* @return
*/
public String formInput(Object row, String fieldinfo) {
return formInput(row, fieldinfo, null);
}
/**
*
* @param sb
* @param field
* @param type
* @param label
* @param required
* @param loader
*/
public void formInputStart(StringBuffer sb, String field, String type, String label,
boolean required, Object loader) {
sb.append("<p id=\"");
sb.append(field);
sb.append(".input\" class=\"foorm-"+type+"\" style=\"clear:all;\">");
if (label != null && ( ! "checkbox".equals(type) ) ) {
sb.append("<label for=\"");
sb.append(field);
sb.append("\" style=\"display:block;float:none;\">");
}
if (label != null && required ) {
sb.append("<span class=\"foorm-required\" style=\"color:#903;font-weight:bold;\" title=\"");
sb.append(getI18N(label, loader));
sb.append("\">*</span>");
}
if (label != null && ( ! "checkbox".equals(type) ) ) {
sb.append(getI18N(label, loader));
sb.append("</label>");
}
}
/**
*
* @param sb
* @param field
* @param label
* @param required
* @param loader
*/
public void formInputEnd(StringBuffer sb, String field, String label, boolean required,
Object loader) {
sb.append("</p>\n");
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param size
* @param loader
* @return
*/
public String formInputText(String value, String field, String label, boolean required,
String size, Object loader) {
if (value == null)
value = "";
StringBuffer sb = new StringBuffer();
formInputStart(sb, field, "text", label, required, loader);
sb.append("<input type=\"text\" id=\"");
sb.append(field);
sb.append("\" name=\"");
sb.append(field);
sb.append("\" size=\"");
sb.append(size);
sb.append("\" style=\"border:1px solid #555;padding:5px;font-size:1em;width:300px\" value=\"");
sb.append(htmlSpecialChars(value));
sb.append("\"/>");
formInputEnd(sb, field, label, required, loader);
return sb.toString();
}
/**
*
* @param value
* @param field
* @return
*/
public String formInputKey(Object value, String field) {
Long key = getLongNull(value);
if (key == null)
return "";
String val = key.toString();
return formInputHidden(val, field);
}
/**
*
* @param value
* @param field
* @return
*/
public String formInputHidden(String value, String field) {
if (value == null)
return "";
if ("".equals(value))
return "";
StringBuffer sb = new StringBuffer();
sb.append("<input type=\"hidden\" id=\"");
sb.append(field);
sb.append("\" name=\"");
sb.append(field);
sb.append("\" value=\"");
sb.append(htmlSpecialChars(value));
sb.append("\"/>");
return sb.toString();
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param rows
* @param cols
* @param loader
* @return
*/
public String formInputTextArea(String value, String field, String label,
boolean required, String rows, String cols, Object loader) {
if (value == null)
value = "";
StringBuffer sb = new StringBuffer();
sb.append("<p id=\"");
sb.append(field);
sb.append(".input\" class=\"longtext\" style=\"clear:all;\">");
formInputStart(sb, field, "textarea", label, required, loader);
sb.append("<textarea style=\"border:1px solid #555;width:300px\" id=\"");
sb.append(field);
sb.append("\" name=\"");
sb.append(field);
sb.append("\" rows=\"");
sb.append(rows);
sb.append("\" cols=\"");
sb.append(cols);
sb.append("\"/>");
sb.append(htmlSpecialChars(value));
sb.append("</textarea>\n");
formInputEnd(sb, field, label, required, loader);
return sb.toString();
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param choices
* @param loader
* @return
*/
public String formInputRadio(Object value, String field, String label,
boolean required, String[] choices, Object loader) {
StringBuffer sb = new StringBuffer();
// formInputStart(sb, field, "radio", label, required, loader);
sb.append("<h4>");
sb.append(getI18N(label, loader));
sb.append("</h4>\n");
int val = 0;
if (value != null && value instanceof Number)
val = ((Number) value).intValue();
if (value != null && value instanceof String) {
Integer ival = new Integer((String) value);
val = ival.intValue();
}
if (val < 0)
val = 0;
if (choices == null || val >= choices.length)
val = 0;
int i = 0;
for (String choice : choices) {
String checked = "";
if (i == val)
checked = " checked=\"checked\"";
sb.append("<p style=\"border:padding:3px;;margin:7px 3px;\">\n");
sb.append("<input type=\"radio\" name=\"");
sb.append(field);
sb.append("\" value=\"" + i + "\" id=\"");
String id = field + "_" + choice;
sb.append(id + "\"");
sb.append(checked);
sb.append("/><label for=\"");
sb.append(id);
sb.append("\">");
sb.append(getI18N(label + "_" + choice, loader));
sb.append("</label></p>\n");
i++;
}
formInputEnd(sb, field, label, required, loader);
return sb.toString();
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param loader
* @return
*/
public String formInputCheckbox(Object value, String field, String label,
boolean required, Object loader) {
StringBuffer sb = new StringBuffer();
formInputStart(sb, field, "checkbox", label, required, loader);
int val = getInt(value);
String checked = "";
if (val == 1) checked = " checked=\"checked\"";
sb.append("<input type=\"checkbox\" name=\"");
sb.append(field);
sb.append("\" value=\"1\" id=\"");
sb.append(field);
sb.append("\"");
sb.append(checked);
// onclick fires after "checked" is updated so it is the new state of checked
// http://stackoverflow.com/questions/4471401/getting-value-of-html-checkbox-from-onclick-onchange-events
if ( val == 1 ) {
sb.append("onclick=\"if(this.checked) document.getElementById('");
sb.append(field);
sb.append(".mirror').name = '");
sb.append(field);
sb.append(".ignore'; else document.getElementById('");
sb.append(field);
sb.append(".mirror').name = '");
sb.append(field);
sb.append("';\"");
}
sb.append("/>");
if ( val == 1 ) {
sb.append("<input type=\"hidden\" name=\"");
sb.append(field);
sb.append(".ignore\" id=\"");
sb.append(field);
sb.append(".mirror\" value=\"0\" />");
}
sb.append(getI18N(label, loader));
sb.append("<br/>\n");
formInputEnd(sb, field, label, required, loader);
return sb.toString();
}
/**
*
* @param field
* @param label
* @param loader
* @return
*/
public String formInputHeader(String field, String label, Object loader) {
StringBuffer sb = new StringBuffer();
sb.append("<h4>");
sb.append(getI18N(label, loader));
sb.append("</h4>\n");
return sb.toString();
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param size
* @param loader
* @return
*/
public String formInputURL(String value, String field, String label, boolean required,
String size, Object loader) {
return formInputText(value, field, label, required, size, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param size
* @param loader
* @return
*/
public String formInputId(String value, String field, String label, boolean required,
String size, Object loader) {
return formInputText(value, field, label, required, size, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param required
* @param size
* @param loader
* @return
*/
public String formInputInteger(Object value, String field, String label,
boolean required, String size, Object loader) {
if (value == null)
value = "";
if (value instanceof Integer && ((Integer) value).intValue() == 0)
value = "";
if (value instanceof Long && ((Long) value).intValue() == 0)
value = "";
if (value instanceof String)
return formInputText((String) value, field, label, required, size, loader);
return formInputText(value.toString(), field, label, required, size, loader);
}
// Produce a form for createing a new object or editing an existing object
/**
*
*/
public String formInput(Object row, String fieldinfo, Object loader) {
Properties info = parseFormString(fieldinfo);
String field = info.getProperty("field", null);
String type = info.getProperty("type", null);
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
Object value = getField(row, field);
String label = info.getProperty("label", field);
// look for tool id prefix
if (field.indexOf("_") != -1)
{
String[] array = field.split("_");
try
{
// the first array item should be an long value
Long.parseLong(array[0]);
// reset the input value
value = getField(row, array[1]);
// reset the input label
label = info.getProperty("label", array[1]);
}
catch (NumberFormatException e)
{
// do nothing
}
}
String hidden = info.getProperty("hidden", null);
if ("true".equals(hidden))
return "";
boolean required = "true".equals(info.getProperty("required", "false"));
String size = info.getProperty("size", "40");
String cols = info.getProperty("cols", "40");
String rows = info.getProperty("rows", "5");
if ("key".equals(type))
return formInputKey(value, field);
if ("integer".equals(type))
return formInputInteger(value, field, label, required, size, loader);
if ("text".equals(type))
return formInputText((String) value, field, label, required, size, loader);
if ("hidden".equals(type))
return formInputHidden((String) value, field);
if ("url".equals(type))
return formInputURL((String) value, field, label, required, size, loader);
if ("id".equals(type))
return formInputId((String) value, field, label, required, size, loader);
if ("textarea".equals(type))
return formInputTextArea((String) value, field, label, required, rows, cols, loader);
if ("autodate".equals(type))
return "";
if ("checkbox".equals(type)) {
return formInputCheckbox(value, field, label, required, loader);
}
if ("radio".equals(type)) {
String choices = info.getProperty("choices", null);
if (choices == null)
return "\n<!-- Foorm.formInput() requires choices=on,off,part -->\n";
String[] choiceList = choices.split(",");
if (choiceList.length < 1)
return "\n<!-- Foorm.formInput() requires choices=on,off,part -->\n";
// set the default value of radio button
if (value == null)
{
value= "0";
}
return formInputRadio(value, field, label, required, choiceList, loader);
}
if ("header".equals(type))
return formInputHeader(field, label, loader);
return "\n<!-- Foorm.formInput() unrecognized type " + type + " field=" + field
+ " -->\n";
}
/**
*
* @param fieldinfo
* @return
*/
public ArrayList<String> utilI18NStrings(String[] fieldinfo) {
return checkI18NStrings(fieldinfo, null);
}
/**
*
* @param fieldinfo
* @param loader
* @return
*/
public ArrayList<String> checkI18NStrings(String[] fieldinfo, Object loader) {
ArrayList<String> strings = new ArrayList<String>();
for (String line : fieldinfo) {
Properties info = parseFormString(line);
String label = info.getProperty("label", info.getProperty("field"));
String type = info.getProperty("type", null);
String hidden = info.getProperty("hidden", null);
if ("true".equals(hidden))
continue;
if ("autodate".equals(type))
continue;
String choices = info.getProperty("choices", null);
if (loadI18N(label, loader) == null)
strings.add(label);
if ("radio".equals(type) && choices != null) {
String[] choiceList = choices.split(",");
for (String choice : choiceList) {
String newkey = label + "_" + choice;
if (loadI18N(newkey, loader) == null)
strings.add(newkey);
}
}
}
return strings;
}
/**
*
* @param row
* @param formDefinition
* @return
*/
public String formInput(Object row, String[] formDefinition) {
return formInput(row, formDefinition, null);
}
/**
*
* @param row
* @param formDefinition
* @param loader
* @return
*/
public String formInput(Object row, String[] formDefinition, Object loader) {
StringBuffer sb = new StringBuffer();
String header = null;
String fieldList[] = null;
for (String formInput : formDefinition) {
String tmp = formInput(row, formInput, loader);
if (tmp.length() < 1)
continue;
Properties info = parseFormString(formInput);
String type = info.getProperty("type", null);
String field = info.getProperty("field", null);
if ( "header".equals(type) ) {
String fields = info.getProperty("fields", "");
fieldList = fields.split(",");
if (fieldList.length > 1) {
header = tmp;
continue;
}
}
if ( header != null && Arrays.asList(fieldList).contains(field) ) {
sb.append(header);
sb.append("\n");
header = null;
fieldList = null;
}
sb.append(tmp);
sb.append("\n");
}
return sb.toString();
}
/**
*
* @param row
* @param fieldinfo
* @return
*/
public String formOutput(Object row, String fieldinfo) {
return formOutput(row, fieldinfo, null);
}
/**
*
* @param sb
* @param field
* @param label
* @param loader
*/
public void formOutputStart(StringBuffer sb, String field, String label, Object loader) {
sb.append("<p class=\"row\">\n");
if (label != null) {
sb.append("<b>");
sb.append(getI18N(label, loader));
sb.append("</b><br/>");
}
}
/**
*
* @param sb
* @param field
* @param label
* @param loader
*/
public void formOutputEnd(StringBuffer sb, String field, String label, Object loader) {
sb.append("</p>\n");
}
/**
*
* @param value
* @param field
* @param label
* @param loader
* @return
*/
public String formOutputText(String value, String field, String label, Object loader) {
if (value == null)
value = "";
StringBuffer sb = new StringBuffer();
formOutputStart(sb, field, label, loader);
sb.append(htmlSpecialChars(value));
formOutputEnd(sb, field, label, loader);
return sb.toString();
}
/**
*
* @param value
* @param field
* @param label
* @param loader
* @return
*/
public String formOutputTextArea(String value, String field, String label, Object loader) {
return formOutputText(value, field, label, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param choices
* @param loader
* @return
*/
public String formOutputRadio(Long value, String field, String label, String[] choices,
Object loader) {
int val = 0;
if (value != null)
val = value.intValue();
if (val > choices.length - 1)
val = 0;
String str = getI18N(label + "_" + choices[val], loader);
return formOutputText(str, field, label, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param loader
* @return
*/
public String formOutputCheckbox(Long value, String field, String label,
Object loader) {
int val = getInt(value);
String str = getI18N(label, loader);
String off = getI18N("bl_off", "(Off)", loader);
if ( val != 1 ) str = off + " " + str;
return formOutputText(str, field, label, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param loader
* @return
*/
public String formOutputURL(String value, String field, String label, Object loader) {
return formOutputText(value, field, label, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param loader
* @return
*/
public String formOutputId(String value, String field, String label, Object loader) {
return formOutputText(value, field, label, loader);
}
/**
*
* @param value
* @param field
* @param label
* @param loader
* @return
*/
public String formOutputInteger(Long value, String field, String label, Object loader) {
String strval = "";
if (value != null)
strval = value.toString();
return formOutputText(strval, field, label, loader);
}
/**
*
* @param row
* @param fieldinfo
* @param loader
* @return
*/
public String formOutput(Object row, String fieldinfo, Object loader) {
Properties info = parseFormString(fieldinfo);
String field = info.getProperty("field", null);
String type = info.getProperty("type", null);
Object value = getField(row, field);
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
String hidden = info.getProperty("hidden", null);
if ("true".equals(hidden))
return "";
String label = info.getProperty("label", field);
if ("key".equals(type))
return ""; // Key will be handled by the caller
if ("autodate".equals(type))
return "";
if ("integer".equals(type))
return formOutputInteger(getLongNull(value), field, label, loader);
if ("text".equals(type))
return formOutputText((String) value, field, label, loader);
if ("url".equals(type))
return formOutputURL((String) value, field, label, loader);
if ("id".equals(type))
return formOutputId((String) value, field, label, loader);
if ("textarea".equals(type))
return formOutputTextArea((String) value, field, label, loader);
if ("checkbox".equals(type)) {
return formOutputCheckbox(getLongNull(value), field, label, loader);
}
if ("radio".equals(type)) {
String choices = info.getProperty("choices", null);
if (choices == null)
return "\n<!-- Foorm.formOutput() requires choices=on,off,part -->\n";
String[] choiceList = choices.split(",");
if (choiceList.length < 1)
return "\n<!-- Foorm.formOutput() requires choices=on,off,part -->\n";
return formOutputRadio(getLongNull(value), field, label, choiceList, loader);
}
return "\n<!-- Foorm.formOutput() unrecognized type " + type + " field=" + field
+ " -->\n";
}
/**
*
* @param row
* @param formDefinition
* @param loader
* @return
*/
public String formOutput(Object row, String[] formDefinition, Object loader) {
StringBuffer sb = new StringBuffer();
for (String formOutput : formDefinition) {
String tmp = formOutput(row, formOutput, loader);
if (tmp.length() < 1)
continue;
sb.append(tmp);
sb.append("\n");
}
return sb.toString();
}
/**
*
* @param parms
* @param formDefinition
* @param forInsert
* @param loader
* @return
*/
public String formValidate(Properties parms, String[] formDefinition,
boolean forInsert, Object loader, SortedMap<String,String> errors) {
return formExtract(parms, formDefinition, loader, forInsert, null, errors);
}
// dataMap should be empty
/**
* dataMap should be empty
* errors should be empty
*/
public String formExtract(Object parms, String[] formDefinition, Object loader,
boolean forInsert, Map<String, Object> dataMap, SortedMap<String,String> errors) {
StringBuffer sb = new StringBuffer();
String error = null;
for (String formInput : formDefinition) {
Properties info = parseFormString(formInput);
String field = info.getProperty("field", null);
String type = info.getProperty("type", null);
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
if ( "header".equals(type) ) continue;
String label = info.getProperty("label", field);
// System.out.println("field="+field+" type="+type);
// Check the automatically populate empty date fields
if ("autodate".equals(type) && dataMap != null && (!isFieldSet(parms, field)) ) {
java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(
new java.util.Date().getTime());
if ("updated_at".equals(field) || (forInsert && "created_at".equals(field))) {
dataMap.put(field, sqlTimestamp);
}
}
// For update, we don't worry about fields that are not set
if ((!forInsert) && (!isFieldSet(parms, field)))
continue;
Object dataField = getField(parms, field);
String sdf = null;
if (dataField instanceof String)
sdf = (String) dataField;
if (sdf != null && sdf.length() < 1) {
sdf = null;
dataField = null;
}
if ("true".equals(info.getProperty("required")) && (dataField == null)) {
if (sb.length() > 0) sb.append(", ");
error = getI18N("foorm.missing.field", "Required Field:", loader) + " " + getI18N(label, loader);
sb.append(error);
if ( errors != null ) errors.put(label, error);
}
String maxs = info.getProperty("maxlength", null);
if (maxs != null && dataField instanceof String) {
int maxlength = (new Integer(maxs)).intValue();
String truncate = info.getProperty("truncate", "true");
if (sdf.length() > maxlength) {
if ("true".equals(truncate)) {
sdf = sdf.substring(0, maxlength);
dataField = sdf;
} else {
if (sb.length() > 0)
sb.append(", ");
error = getI18N("foorm.maxlength.field", "Field >", loader) + " " + maxlength
+ " " + getI18N(label, loader);
sb.append(error);
if ( errors != null ) errors.put(label, error);
}
}
}
if ("integer".equals(type) || "radio".equals(type) || "checkbox".equals(type) ) {
if (dataField == null) {
if (dataMap != null)
dataMap.put(field, null);
} else if (dataField instanceof Number) {
if (dataMap != null)
dataMap.put(field, ((Number) dataField).intValue());
} else {
try {
Integer ival = new Integer(sdf);
if (dataMap != null)
dataMap.put(field, ival);
} catch (Exception e) {
if (sb.length() > 0)
sb.append(", ");
error = getI18N("foorm.integer.field", "Field should be an integer:", loader) + " " + getI18N(label, loader);
sb.append(error);
if ( errors != null ) errors.put(label, error);
}
}
}
if ("id".equals(type)) {
if (sdf == null) {
if (dataMap != null)
dataMap.put(field, null);
} else if (sdf.matches("^[0-9a-zA-Z._-]*$")) {
if (dataMap != null)
dataMap.put(field, sdf);
} else {
if (sb.length() > 0)
sb.append(", ");
error = getI18N("foorm.id.field", "Field has invalid characters:", loader) + " " + getI18N(label, loader);
sb.append(error);
if ( errors != null ) errors.put(label, error);
}
}
if ("url".equals(type)) {
if (sdf == null) {
if (dataMap != null)
dataMap.put(field, null);
} else if (sdf.matches("^(http://|https://)[a-zA-Z0-9][a-zA-Z0-9]*.*")) {
if (dataMap != null)
dataMap.put(field, sdf);
} else {
if (sb.length() > 0)
sb.append(", ");
error = getI18N("foorm.url.field", "Field is not a url:", loader) + " " + getI18N(label, loader);
sb.append(error);
if ( errors != null ) errors.put(label, error);
}
}
if ("text".equals(type) || "textarea".equals(type)) {
if (sdf == null) {
if (dataMap != null)
dataMap.put(field, null);
} else {
if (dataMap != null)
dataMap.put(field, sdf);
}
}
}
if (sb.length() < 1)
return null;
return sb.toString();
}
/**
*
* @param dataMap
* @return
*/
public String[] insertForm(Map<String, Object> dataMap) {
StringBuffer fields = new StringBuffer();
StringBuffer qmarks = new StringBuffer();
for (String key : dataMap.keySet()) {
if (qmarks.length() > 0) {
fields.append(", ");
qmarks.append(", ");
}
fields.append(key);
qmarks.append("?");
}
// fields.append(" ) VALUES (");
// fields.append(qmarks);
// fields.append(" ) ");
return new String[] { fields.toString(), qmarks.toString() };
}
/**
*
* @param fieldinfo
* @return
*/
public String formSelect(String[] fieldinfo) {
return formSelect(null, fieldinfo, false);
}
/**
*
* @param tableName
* @param fieldinfo
* @return
*/
public String formSelect(String tableName, String[] fieldinfo) {
return formSelect(tableName, fieldinfo, true);
}
/**
*
* @param tableName
* @param fieldinfo
* @param doAS
* @return
*/
public String formSelect(String tableName, String[] fieldinfo, boolean doAS) {
StringBuffer fields = new StringBuffer();
for (String line : fieldinfo) {
Properties info = parseFormString(line);
String field = info.getProperty("field");
String type = info.getProperty("type");
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
if ( "header".equals(type) ) continue;
if (fields.length() > 0) {
fields.append(", ");
}
if ( tableName != null ) {
fields.append(tableName);
fields.append(".");
}
fields.append(field);
if ( doAS && tableName != null ) {
fields.append(" AS ");
fields.append(field);
}
}
return fields.toString();
}
/**
*
* @param dataMap
* @return
*/
public String updateForm(Map<String, Object> dataMap) {
StringBuffer fields = new StringBuffer();
for (String key : dataMap.keySet()) {
if (!dataMap.containsKey(key))
continue;
if ("created_at".equals(key))
continue;
if (fields.length() > 0)
fields.append(", ");
fields.append(key);
fields.append("=?");
}
return fields.toString();
}
/**
*
* @param dataMap
* @return
*/
public Object[] getInsertObjects(Map<String, Object> dataMap) {
Object[] retval = new Object[dataMap.size()];
int i = 0;
for (String key : dataMap.keySet()) {
retval[i++] = dataMap.get(key);
}
return retval;
}
/**
*
* @param dataMap
* @return
*/
public Object[] getUpdateObjects(Map<String, Object> dataMap) {
int size = dataMap.size();
for (String key : dataMap.keySet()) {
if (!dataMap.containsKey(key))
size--;
if ("created_at".equals(key))
size--;
}
Object[] retval = new Object[size];
int i = 0;
for (String key : dataMap.keySet()) {
if (!dataMap.containsKey(key))
continue;
if ("created_at".equals(key))
continue;
retval[i++] = dataMap.get(key);
}
return retval;
}
// Filter a form definition based on a controlling row and/or a regex
//
// The controlling row has fields that are interpreted as
// 0=force off, 1=force on, 2 = delegate setting
// For radio buttons in our form, it simply checks for
// the field of the same name in the controlling row.
// For non-radio fields, it looks for a field in the
// controlling row prepended by 'allow'.
/**
*
*/
public String[] filterForm(Object controlRow, String[] fieldinfo) {
return filterForm(controlRow, fieldinfo, null, null);
}
/**
*
* @param fieldinfo
* @param includePattern
* @param excludePattern
* @return
*/
public String[] filterForm(String[] fieldinfo, String includePattern,
String excludePattern) {
return filterForm(null, fieldinfo, includePattern, excludePattern);
}
/**
*
* @param controlRow
* @param fieldinfo
* @param includePattern
* @param excludePattern
* @return
*/
public String[] filterForm(Object controlRow, String[] fieldinfo,
String includePattern, String excludePattern) {
if (fieldinfo == null)
return null;
ArrayList<String> ret = new ArrayList<String>();
for (String line : fieldinfo) {
if (includePattern != null && (!line.matches(includePattern)))
continue;
if (excludePattern != null && (line.matches(excludePattern)))
continue;
Properties fields = parseFormString(line);
String field = fields.getProperty("field", null);
String type = fields.getProperty("type", null);
String allowed = fields.getProperty("allowed", null);
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
// always allow autodate fields
if ("autodate".equals(type))
{
ret.add(line);
}
// always allow the SITE_ID field
else if ("SITE_ID".equals(field))
{
ret.add(line);
}
// We always assume radio and checkbox may be allowed
else if ("radio".equals(type) || "checkbox".equals(type) ) {
// Field = Always Off (0), Always On (1), or Delegate(2)
int value = getInt(getField(controlRow, field));
if ( value == 2 || ! isFieldSet(controlRow, field) ) ret.add(line);
// When there is an allow field in the control row, check it
} else if ( isFieldSet(controlRow, "allow" + field) && ! "false".equals(allowed) ) {
Object allowRow = getField(controlRow, "allow" + field);
int value = getInt(allowRow);
if ( value == 1 ) ret.add(line);
} else {
ret.add(line);
}
}
return ret.toArray(new String[ret.size()]);
}
// http://technology-ameyaaloni.blogspot.com/2010/06/mysql-to-hsql-migration-tips.html
/**
*
*/
public String formSql(String fieldinfo, String vendor) {
Properties info = parseFormString(fieldinfo);
String field = info.getProperty("field", null);
String type = info.getProperty("type", null);
if ( "header".equals(type) ) return null;
String maxs = info.getProperty("maxlength", null);
int maxlength = 0;
if (maxs != null)
maxlength = (new Integer(maxs)).intValue();
if (maxlength < 1)
maxlength = 80;
String required = info.getProperty("required", null);
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
String schema = null;
if ("key".equals(type)) {
if ("hsqldb".equals(vendor)) {
schema = "INTEGER IDENTITY PRIMARY KEY";
} else if ("oracle".equals(vendor)) {
schema = "INTEGER";
} else {
schema = "INTEGER NOT NULL AUTO_INCREMENT";
}
} else if ("autodate".equals(type)) {
if ("oracle".equals(vendor)) {
schema = "TIMESTAMP NOT NULL";
} else {
schema = "DATETIME NOT NULL";
}
} else if ("integer".equals(type)) {
if ("oracle".equals(vendor)) {
schema = "INTEGER";
} else {
schema = "INT";
}
} else if ("url".equals(type) || "text".equals(type) || "textarea".equals(type)) {
if ("oracle".equals(vendor)) {
if (maxlength < 4000) {
schema = "VARCHAR2(" + maxlength + ")";
} else {
schema = "CLOB";
}
} else if ("hsqldb".equals(vendor)) {
schema = "VARCHAR(" + maxlength + ")";
} else {
if (maxlength < 512) {
schema = "VARCHAR(" + maxlength + ")";
} else {
schema = "TEXT(" + maxlength + ")";
}
}
} else if ("radio".equals(type) || "checkbox".equals(type) ) {
if ("oracle".equals(vendor)) {
schema = "NUMBER(1) DEFAULT '0'";
} else {
schema = "TINYINT DEFAULT '0'";
}
}
if (schema == null)
return null;
// BLTI-220 - This makes migrations challenging, adding columns
// With no data - the software can still enforce required - but
// we leave it up to the insert and update code
//if ("true".equals(required) && !(schema.indexOf("NOT NULL") > 0))
//schema += " NOT NULL";
return " " + field + " " + schema;
}
public String getFormField(String [] formDefinition, String fieldName)
{
for (String formField : formDefinition) {
Properties info = parseFormString(formField);
String field = info.getProperty("field", null);
if ( fieldName.equals(field) ) return formField;
}
return null;
}
/**
*
* @param table
* @param formDefinition
* @param vendor
* @param md
* @return
*/
public String[] formAdjustTable(String table, String[] formDefinition, String vendor, ResultSetMetaData md) {
ArrayList<String> rv = new ArrayList<String>();
for (String formField : formDefinition) {
Properties info = parseFormString(formField);
String field = info.getProperty("field", null);
String type = info.getProperty("type", null);
if ( "header".equals(type) ) continue;
String maxs = info.getProperty("maxlength", null);
int maxlength = 0;
if (maxs != null) maxlength = (new Integer(maxs)).intValue();
if (maxlength < 1) maxlength = 80;
String sqlType = null;
boolean autoIncrement = false;
int sqlLength = -1;
boolean isNullable = false;
try {
for( int i = 1; i <= md.getColumnCount(); i++ ) {
// System.out.println("F="+field+" SF="+md.getColumnLabel(i));
if ( field.equalsIgnoreCase(md.getColumnLabel(i)) ) {
sqlLength = md.getColumnDisplaySize(i);
autoIncrement = md.isAutoIncrement(i);
sqlType = getSuperType(md.getColumnClassName(i));
isNullable = (md.isNullable(i) == ResultSetMetaData.columnNullable);
break;
}
}
} catch(Exception e) {
// ignore
}
// System.out.println( field + " (" + maxlength + ") type="+type);
// System.out.println( field + " (" + sqlLength + ") auto=" + autoIncrement+" type="+sqlType+" null="+isNullable);
// If the field is not there...
if ( sqlType == null ) {
if ( "oracle".equals(vendor) ) {
rv.add("ALTER TABLE "+table+" ADD ( " + formSql(formField, vendor) + " )");
} else if ( "mysql".equals(vendor) ) {
rv.add("ALTER TABLE "+table+" ADD " + formSql(formField, vendor));
} else {
rv.add("ALTER TABLE "+table+" ADD COLUMN " + formSql(formField, vendor));
}
continue;
}
String ff = formSql(formField, vendor);
// BLTI-220, BLTI-238 - Required will be enforced in software - not the DB
boolean shouldAlter = false;
if ("key".equals(type)) {
if ( ! NUMBER_TYPE.equals(sqlType) ) logger.severe(field+" must be Integer and Auto Increment");
} else if ("autodate".equals(type)) {
} else if ("url".equals(type) || "text".equals(type) || "textarea".equals(type)) {
if ( "oracle.sql.CLOB".equals(sqlType) ) continue; // CLOBS large enough :)
if ( ! STRING_TYPE.equals(sqlType)) {
logger.severe(field+" must be String field");
continue;
}
if ( sqlLength < maxlength ) shouldAlter = true;
if ( ! isNullable ) shouldAlter = true; // BLTI-220, BLTI-238
} else if ("radio".equals(type) || "checkbox".equals(type) || "integer".equals(type) ) {
if ( NUMBER_TYPE.equals(sqlType)) continue;
logger.severe(field+" must be Integer field");
}
if ( shouldAlter ) {
if ( "oracle".equals(vendor) ) {
rv.add("ALTER TABLE "+table+" MODIFY ( " + ff + " )");
} else if ( "mysql".equals(vendor) ) {
rv.add("ALTER TABLE "+table+" MODIFY " + ff);
} else {
rv.add("ALTER TABLE "+table+" ALTER COLUMN " + ff);
}
}
}
return rv.toArray(new String[rv.size()]);
}
/**
*
* @param table
* @param formDefinition
* @param vendor
* @param doReset
* @return
*/
public String[] formSqlTable(String table, String[] formDefinition, String vendor, boolean doReset) {
String theKey = formSqlKey(formDefinition);
String fieldList = formSqlFields(formDefinition, vendor);
ArrayList<String> rv = new ArrayList<String>();
if (doReset)
rv.add("DROP TABLE " + table);
if ("oracle".equals(vendor)) {
rv.add("CREATE TABLE " + table + " (\n" + formSqlFields(formDefinition, vendor)
+ "\n)\n");
if (theKey != null) {
String seqName = getSqlSequence(table, theKey, vendor);
if (seqName != null) {
if (doReset)
rv.add("DROP SEQUENCE " + seqName);
rv.add("CREATE SEQUENCE " + seqName + " INCREMENT BY 1 START WITH 1\n");
}
}
} else {
String keySpec = "";
if (theKey != null)
keySpec = ",\n PRIMARY KEY( " + theKey + " )";
rv.add("CREATE TABLE " + table + " (\n" + formSqlFields(formDefinition, vendor)
+ keySpec + "\n)\n");
}
return rv.toArray(new String[rv.size()]);
}
/**
*
* @param table
* @param theKey
* @param vendor
* @return
*/
public String getSqlSequence(String table, String theKey, String vendor) {
if (!"oracle".equals(vendor))
return null;
if (table == null || theKey == null)
return null;
return table + "_" + theKey + "_sequence";
}
// Walk the superclass tree to find a more general class to make portability easier
// Mostly this marks the various extensions of java.lang.Number as java.lang.Number
// to simplify casting
public static String getSuperType(String className)
{
try {
Class c = Class.forName(className);
while ( c != null ) {
if ( STRING_TYPE.equals(c.getName()) ) return STRING_TYPE;
if ( NUMBER_TYPE.equals(c.getName()) ) return NUMBER_TYPE;
c = c.getSuperclass();
}
} catch(Exception e) {
// System.out.println("OOPS");
e.printStackTrace();
}
return className;
}
/**
*
* @param formDefinition
* @param vendor
* @return
*/
public String formSqlFields(String[] formDefinition, String vendor) {
StringBuffer sb = new StringBuffer();
for (String formField : formDefinition) {
String retval = formSql(formField, vendor);
if (retval == null)
continue;
if (sb.length() > 0)
sb.append(",\n");
sb.append(retval);
}
return sb.toString();
}
/**
*
* @param formDefinition
* @return
*/
public String formSqlKey(String[] formDefinition) {
StringBuffer sb = new StringBuffer();
String theKey = null;
for (String formField : formDefinition) {
Properties info = parseFormString(formField);
String field = info.getProperty("field", null);
String type = info.getProperty("type", null);
if (field == null || type == null) {
throw new IllegalArgumentException(
"All model elements must include field name and type");
}
if (!"key".equals(type))
continue;
if (theKey != null) {
throw new IllegalArgumentException("Models can only have one key column.");
}
theKey = field;
}
return theKey;
}
// Paging helpers
// startRec is zero-based
/**
*
*/
public String getPagedSelect(String sqlIn, int startRec, int endRec, String vendor) {
if ("hsqldb".equals(vendor)) {
if (startRec > endRec)
return null;
sqlIn = sqlIn.trim();
int position = sqlIn.toLowerCase().indexOf("select ");
if (position != 0)
return null;
int recordCount = (endRec - startRec) + 1;
String retval = "select limit " + startRec + " " + recordCount + " "
+ sqlIn.substring(position + 7);
return retval;
} else if ("oracle".equals(vendor)) {
if (startRec > endRec)
return null;
String retval = "select * from ( select a.*, ROWNUM foorm_rnum from ( " + sqlIn
+ " ) a where ROWNUM <= " + (endRec + 1) + " ) where foorm_rnum >= " + (startRec + 1);
return retval;
} else { // MySql for sure
if (startRec > endRec)
return null;
int recordCount = (endRec - startRec) + 1;
return sqlIn + " limit " + startRec + "," + recordCount;
}
}
}