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