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 /** 019 Represents a field that: 020 <ol> 021 <li>returns one (1) string as their value. Contrast this with 022 selects/with/multiple and radiogroups that may return 023 a String[]. 024 <li> 025 In addition, the <i>name</i> of this field is always 026 returned on a form submit by the browser (barring browser 027 hacks etc). For example, if a text field is not filled out 028 by the user, the browser still returns that text field (with 029 no value). Contrast this with radio buttons that are not 030 returned at all (not even their name) if the user does not 031 select them. 032 </ol> 033 <p>Important note: the {@link trimValues(boolean)} method 034 will by default trim whitespace from the beginning/end of 035 user input. If the resulting string is empty (""), then 036 it will be treated as if the user had not entered anything. 037 (which is typically the desired behavior). 038 039 @author hursh jain 040 **/ 041 public abstract class AbstractText extends Field 042 { 043 static class Data { 044 String value; 045 } 046 047 String orig_value; 048 boolean trimValues = true; 049 050 AbstractText (String name) { 051 super(name); 052 } 053 054 AbstractText (String name, String value) 055 { 056 super(name); 057 if (value == null) 058 { 059 log.warn("specified value was null, defaulting to \"\""); 060 value = ""; 061 } 062 orig_value = value; 063 } 064 065 /** 066 Sets the value of the field from the submitted form data. 067 068 <b>Note, by default, it is assumed that all abstract text fields have 069 different names in the html form</b>. Mulitple fields with the same name 070 are not supported. <u>If there is more than one field with the same name 071 (such as multiple text fields with the same name), then only 1 value will 072 be saved (and the rest will be ignored)</u> [This is one of - or perhaps 073 the only - restriction of this form API; without it, things become too 074 complex to manage]. 075 */ 076 public void setValueFromSubmit(FormData fd, HttpServletRequest req) 077 throws SubmitHackedException 078 { 079 String value = req.getParameter(name); 080 081 //can be null if not sent by client for some reason 082 //will be "" is not isFilled by the client since the servlet 083 //api, for the request params 'foo=&bar=, getParam("foo") 084 //returns an empty string (not null). 085 // 086 if (value == null) { 087 //Browsers return no value for disabled fields !! 088 if (! enabled || ! isEnabled(fd)) 089 return; 090 //client was buggy or hacked 091 hacklert(req, "Did not find ["+name+"] field in the request (but expected to), defaulting to \"\""); 092 return; 093 } 094 095 if (trimValues) { 096 value = value.trim(); 097 } 098 099 //servlet api returns an empty string for param 'foo=' [not null] 100 //we treat that as a null value, we also treat white space 101 //as null if trimming is on. 102 if (value.equals("")) 103 return; 104 105 //we have a non-null value 106 AbstractText.Data data = new AbstractText.Data(); 107 fd.putData(name, data); 108 data.value = value; 109 } 110 111 /** 112 Sets the <b>initial</b> value of this text element to the specified string. 113 If the specified value is <tt>null</tt>, then the initial value is set to 114 "" (the empty string). 115 **/ 116 public void setValue(String value) 117 { 118 if (value == null) { 119 log.warn("specified value was null, defaulting to \"\""); 120 value = ""; 121 } 122 this.orig_value = value; 123 } 124 125 /** 126 Sets the selected values for this select in the specified form data. This 127 is useful for showing different <i>initial</i> values to each user (before 128 the form has been submitted by that user). 129 <p> 130 If the form has not been submitted, there is no form data object. A form 131 data object should be manually created if needed for storing the value. 132 133 @param fd the non-null form data used for rendering the form 134 @param value the value to be set 135 */ 136 public void setValue(FormData fd, String value) 137 { 138 Argcheck.notnull(fd, "specified fd param was null"); 139 140 if (value == null) { 141 log.warn("specified value was null, defaulting to \"\""); 142 value = ""; 143 } 144 AbstractText.Data data = new AbstractText.Data(); 145 146 fd.putData(name, data); 147 data.value = value; 148 } 149 150 151 /** 152 Returns a string representing the value of this field or <tt>null</tt> if 153 there is no current value. The <i>names</i> of Form fields like 154 <tt>text</tt> and <tt>textarea</tt> are always sent back by the browser 155 if the field is enabled. However if the <i>values</i> are empty, then 156 this method will return <tt>null</tt>. For example, if the browser 157 returned <xmp>foo=&bar=baz</xmp>, then <tt>foo</tt> will have a 158 <tt>null</tt> value (even though the <i>servlet api</i> returns an empty 159 string). 160 */ 161 public String getValue(FormData fd) 162 { 163 AbstractText.Data data = (AbstractText.Data) fd.getData(name); 164 165 if (data == null) 166 return null; 167 168 return data.value; 169 } 170 171 172 /** 173 Convenience method that returns the value of this field as a String. 174 <tt>null</tt> values (ie which can happen when the field is disabled and 175 no value sent by the browser) <i>are returned as an empty string.</i> 176 177 @throws NumberFormatException if the value could not be 178 returned as in integer. 179 */ 180 public String getStringValue(FormData fd) 181 { 182 String s = getValue(fd); 183 if (s == null) 184 s = ""; 185 return s; 186 } 187 188 /** 189 Convenience method that returns the value of this 190 field as a Integer. 191 192 @throws NumberFormatException if the value could not be 193 returned as an integer. 194 */ 195 public int getIntValue(FormData fd) { 196 String value = getValue(fd); 197 if (value != null) 198 value = value.trim(); 199 return Integer.parseInt(value); 200 } 201 202 /** 203 Convenience method that returns the value of this field as a 204 Short. 205 206 @throws NumberFormatException if the value could not be 207 returned as a short. 208 */ 209 public short getShortValue(FormData fd) { 210 String value = getValue(fd); 211 if (value != null) 212 value = value.trim(); 213 return Short.parseShort(value); 214 } 215 216 /** 217 Convenience method that returns the value of this field as a 218 Float. 219 220 @throws NumberFormatException if the value could not be 221 returned as a float. 222 */ 223 public float getFloatValue(FormData fd) { 224 String value = getValue(fd); 225 if (value != null) 226 value = value.trim(); 227 return Float.parseFloat(value); 228 } 229 230 231 /** 232 Convenience method that returns the value of this field as a 233 Double. 234 235 @throws NumberFormatException if the value could not be 236 returned as a double. 237 */ 238 public double getDoubleValue(FormData fd) { 239 String value = getValue(fd); 240 if (value != null) 241 value = value.trim(); 242 return Double.parseDouble(value); 243 } 244 245 /** 246 Convenience method that returns the value of this field as a boolean. The 247 value is converted into a boolean as per the {@link 248 Boolean.valueOf(String)} method. 249 */ 250 public boolean getBooleanValue(FormData fd) { 251 return Boolean.valueOf(getValue(fd)).booleanValue(); 252 } 253 254 /** 255 The value to render this field with. Maintains state and returns 256 whatever the user typed in last if applicable. If the form has 257 not been shown to the user or if this field is disabled at all, returns 258 the original value. 259 */ 260 String getRenderValue(FormData fd) 261 { 262 if (! enabled) { 263 return orig_value; 264 } 265 266 if (fd != null) 267 { 268 AbstractText.Data data = (AbstractText.Data) fd.getData(name); 269 if (data == null) 270 return ""; 271 else 272 return data.value; 273 } 274 else { //fd == null, no form data, showing form for first time 275 return orig_value; 276 } 277 } 278 279 public boolean isFilled(FormData fd) 280 { 281 AbstractText.Data data = (AbstractText.Data) fd.getData(name); 282 283 //data is created only if the submitted value was not null. If 284 //data is not null, then there was a sumbitted value. 285 if (data == null) 286 return false; 287 288 String value = data.value; 289 290 if (value == null) { 291 log.error("Internal error: unexpected state"); 292 } 293 294 //since it's always at least some string -- possibly 295 //all spaces but it'll be non-null 296 return true; 297 } 298 299 public void reset(FormData fd) { 300 AbstractText.Data data = (AbstractText.Data) fd.getData(name); 301 if (data != null) 302 data.value = orig_value; 303 } 304 305 /** 306 Trims leading and ending spaces from all entered values. 307 This is <tt>true</tt> by default. Specify <tt>false</tt> to 308 turn this off. 309 */ 310 public void trimValues(boolean val) 311 { 312 trimValues = val; 313 } 314 315 public String toString() 316 { 317 return super.toString() + "; Orig. value: [" + orig_value + "]"; 318 } 319 320 }