1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.dbforms.taglib;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import org.dbforms.config.DbFormsConfig;
28 import org.dbforms.config.DbFormsConfigRegistry;
29 import org.dbforms.config.ResultSetVector;
30 import org.dbforms.interfaces.IDataContainer;
31 import org.dbforms.interfaces.IEscaper;
32 import org.dbforms.interfaces.IFormatEmbeddedData;
33 import org.dbforms.interfaces.IStaticDataList;
34 import org.dbforms.interfaces.StaticData;
35
36 import org.dbforms.util.MessageResources;
37 import org.dbforms.util.ReflectionUtil;
38 import org.dbforms.util.SqlUtil;
39 import org.dbforms.util.Util;
40
41 import java.sql.Connection;
42 import java.sql.SQLException;
43
44 import java.util.List;
45
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.jsp.JspException;
48 import javax.servlet.jsp.PageContext;
49
50
51
52 /***
53 * DOCUMENT ME!
54 *
55 * @author $author$
56 * @version $Revision: 1.3 $
57 */
58 public abstract class AbstractEmbeddedDataTag extends AbstractDbBaseHandlerTag
59 implements javax.servlet.jsp.tagext.TryCatchFinally, IStaticDataList {
60 private static Log logCat = LogFactory.getLog(AbstractEmbeddedDataTag.class
61 .getName());
62 private IFormatEmbeddedData printfFormat;
63 private List data;
64 private String dbConnectionName;
65 private String disableCache = "false";
66 private String format;
67 private String formatClass;
68 private String name;
69
70 /***
71 * DOCUMENT ME!
72 *
73 * @param name
74 * DOCUMENT ME!
75 */
76 public void setDbConnectionName(String name) {
77 dbConnectionName = name;
78 }
79
80
81 /***
82 * DOCUMENT ME!
83 *
84 * @return DOCUMENT ME!
85 */
86 public String getDbConnectionName() {
87 return dbConnectionName;
88 }
89
90
91 /***
92 * Insert the method's description here. Creation date: (2001-09-21
93 * 12:20:42)
94 *
95 * @param newDisableCache
96 * java.lang.String
97 */
98 public void setDisableCache(java.lang.String newDisableCache) {
99 disableCache = newDisableCache;
100 }
101
102
103 /***
104 * Insert the method's description here. Creation date: (2001-09-21
105 * 12:20:42)
106 *
107 * @return java.lang.String
108 */
109 public java.lang.String getDisableCache() {
110 return disableCache;
111 }
112
113
114 /***
115 * DOCUMENT ME!
116 *
117 * @return DOCUMENT ME!
118 */
119 public IEscaper getEscaper() {
120 IDataContainer parent = ((IDataContainer) getParent());
121 IEscaper res = parent.getEscaper();
122
123 return res;
124 }
125
126
127 /***
128 * DOCUMENT ME!
129 *
130 * @param format
131 * DOCUMENT ME!
132 */
133 public void setFormat(java.lang.String format) {
134 this.format = format;
135 }
136
137
138 /***
139 * Sets the formatClass.
140 *
141 * @param formatClass
142 * The formatClass to set
143 */
144 public void setFormatClass(String formatClass) {
145 this.formatClass = formatClass;
146 }
147
148
149 /***
150 * Returns the formatClass.
151 *
152 * @return String
153 */
154 public String getFormatClass() {
155 return formatClass;
156 }
157
158
159 /***
160 * set the name of the embedded data. every embedded data entity on a jsp
161 * page has to have a unique name. this name is used for storing (caching)
162 * and retrieving data in Page-Scope. this is useful if a tag gets evaluated
163 * many times -> we do not want the queries etc. to be executed every time!
164 *
165 * @param name
166 * DOCUMENT ME!
167 */
168 public void setName(String name) {
169 this.name = name;
170 }
171
172
173 /***
174 * returns the unique name of the embedded data
175 *
176 * @return DOCUMENT ME!
177 */
178 public String getName() {
179 return name;
180 }
181
182
183
184 /***
185 * DOCUMENT ME!
186 */
187 public void doFinally() {
188 name = null;
189 dbConnectionName = null;
190 format = null;
191 printfFormat = null;
192 formatClass = null;
193 disableCache = "false";
194 }
195
196
197 /***
198 * DOCUMENT ME!
199 *
200 * @return DOCUMENT ME!
201 *
202 * @throws JspException
203 * DOCUMENT ME!
204 * @throws IllegalArgumentException
205 * DOCUMENT ME!
206 */
207 public int doStartTag() throws JspException {
208 /***
209 * Grunikiewicz.philip 2001-09-21 Sometimes a developer may want to
210 * execute the embedded data query for each row. i.e. not cache the
211 * result set. Example: Table contains 1000+ of rows, use queryData with
212 * qualified 'where' clause. Data cannot be cached because each
213 * subsequent row need to execute a different query (whereClause with
214 * different parameters)
215 */
216 printfFormat = null;
217
218 if (!Util.isNull(format) || !Util.isNull(getFormatClass())) {
219 if (Util.isNull(getFormatClass())) {
220 setFormatClass(getConfig().getDefaultFormatterClass());
221 }
222
223 if (Util.isNull(format)) {
224 setFormat("%s");
225 }
226
227 if (format.indexOf('%') < 0)
228
229
230 {
231 StringBuffer newFormat = new StringBuffer();
232
233 for (int j = 0; j < format.length(); j++) {
234 if (format.charAt(j) == 's') {
235 newFormat.append("%s");
236 } else {
237 newFormat.append(format.charAt(j));
238 }
239 }
240
241 format = newFormat.toString();
242
243
244 }
245
246 try {
247 printfFormat = (IFormatEmbeddedData) ReflectionUtil.newInstance(getFormatClass());
248 printfFormat.setLocale(MessageResources.getLocale(
249 (HttpServletRequest) pageContext.getRequest()));
250 printfFormat.setFormat(format);
251 } catch (Exception e) {
252 logCat.error("cannot create the new printfFormat ["
253 + getFormatClass() + "]", e);
254 }
255 }
256
257 int result = SKIP_BODY;
258 data = null;
259
260
261
262 if (useCache()) {
263 data = (List) pageContext.getAttribute(name, PageContext.PAGE_SCOPE);
264 }
265
266
267 if (data == null) {
268 result = EVAL_BODY_BUFFERED;
269 logCat.info("generating Embeddeddata " + name);
270
271
272
273
274 DbFormsConfig config = null;
275
276 try {
277 config = DbFormsConfigRegistry.instance().lookup();
278 } catch (Exception e) {
279 logCat.error(e);
280 throw new JspException(e);
281 }
282
283 Connection con = null;
284
285 try {
286 con = config.getConnection(dbConnectionName);
287 } catch (Exception e) {
288 throw new JspException(e);
289 }
290
291 try {
292 data = fetchData(con);
293
294
295
296 pageContext.setAttribute(name, data, PageContext.PAGE_SCOPE);
297
298
299 } catch (SQLException sqle) {
300 throw new JspException("Database error in EmbeddedData.fetchData "
301 + sqle.toString());
302 } finally {
303 SqlUtil.closeConnection(con);
304 }
305 } else {
306 logCat.info(" Embeddeddata " + name + " already generated");
307 }
308
309 ((IDataContainer) getParent()).setEmbeddedData(data);
310
311
312 return result;
313 }
314
315
316 /***
317 * this method is implemented by subclasses in order to match the user's
318 * need for specific data.
319 *
320 * @param con
321 * DOCUMENT ME!
322 *
323 * @return DOCUMENT ME!
324 */
325 protected abstract List fetchData(Connection con) throws SQLException;
326
327 /***
328 * DOCUMENT ME!
329 *
330 * @param pair
331 * DOCUMENT ME!
332 */
333 public void addElement(StaticData pair) {
334 data.add(pair);
335 }
336
337
338
339
340 /***
341 * formatEmbeddedResultRows() formats a result set accornding to a
342 * eventually given format string. If no format string is given, the output
343 * format is a comma separated list of values. This method is called by
344 * subclasses TableData and QueryData
345 *
346 * @param rsv
347 * result set vector to be formatted
348 *
349 * @return a vector of key-value pairs, the values eventually formatted
350 * according to a given format string
351 */
352 protected List formatEmbeddedResultRows(ResultSetVector rsv) {
353 List result = new java.util.Vector();
354 boolean resultSuccessFullyFormated = false;
355
356 if (printfFormat != null) {
357 try {
358 rsv.moveFirst();
359
360 for (int i = 0; i < rsv.size(); i++) {
361
362 String[] currentRow = rsv.getCurrentRow();
363 String htKey = currentRow[0];
364
365 Object[] objs = rsv.getCurrentRowAsObjects();
366
367 Object[] objs2 = new Object[objs.length - 1];
368
369 for (int j = 0; j < objs2.length; j++) {
370 if ((objs[j] instanceof String) || (objs[j] instanceof Byte)
371 || (objs[j] instanceof java.lang.Integer)
372 || (objs[j] instanceof Short)
373 || (objs[j] instanceof Float)
374 || (objs[j] instanceof Long)
375 || (objs[j] instanceof Double)) {
376 objs2[j] = objs[(j + 1)];
377 } else {
378 objs2[j] = currentRow[j + 1];
379
380
381 }
382 }
383
384 String htValue = printfFormat.sprintf(objs2);
385 result.add(new StaticData(htKey, htValue));
386 rsv.moveNext();
387 }
388
389 resultSuccessFullyFormated = true;
390 } catch (IllegalArgumentException ex) {
391 logCat.error("Could not format result using format '" + format
392 + "', error message is " + ex.getMessage());
393 logCat.error(
394 "Using fallback method of comma separated list instead");
395 result = new java.util.Vector();
396 } catch (NullPointerException npe)
397
398 {
399 logCat.error("Could not format result using format '" + format
400 + "', error message is " + npe.getMessage());
401 logCat.error(
402 "Using fallback method of comma separated list instead");
403 result = new java.util.Vector();
404 }
405 }
406
407 if (!resultSuccessFullyFormated)
408 {
409 rsv.moveFirst();
410
411 for (int i = 0; i < rsv.size(); i++) {
412
413 String[] currentRow = rsv.getCurrentRow();
414 String htKey = currentRow[0];
415 StringBuffer htValueBuf = new StringBuffer();
416
417 for (int j = 1; j < currentRow.length; j++) {
418 htValueBuf.append(currentRow[j]);
419
420 if (j < (currentRow.length - 1)) {
421 htValueBuf.append(", ");
422 }
423 }
424
425 String htValue = htValueBuf.toString();
426
427 result.add(new StaticData(htKey, htValue));
428 rsv.moveNext();
429 }
430 }
431
432 return result;
433 }
434
435
436 /***
437 * DOCUMENT ME!
438 *
439 * @return DOCUMENT ME!
440 */
441 protected boolean useCache() {
442 return !(Util.getTrue(this.getDisableCache()));
443 }
444 }