1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dbforms.taglib;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import org.dbforms.config.Constants;
30 import org.dbforms.config.DbFormsConfigRegistry;
31 import org.dbforms.config.Field;
32 import org.dbforms.config.FieldValue;
33 import org.dbforms.config.FieldValues;
34 import org.dbforms.config.Table;
35 import org.dbforms.interfaces.IDataContainer;
36 import org.dbforms.interfaces.StaticData;
37
38 import org.dbforms.util.MessageResources;
39 import org.dbforms.util.ParseUtil;
40 import org.dbforms.util.StringUtil;
41 import org.dbforms.util.Util;
42
43 import java.text.SimpleDateFormat;
44
45 import java.util.List;
46
47 import javax.servlet.http.HttpServletRequest;
48 import javax.servlet.jsp.JspException;
49 import javax.servlet.jsp.PageContext;
50
51
52
53 /***
54 * Map a placeholder (?) in sql code to an input tag. Used as nested tag inside
55 * filterCondition. Implements DataContainer interface to use the nested tags
56 * queryData, staticData ...
57 *
58 * @author Sergio Moretti
59 * @version $Revision: 1.39 $
60 */
61 public class DbFilterValueTag extends AbstractDbBaseHandlerTag implements IDataContainer,
62 javax.servlet.jsp.tagext.TryCatchFinally {
63 /*** DOCUMENT ME! */
64 private static String FLT_VALUETYPE_DATE = "date";
65
66 /*** DOCUMENT ME! */
67 private static String FLT_VALUETYPE_NUMERIC = "numeric";
68
69 /*** DOCUMENT ME! */
70 private static String FLT_VALUETYPE_SELECT = "select";
71
72 /*** DOCUMENT ME! */
73 private static String FLT_VALUETYPE_TEXT = "text";
74
75 /*** DOCUMENT ME! */
76 private static String FLT_VALUETYPE_TIMESTAMP = "timestamp";
77 private static Log logCat = LogFactory.getLog(DbFilterValueTag.class
78 .getName());
79
80 /*** contain the state of this tag object */
81 private transient State state;
82
83 /***
84 *
85 */
86 public DbFilterValueTag() {
87 super();
88 state = new State();
89 }
90
91 /***
92 * Allows an additional (independant) entry into the select list
93 *
94 * @param string
95 */
96 public void setCustomEntry(String string) {
97 state.customEntry = string;
98 }
99
100
101 /***
102 * This method is a "hookup" for EmbeddedData - Tags which can assign the
103 * lines of data they loaded (by querying a database, or by rendering
104 * data-subelements, etc. etc.) and make the data available to this tag.
105 * [this method is defined in Interface DataContainer]
106 *
107 * @param embeddedData DOCUMENT ME!
108 */
109 public void setEmbeddedData(List embeddedData) {
110 state.embeddedData = embeddedData;
111 }
112
113
114 /***
115 * property jsCalendarDateFormat.
116 *
117 * @param string
118 */
119 public void setJsCalendarDateFormat(String string) {
120 state.jsCalendarDateFormat = string;
121 }
122
123
124 /***
125 * DOCUMENT ME!
126 *
127 * @return
128 */
129 public String getJsCalendarDateFormat() {
130 return state.jsCalendarDateFormat;
131 }
132
133
134 /***
135 * property label showed before input tag
136 *
137 * @param string
138 */
139 public void setLabel(String string) {
140 state.label = string;
141 }
142
143
144 /***
145 * DOCUMENT ME!
146 *
147 * @return
148 */
149 public String getLabel() {
150 return state.label;
151 }
152
153
154 /***
155 * DOCUMENT ME!
156 *
157 * @param value DOCUMENT ME!
158 */
159 public void setSearchAlgo(String value) {
160 state.searchAlgo = value;
161 }
162
163
164 /***
165 * DOCUMENT ME!
166 *
167 * @return DOCUMENT ME!
168 */
169 public String getSearchAlgo() {
170 return state.searchAlgo;
171 }
172
173
174 /***
175 * property currently selected index, valid only when type = select
176 *
177 * @param string
178 */
179 public void setSelectedIndex(String string) {
180 state.selectedIndex = string;
181 }
182
183
184 /***
185 * property html input's attribute size
186 *
187 * @param string
188 */
189 public void setSize(String string) {
190 state.size = string;
191 }
192
193
194 /***
195 * DOCUMENT ME!
196 *
197 * @param pg DOCUMENT ME!
198 * @param parent DOCUMENT ME!
199 * @param state
200 */
201 public void setState(PageContext pg,
202 DbFilterConditionTag parent,
203 State state) {
204 setPageContext(pg);
205 setParent(parent);
206 this.state = state;
207 }
208
209
210 /***
211 * css class to be applied to input element
212 *
213 * @param string
214 */
215 public void setStyleClass(String string) {
216 state.styleClass = string;
217 }
218
219
220 /***
221 * type of the input element that will be rendered, possible values are:
222 *
223 * <dl>
224 * <dt>
225 * text
226 * </dt>
227 * <dd>
228 * text input
229 * </dd>
230 * <dt>
231 * date
232 * </dt>
233 * <dd>
234 * input text for date type, a validation of the value will be done, and it
235 * supports the jscal object
236 * </dd>
237 * <dt>
238 * timestamp
239 * </dt>
240 * <dd>
241 * input text for timestamp type, a validation of the value will be done,
242 * and it supports the jscal object (it doesn't fit very well, anyway ...)
243 * </dd>
244 * <dt>
245 * numeric
246 * </dt>
247 * <dd>
248 * input text for number, a validation of the value will be done
249 * </dd>
250 * <dt>
251 * select
252 * </dt>
253 * <dd>
254 * render an html select element, filled with nested tags like queryData,
255 * staticData and so on.
256 * </dd>
257 * </dl>
258 *
259 *
260 * @param string
261 */
262 public void setType(String string) {
263 state.type = string;
264 }
265
266
267 /***
268 * DOCUMENT ME!
269 *
270 * @param string
271 */
272 public void setUseJsCalendar(String string) {
273 state.useJsCalendar = string;
274 }
275
276
277 /***
278 * DOCUMENT ME!
279 *
280 * @return
281 */
282 public String getUseJsCalendar() {
283 return state.useJsCalendar;
284 }
285
286
287 /***
288 * reset tag state
289 *
290 * @see javax.servlet.jsp.tagext.TryCatchFinally#doFinally()
291 */
292 public void doFinally() {
293 state = new State();
294 super.doFinally();
295 }
296
297
298 /***
299 * initialize environment
300 *
301 * @see javax.servlet.jsp.tagext.Tag#doStartTag()
302 */
303 public int doStartTag() throws JspException {
304 init();
305
306 return EVAL_BODY_BUFFERED;
307 }
308
309
310 /***
311 * read from request all values associated to the condition identified with
312 * <tableId>, <conditionId>. It try to read the value with
313 * identifier 0, if succeded go on with identifier 1, and so on.
314 *
315 * @param request
316 * @param tableId identify filter in request's parameters
317 * @param conditionId identify condition in request's parameter
318 *
319 * @return list of all values readed from request
320 */
321 protected static FieldValue[] readValuesFromRequest(HttpServletRequest request,
322 int tableId,
323 int conditionId) {
324 FieldValues values = new FieldValues();
325
326 for (int valueId = 0; true; ++valueId) {
327
328
329 String paramValue = DbFilterConditionTag.getConditionName(tableId,
330 conditionId)
331 + DbFilterTag.FLT_VALUE + valueId;
332 String paramType = DbFilterConditionTag.getConditionName(tableId,
333 conditionId)
334 + DbFilterTag.FLT_VALUETYPE + valueId;
335 String searchAlgoType = DbFilterConditionTag.getConditionName(tableId,
336 conditionId)
337 + DbFilterTag.FLT_SEARCHALGO + valueId;
338
339 String value = ParseUtil.getParameter(request, paramValue);
340 String valueType = ParseUtil.getParameter(request, paramType);
341
342 String aSearchAlgorithm = ParseUtil.getParameter(request,
343 searchAlgoType);
344 int algorithm = Constants.SEARCH_ALGO_SHARP;
345
346 if (!Util.isNull(aSearchAlgorithm)) {
347 if (aSearchAlgorithm.startsWith("weakStartEnd")) {
348 algorithm = Constants.SEARCH_ALGO_WEAK_START_END;
349 } else if (aSearchAlgorithm.startsWith("weakStart")) {
350 algorithm = Constants.SEARCH_ALGO_WEAK_START;
351 } else if (aSearchAlgorithm.startsWith("weakEnd")) {
352 algorithm = Constants.SEARCH_ALGO_WEAK_END;
353 } else if (aSearchAlgorithm.startsWith("weak")) {
354 algorithm = Constants.SEARCH_ALGO_WEAK;
355 }
356 }
357
358 valueType = Util.isNull(valueType) ? FLT_VALUETYPE_TEXT
359 : valueType;
360
361 if (value != null) {
362
363 Field f = new Field();
364 f.setName(paramValue);
365 f.setId(valueId);
366 f.setFieldType(valueType);
367
368 Table table = null;
369
370 try {
371 table = DbFormsConfigRegistry.instance()
372 .lookup()
373 .getTable(tableId);
374 } catch (Exception e) {
375 logCat.error("readValuesFromRequest", e);
376 }
377
378 f.setTable(table);
379
380 FieldValue fv = new FieldValue(f, value);
381 fv.setLocale(MessageResources.getLocale(request));
382 fv.setSearchAlgorithm(algorithm);
383 values.put(fv);
384 } else {
385
386 break;
387 }
388 }
389
390 return values.toArray();
391 }
392
393
394 /***
395 * DOCUMENT ME!
396 *
397 * @return DOCUMENT ME!
398 */
399 protected Object getFieldObject() {
400 FieldValue fv = new FieldValue(getField(), state.value);
401 fv.setLocale(MessageResources.getLocale((HttpServletRequest) pageContext
402 .getRequest()));
403
404 return fv.getFieldValueAsObject();
405 }
406
407
408 /***
409 * DOCUMENT ME!
410 *
411 * @return
412 */
413 protected State getState() {
414 return state;
415 }
416
417
418 /***
419 * render output of this value object. This is called only if its parent's
420 * condition is selected
421 *
422 * @return
423 *
424 * @throws JspException
425 */
426 protected StringBuffer render() throws JspException {
427 StringBuffer buf = new StringBuffer();
428
429 Field f = new Field();
430 f.setName(state.label);
431 f.setId(state.valueId);
432 f.setFieldType(state.type);
433 f.setTable(getParentForm().getTable());
434 setField(f);
435
436 if (state.label != null) {
437 if (getParentForm().hasCaptionResourceSet()) {
438 try {
439 String message = MessageResources.getMessage((HttpServletRequest)pageContext.getRequest(), state.label);
440 if (message != null) {
441 state.label = message;
442 }
443 } catch (Exception e) {
444 logCat.debug("setCaption(" + state.label + ") Exception : "
445 + e.getMessage());
446 }
447 }
448 buf.append("<b>" + state.label + "</b>\n");
449 }
450
451 if (state.type.equalsIgnoreCase(FLT_VALUETYPE_TEXT)
452 || state.type.equalsIgnoreCase(FLT_VALUETYPE_NUMERIC)) {
453 renderTextElement(buf);
454 } else if (state.type.equalsIgnoreCase(FLT_VALUETYPE_DATE)
455 || state.type.equalsIgnoreCase(FLT_VALUETYPE_TIMESTAMP)) {
456 renderDateElement(buf);
457 } else if (FLT_VALUETYPE_SELECT.equalsIgnoreCase(state.type)
458 && (state.embeddedData != null)) {
459 renderSelectElement(buf);
460 } else {
461 throw new JspException("type not correct");
462 }
463
464 return buf;
465 }
466
467
468 private String getSearchAlgoType() {
469 return ((DbFilterConditionTag) getParent()).getConditionName()
470 + DbFilterTag.FLT_SEARCHALGO + state.valueId;
471 }
472
473
474 private String getValueName() {
475 return ((DbFilterConditionTag) getParent()).getConditionName()
476 + DbFilterTag.FLT_VALUE + state.valueId;
477 }
478
479
480 private String getValueType() {
481 return ((DbFilterConditionTag) getParent()).getConditionName()
482 + DbFilterTag.FLT_VALUETYPE + state.valueId;
483 }
484
485
486 /***
487 * generate option element for select. borrowed from
488 *
489 * @param value
490 * @param description
491 * @param selected
492 *
493 * @return string containing an html option element
494 *
495 * @see DbSearchComboTag#generateTagString
496 */
497 private String generateTagString(String value,
498 String description,
499 boolean selected) {
500 StringBuffer tagBuf = new StringBuffer();
501 tagBuf.append("<option value=\"");
502 tagBuf.append(value);
503 tagBuf.append("\"");
504
505 if (selected) {
506 tagBuf.append(" selected=\"selected\"");
507 }
508
509 tagBuf.append(">");
510 tagBuf.append(description.trim());
511 tagBuf.append("</option>");
512
513 return tagBuf.toString();
514 }
515
516
517 /***
518 * initialize tag's state before start using it
519 */
520 private void init() {
521
522
523 if (state.type == null) {
524 state.type = "text";
525 }
526
527 if (state.styleClass == null) {
528 state.styleClass = "";
529 }
530
531 state.valueId = ((DbFilterConditionTag) getParent()).addValue(this);
532 state.value = ParseUtil.getParameter((HttpServletRequest) pageContext
533 .getRequest(), getValueName());
534
535 if (state.value == null) {
536 state.value = "";
537 }
538
539
540
541 state.embeddedData = null;
542 }
543
544
545 /***
546 * render input's type "date"
547 *
548 * @param buf
549 */
550 private void renderDateElement(StringBuffer buf) {
551 renderTextElement(buf);
552
553
554
555
556 if ("true".equals(state.useJsCalendar)) {
557 buf.append(" <a href=\"javascript:doNothing()\" ")
558 .append(" onclick=\"");
559
560 setPattern(state.jsCalendarDateFormat);
561 state.jsCalendarDateFormat = ((SimpleDateFormat) getFormatter())
562 .toPattern();
563
564 if (state.jsCalendarDateFormat != null)
565 {
566 buf.append("calDateFormat='" + state.jsCalendarDateFormat + "';");
567 }
568
569 buf.append("setDateField(document.dbform['")
570 .append(getValueName())
571 .append("']);")
572 .append(" top.newWin = window.open('")
573 .append(((HttpServletRequest) pageContext.getRequest())
574 .getContextPath())
575 .append("/dbformslib/jscal/calendar.html','cal','width=270,height=280')\">")
576 .append("<img src=\"")
577 .append(((HttpServletRequest) pageContext.getRequest())
578 .getContextPath())
579 .append("/dbformslib/jscal/calendar.gif\" width=\"32\" height=\"32\" ")
580 .append(" border=0 alt=\"Click on the Calendar to activate the Pop-Up Calendar Window.\">")
581 .append("</img>")
582 .append("</a>");
583 }
584 }
585
586
587 /***
588 * render input's type "select"
589 *
590 * @param buf
591 */
592 private void renderSelectElement(StringBuffer buf) {
593 String sizestr = "";
594
595 if (state.size != null) {
596 sizestr = "size=\"" + state.size + "\" ";
597 }
598
599 buf.append("<select name=\"" + getValueName() + "\" " + sizestr
600 + " class=\"" + state.styleClass + "\">\n");
601
602 if ((state.customEntry != null)
603 && (state.customEntry.trim()
604 .length() > 0)) {
605 String aKey = org.dbforms.util.StringUtil.getEmbeddedStringWithoutDots(state.customEntry,
606 0,
607 ',');
608 String aValue = org.dbforms.util.StringUtil
609 .getEmbeddedStringWithoutDots(state.customEntry, 1, ',');
610
611
612 if (getParentForm().hasCaptionResourceSet()) {
613 aValue = MessageResources.getMessage((HttpServletRequest)pageContext.getRequest(),aValue);
614 }
615
616 boolean isSelected = false;
617
618 if ((state.selectedIndex == null)
619 || (state.selectedIndex.trim()
620 .length() == 0)) {
621 isSelected = "true".equals(StringUtil.getEmbeddedStringWithoutDots(state.customEntry,
622 2,
623 ','));
624 }
625
626 buf.append(generateTagString(aKey, aValue, isSelected));
627 }
628
629 int embeddedDataSize = state.embeddedData.size();
630
631 for (int i = 0; i < embeddedDataSize; i++) {
632 StaticData aKeyValuePair = (StaticData) state.embeddedData.get(i);
633 String aKey = aKeyValuePair.getKey();
634 String aValue = aKeyValuePair.getValue();
635
636
637
638 boolean isSelected = aKey.equals(state.value);
639 buf.append(generateTagString(aKey, aValue, isSelected));
640 }
641
642 buf.append("</select>\n");
643 }
644
645
646 /***
647 * render input's type "text"
648 *
649 * @param buf
650 */
651 private void renderTextElement(StringBuffer buf) {
652 String sizestr = "";
653
654 if (state.size != null) {
655 sizestr = "size=\"" + state.size + "\" ";
656 }
657
658 buf.append("<input type=\"text\" name=\"" + getValueName()
659 + "\" value=\"" + this.getFormattedFieldValue() + "\""
660 + sizestr + " class=\"" + state.styleClass + "\"/>\n");
661 buf.append("<input type=\"hidden\" name=\"" + getValueType()
662 + "\" value=\"" + state.type.toLowerCase() + "\"/>\n");
663
664 if (!Util.isNull(state.searchAlgo)) {
665 buf.append("<input type=\"hidden\" name=\"" + getSearchAlgoType()
666 + "\" value=\"" + state.searchAlgo + "\"/>\n");
667 }
668 }
669
670 /***
671 * tag's state holder. Used a separate class to hold tag's state to
672 * workaround to Tag pooling, in which an tag object is reused, but we have
673 * the need to store informations about all child tags in the parent, so we
674 * store the state, and apply it to a dummy tag when needed.
675 *
676 * @author Sergio Moretti
677 */
678 protected static class State {
679 /***
680 * contains list of elements to show as options when type is select,
681 * (DataContainer interface)
682 */
683 protected List embeddedData = null;
684
685 /*** Allows an additional (independant) entry into the select list */
686 protected String customEntry = null;
687
688 /*** Holds value of property jsCalendarDateFormat. */
689 protected String jsCalendarDateFormat = null;
690
691 /*** label showed before input tag */
692 protected String label = null;
693
694
695
696
697 protected String searchAlgo = null;
698
699 /*** currently selected index, valid only when type = select */
700 protected String selectedIndex = null;
701
702 /*** html input's attribute size */
703 protected String size = null;
704
705 /*** css class to be applied to input element */
706 protected String styleClass = null;
707
708 /*** type of input */
709 protected String type = null;
710
711 /*** Holds value of property useJsCalendar. */
712 protected String useJsCalendar = null;
713
714 /*** current value, readed from request */
715 protected String value = null;
716
717 /*** identifier of this value object */
718 protected int valueId = -1;
719 }
720 }