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 006 package fc.web.forms; 007 008 import javax.servlet.*; 009 import javax.servlet.http.*; 010 import java.io.*; 011 import java.util.*; 012 013 import fc.jdbc.*; 014 import fc.io.*; 015 import fc.util.*; 016 017 /** 018 Represents an HTML hidden field. If this object is created with an array of 019 string values, then each string value will be written out as a seperate 020 hidden field and all such written hidden fields will have the same name. 021 When the form is submitted, all values can be retrieved as an array of 022 strings. 023 024 @author hursh jain 025 **/ 026 public final class Hidden extends Field 027 { 028 static String[] empty_arr = new String[] { "" }; 029 030 final static class Data { 031 String[] values; 032 } 033 034 String[] orig_values; 035 boolean dynamicallyAdded = false; 036 037 /** 038 Creates a new text element with the initial value set to an empty string. 039 This is useful in cases where we are interested in the presense/absense of 040 the name of the hidden field and don't care about a seperate value. 041 **/ 042 public Hidden(String name) 043 { 044 this(name, ""); 045 } 046 047 /** 048 Creates a new hidden element with the specified initial value. 049 If the initial value is specified as <tt>null</tt>, it is set to be 050 an empty string. 051 **/ 052 public 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 /** 062 Convenience constructor to creates a new hidden element with the 063 specified initial integer value (converted to a string). 064 **/ 065 public Hidden(String name, int value) 066 { 067 super(name); 068 orig_values = new String[] { String.valueOf(value) }; 069 } 070 071 /** 072 Creates a new hidden element with the specified initial values. 073 **/ 074 public 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 /** 086 Creates a new hidden element with the specified initial values. Each 087 element in the List will be added by invoking <tt>toString</tt> on it. 088 **/ 089 public 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 107 public Field.Type getType() { 108 return Field.Type.HIDDEN; 109 } 110 111 public 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 /** 145 Returns a String representing the value of this field or <tt>null</tt> 146 if there is no current value. If more than one value exists for this 147 hidden field, use the {@link getValues} method. If called when more 148 than one value exists, this method will return any 1 arbitrary value. 149 */ 150 public 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 /** 165 Returns a String[] containing all values associated with this field. 166 */ 167 public 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 /** 182 Convenience method that returns one value of this field as a String with 183 null values being returned as an empty string). <b>If more than one value 184 exists, use the {@link #getValues} method instead.</b> 185 186 @throws NumberFormatException if the value could not be 187 returned as in integer. 188 */ 189 public String getStringValue(FormData fd) 190 { 191 String s = getValue(fd); 192 if (s == null) 193 s = ""; 194 return s; 195 } 196 197 /** 198 Convenience method that returns one value of this field as a Integer. <b>If 199 more 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 */ 204 public 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 /** 212 Convenience method that returns one value of this field as a Short. <b>If 213 more 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 */ 218 public 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 /** 226 Convenience method that returns one value of this field as a boolean. The 227 value is converted into a boolean as per the {@link 228 Boolean.valueOf(String)} method. <b>If more than one value exists, use the 229 {@link #getValues} method instead.</b> 230 */ 231 public boolean getBooleanValue(FormData fd) { 232 return Boolean.valueOf(getValue(fd)).booleanValue(); 233 } 234 235 /** 236 The values to render this field with. If the form has not been shown to the 237 user at all or if the specified fd object is null, returns the original 238 values. Also if this field was dynamically added to the formdata, the 239 original values will be returned (since there will never be any submitted 240 values). 241 */ 242 String[] 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 259 public void setValueFromSubmit(FormData fd, HttpServletRequest req) 260 throws 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 /** 278 Sets the <b>initial</b> values of this text element. 279 **/ 280 public 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 /** 291 Sets the <b>initial</b> values of this text element. 292 **/ 293 public 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 303 public 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 321 public void reset(FormData fd) { 322 Data data = (Data) fd.getData(name); 323 data.values = orig_values; 324 } 325 326 public String toString() 327 { 328 return super.toString() + "; Orig. value: [" + Arrays.toString(orig_values) + "]"; 329 } 330 331 } //~class Hidden