001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 002// The Molly framework is freely distributable under the terms of an 003// MIT-style license. For details, see the molly pages web site at: 004// http://www.mollypages.org/. Use, modify, have fun ! 005 006package fc.web.forms; 007 008import javax.servlet.*; 009import javax.servlet.http.*; 010import java.io.*; 011import java.util.*; 012 013import fc.jdbc.*; 014import fc.io.*; 015import fc.util.*; 016 017/** 018Represents an HTML hidden field. If this object is created with an array of 019string values, then each string value will be written out as a seperate 020hidden field and all such written hidden fields will have the same name. 021When the form is submitted, all values can be retrieved as an array of 022strings. 023 024@author hursh jain 025**/ 026public final class Hidden extends Field 027{ 028static String[] empty_arr = new String[] { "" }; 029 030final static class Data { 031 String[] values; 032 } 033 034String[] orig_values; 035boolean dynamicallyAdded = false; 036 037/** 038Creates a new text element with the initial value set to an empty string. 039This is useful in cases where we are interested in the presense/absense of 040the name of the hidden field and don't care about a seperate value. 041**/ 042public Hidden(String name) 043 { 044 this(name, ""); 045 } 046 047/** 048Creates a new hidden element with the specified initial value. 049If the initial value is specified as <tt>null</tt>, it is set to be 050an empty string. 051**/ 052public Hidden(String name, String value) 053 { 054 super(name); 055 if (value == null) 056 value = ""; 057 058 orig_values = new String[] { value }; 059 } 060 061/** 062Convenience constructor to creates a new hidden element with the 063specified initial integer value (converted to a string). 064**/ 065public Hidden(String name, int value) 066 { 067 super(name); 068 orig_values = new String[] { String.valueOf(value) }; 069 } 070 071/** 072Creates a new hidden element with the specified initial values. 073**/ 074public Hidden(String name, String[] values) 075 { 076 super(name); 077 if (values == null) { 078 log.warn("Specified values were null, defaulting to \"\""); 079 orig_values = empty_arr; 080 } 081 else 082 orig_values = values; 083 } 084 085/** 086Creates a new hidden element with the specified initial values. Each 087element in the List will be added by invoking <tt>toString</tt> on it. 088**/ 089public Hidden(String name, final List values) 090 { 091 super(name); 092 if (values == null) { 093 log.warn("Specified values were null, defaulting to \"\""); 094 orig_values = empty_arr; 095 } 096 else{ 097 //was: orig_values = (String[]) values.toArray(new String[0]); 098 //this is more foolproof: 099 final int size = values.size(); 100 orig_values = new String[size]; 101 for (int n = 0; n < size; n++) { 102 orig_values[n] = values.get(n).toString(); 103 } 104 } 105 } 106 107public Field.Type getType() { 108 return Field.Type.HIDDEN; 109 } 110 111public void renderImpl(FormData fd, Writer writer) throws IOException 112 { 113 /* 114 We maintain the submit state even for hidden fields because it is 115 possible that some javascript on the client side might modify the 116 contents of a hidden field. 117 */ 118 String[] values = getRenderValues(fd); 119 120 for (int n = 0; n < values.length; n++) 121 { 122 writer.write("<input type='"); 123 writer.write(getType().toString()); 124 writer.write("' name='"); 125 writer.write(name); 126 writer.write("'"); 127 128 if (values != null) { 129 writer.write(" value='"); 130 writer.write(values[n]); 131 writer.write("'"); 132 } 133 134 final int arlen = arbitraryString.size(); 135 for (int k = 0; k < arlen; k++) { 136 writer.write(" "); 137 writer.write(arbitraryString.get(k).toString()); 138 } 139 140 writer.write("></input>\n"); 141 } 142 } 143 144/** 145Returns a String representing the value of this field or <tt>null</tt> 146if there is no current value. If more than one value exists for this 147hidden field, use the {@link getValues} method. If called when more 148than one value exists, this method will return any 1 arbitrary value. 149*/ 150public String getValue(FormData fd) 151 { 152 if (dynamicallyAdded) { 153 return orig_values[0]; 154 } 155 156 Data data = (Data) fd.getData(name); 157 158 if (data == null) 159 return null; 160 161 return data.values[0]; 162 } 163 164/** 165Returns a String[] containing all values associated with this field. 166*/ 167public String[] getValues(FormData fd) 168 { 169 if (dynamicallyAdded) 170 return orig_values; 171 172 Data data = (Data) fd.getData(name); 173 174 if (data == null) 175 return null; 176 177 return data.values; 178 } 179 180 181/** 182Convenience method that returns one value of this field as a String with 183null values being returned as an empty string). <b>If more than one value 184exists, use the {@link #getValues} method instead.</b> 185 186@throws NumberFormatException if the value could not be 187 returned as in integer. 188*/ 189public String getStringValue(FormData fd) 190 { 191 String s = getValue(fd); 192 if (s == null) 193 s = ""; 194 return s; 195 } 196 197/** 198Convenience method that returns one value of this field as a Integer. <b>If 199more than one value exists, use the {@link #getValues} method instead.</b> 200 201@throws NumberFormatException if the value could not be 202 returned as an integer. 203*/ 204public int getIntValue(FormData fd) { 205 String value = getValue(fd); 206 if (value != null) 207 value = value.trim(); 208 return Integer.parseInt(value); 209 } 210 211/** 212Convenience method that returns one value of this field as a Short. <b>If 213more than one value exists, use the {@link #getValues} method instead.</b> 214 215@throws NumberFormatException if the value could not be 216 returned as a short. 217*/ 218public short getShortValue(FormData fd) { 219 String value = getValue(fd); 220 if (value != null) 221 value = value.trim(); 222 return Short.parseShort(value); 223 } 224 225/** 226Convenience method that returns one value of this field as a boolean. The 227value is converted into a boolean as per the {@link 228Boolean.valueOf(String)} method. <b>If more than one value exists, use the 229{@link #getValues} method instead.</b> 230*/ 231public boolean getBooleanValue(FormData fd) { 232 return Boolean.valueOf(getValue(fd)).booleanValue(); 233 } 234 235/** 236The values to render this field with. If the form has not been shown to the 237user at all or if the specified fd object is null, returns the original 238values. Also if this field was dynamically added to the formdata, the 239original values will be returned (since there will never be any submitted 240values). 241*/ 242String[] getRenderValues(FormData fd) 243 { 244 if (dynamicallyAdded) 245 return orig_values; 246 247 if (fd != null) { 248 Data data = (Data) fd.getData(name); 249 if (data == null) 250 return empty_arr; 251 else 252 return data.values; 253 } 254 else { //fd == null, no form data, showing form for first time 255 return orig_values; 256 } 257 } 258 259public void setValueFromSubmit(FormData fd, HttpServletRequest req) 260throws SubmitHackedException 261 { 262 String[] values = req.getParameterValues(name); 263 264 if (values == null) 265 { //client was buggy or hacked [or field = disabled] 266 if (! enabled || ! isEnabled(fd)) { 267 hacklert(req, "Bug/hack alert: did not find ["+name+"] field in the request (but expected to), defaulting to original values"); 268 } 269 values = empty_arr; 270 } 271 272 Data data = new Data(); 273 fd.putData(name, data); 274 data.values = values; 275 } 276 277/** 278Sets the <b>initial</b> values of this text element. 279**/ 280public void setValue(String[] values) 281 { 282 if (values == null) { 283 log.warn("specified values param was null, defaulting to \"\""); 284 values = empty_arr; 285 } 286 287 this.orig_values = values; 288 } 289 290/** 291Sets the <b>initial</b> values of this text element. 292**/ 293public void setValue(String value) 294 { 295 if (value == null) { 296 log.warn("specified values param was null, defaulting to \"\""); 297 value = ""; 298 } 299 300 this.orig_values = new String[] { value }; 301 } 302 303public boolean isFilled(FormData fd) 304 { 305 Data data = (Data) fd.getData(name); 306 307 if (data == null) 308 return false; 309 310 String[] values = data.values; 311 312 if (values == null) { 313 log.error("Internal error: unexpected state"); 314 } 315 316 //since it's always at least some string -- possibly 317 //all spaces but it'll be non-null 318 return true; 319 } 320 321public void reset(FormData fd) { 322 Data data = (Data) fd.getData(name); 323 data.values = orig_values; 324 } 325 326public String toString() 327 { 328 return super.toString() + "; Orig. value: [" + Arrays.toString(orig_values) + "]"; 329 } 330 331} //~class Hidden