View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/taglib/AbstractEmbeddedDataTag.java,v 1.3 2006/02/06 16:30:45 hkollmann Exp $
3    * $Revision: 1.3 $
4    * $Date: 2006/02/06 16:30:45 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
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) // try cheap compatibility mode for old
228 										// applications without '%'// within
229 										// patterns
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             // was 's bla bla s -- s' is now '%s blabla %s -- %s'
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       // If disableCache not activated, was the data generated by another
261       // instance on the same page yet?
262       if (useCache()) {
263          data = (List) pageContext.getAttribute(name, PageContext.PAGE_SCOPE);
264       }
265 
266       // if not, we do it
267       if (data == null) {
268          result = EVAL_BODY_BUFFERED;
269          logCat.info("generating Embeddeddata " + name);
270 
271          // take Config-Object from application context - this object should
272          // have been
273          // initalized by Config-Servlet on Webapp/server-startup!
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             // Always store data in pageContext - Maybe we need it later.
295             // So we can change dynamic disableCache
296             pageContext.setAttribute(name, data, PageContext.PAGE_SCOPE);
297 
298             // cache result for further loops
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       // DbBaseMultiTag are: select, radio, checkbox!
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                      // use String representation instead
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) // npe will be thrown if null//
397 											// value returned from database
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) // no format given or formatting failed
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 }