001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.acting;
018:
019: import java.io.BufferedInputStream;
020: import java.io.ByteArrayInputStream;
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.InputStream;
024: import java.math.BigDecimal;
025: import java.sql.Array;
026: import java.sql.Clob;
027: import java.sql.Date;
028: import java.sql.PreparedStatement;
029: import java.sql.ResultSet;
030: import java.sql.SQLException;
031: import java.sql.Time;
032: import java.sql.Timestamp;
033: import java.sql.Types;
034: import java.text.DateFormat;
035: import java.text.SimpleDateFormat;
036: import java.util.Collections;
037: import java.util.HashMap;
038: import java.util.Map;
039:
040: import org.apache.avalon.excalibur.datasource.DataSourceComponent;
041: import org.apache.avalon.framework.activity.Disposable;
042: import org.apache.avalon.framework.configuration.Configuration;
043: import org.apache.avalon.framework.configuration.ConfigurationException;
044: import org.apache.avalon.framework.parameters.Parameters;
045: import org.apache.avalon.framework.service.ServiceException;
046: import org.apache.avalon.framework.service.ServiceManager;
047: import org.apache.avalon.framework.service.ServiceSelector;
048: import org.apache.cocoon.environment.Request;
049: import org.apache.cocoon.util.ImageProperties;
050: import org.apache.cocoon.util.ImageUtils;
051:
052: /**
053: * Set up environment for configurable form handling data. It is
054: * important to note that all DatabaseActions use a common configuration
055: * format. This group of actions are unique in that they employ a
056: * terciary mapping. There is the Form parameter, the database column,
057: * and the type.
058: *
059: * Each configuration file must use the same format in order to be
060: * effective. The name of the root configuration element is irrelevant.
061: *
062: * <pre>
063: * <root>
064: * <connection>personnel<connection>
065: * <table>
066: * <keys>
067: * <key param="id" dbcol="id" type="int"/>
068: * </keys>
069: * <values>
070: * <value param="name" dbcol="name" type="string"/>
071: * <value param="department" dbcol="department_id" type="int"/>
072: * </values>
073: * </table>
074: * </root>
075: * </pre>
076: *
077: * The types recognized by this system are:
078: *
079: * <table>
080: * <tr>
081: * <th>Type</th>
082: * <th>Description</th>
083: * </tr>
084: * <tr>
085: * <td>ascii</td>
086: * <td>ASCII Input Stream, a CLOB input</td>
087: * </tr>
088: * <tr>
089: * <td>big-decimal</td>
090: * <td>a <code>java.math.BigDecimal</code> value</td>
091: * </tr>
092: * <tr>
093: * <td>binary</td>
094: * <td>Binary Input Stream, a BLOB input</td>
095: * </tr>
096: * <tr>
097: * <td>byte</td>
098: * <td>a Byte</td>
099: * </tr>
100: * <tr>
101: * <td>string</td>
102: * <td>a String</td>
103: * </tr>
104: * <tr>
105: * <td>date</td>
106: * <td>a Date</td>
107: * </tr>
108: * <tr>
109: * <td>double</td>
110: * <td>a Double</td>
111: * </tr>
112: * <tr>
113: * <td>float</td>
114: * <td>a Float</td>
115: * </tr>
116: * <tr>
117: * <td>int</td>
118: * <td>an Integer</td>
119: * </tr>
120: * <tr>
121: * <td>long</td>
122: * <td>a Long</td>
123: * </tr>
124: * <tr>
125: * <td>short</td>
126: * <td>a Short</td>
127: * </tr>
128: * <tr>
129: * <td>time</td>
130: * <td>a Time</td>
131: * </tr>
132: * <tr>
133: * <td>time-stamp</td>
134: * <td>a Timestamp</td>
135: * </tr>
136: * <tr>
137: * <td>now</td>
138: * <td>a Timestamp with the current day/time--the form value is ignored.</td>
139: * </tr>
140: * <tr>
141: * <td>image</td>
142: * <td>a binary image file, we cache the attribute information</td>
143: * </tr>
144: * <tr>
145: * <td>image-width</td>
146: * <td>
147: * the width attribute of the cached file attribute. NOTE:
148: * param attribute must equal the param for image with a
149: * "-width" suffix.
150: * </td>
151: * </tr>
152: * <tr>
153: * <td>image-height</td>
154: * <td>
155: * the width attribute of the cached file attribute NOTE:
156: * param attribute must equal the param for image with a
157: * "-height" suffix.
158: * </td>
159: * </tr>
160: * <tr>
161: * <td>image-size</td>
162: * <td>
163: * the size attribute of the cached file attribute NOTE:
164: * param attribute must equal the param for image with a
165: * "-size" suffix.
166: * </td>
167: * </tr>
168: * </table>
169: *
170: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
171: * @author <a href="mailto:balld@apache.org">Donald Ball</a>
172: * @version $Id: AbstractDatabaseAction.java 452425 2006-10-03 11:18:47Z vgritsenko $
173: */
174: public abstract class AbstractDatabaseAction extends
175: AbstractComplementaryConfigurableAction implements Disposable {
176:
177: protected Map files = new HashMap();
178: protected static final Map typeConstants;
179: protected ServiceSelector dbselector;
180:
181: static {
182: /*
183: * Initialize the map of type names to jdbc column types.
184: * Note that INTEGER, BLOB, and VARCHAR column types map to more than
185: * one type name.
186: */
187: Map constants = new HashMap();
188: constants.put("ascii", new Integer(Types.CLOB));
189: constants.put("big-decimal", new Integer(Types.BIGINT));
190: constants.put("binary", new Integer(Types.BLOB));
191: constants.put("byte", new Integer(Types.TINYINT));
192: constants.put("string", new Integer(Types.VARCHAR));
193: constants.put("date", new Integer(Types.DATE));
194: constants.put("double", new Integer(Types.DOUBLE));
195: constants.put("float", new Integer(Types.FLOAT));
196: constants.put("int", new Integer(Types.INTEGER));
197: constants.put("long", new Integer(Types.NUMERIC));
198: constants.put("short", new Integer(Types.SMALLINT));
199: constants.put("time", new Integer(Types.TIME));
200: constants.put("time-stamp", new Integer(Types.TIMESTAMP));
201: constants.put("now", new Integer(Types.LONGVARBINARY));
202: //constants.put("image", new Integer(Types.DISTINCT));
203: //constants.put("image-width", new Integer(Types.ARRAY));
204: //constants.put("image-height", new Integer(Types.BIT));
205: //constants.put("image-size", new Integer(Types.CHAR));
206: constants.put("image", new Integer(Types.BLOB));
207: constants.put("image-width", new Integer(Types.INTEGER));
208: constants.put("image-height", new Integer(Types.INTEGER));
209: constants.put("image-size", new Integer(Types.INTEGER));
210: constants.put("row-index", new Integer(Types.INTEGER));
211: constants.put("image-mime-type", new Integer(Types.VARCHAR));
212: constants.put("array", new Integer(Types.ARRAY));
213: constants.put("row", new Integer(Types.STRUCT));
214: constants.put("object", new Integer(Types.OTHER));
215: typeConstants = Collections.unmodifiableMap(constants);
216: }
217:
218: /**
219: * Compose the Actions so that we can select our databases.
220: */
221: public void service(ServiceManager manager) throws ServiceException {
222: super .service(manager);
223: this .dbselector = (ServiceSelector) manager
224: .lookup(DataSourceComponent.ROLE + "Selector");
225: }
226:
227: /**
228: * Get the Datasource we need.
229: */
230: protected final DataSourceComponent getDataSource(Configuration conf)
231: throws ServiceException {
232: Configuration dsn = conf.getChild("connection");
233: return (DataSourceComponent) this .dbselector.select(dsn
234: .getValue(""));
235: }
236:
237: /**
238: * Return whether a type is a Large Object (BLOB/CLOB).
239: */
240: protected final boolean isLargeObject(String type) {
241: if ("ascii".equals(type))
242: return true;
243: if ("binary".equals(type))
244: return true;
245: if ("image".equals(type))
246: return true;
247:
248: return false;
249: }
250:
251: /**
252: * Get the Statement column so that the results are mapped correctly.
253: */
254: protected Object getColumn(ResultSet set, Request request,
255: Configuration entry) throws Exception {
256: Integer type = (Integer) AbstractDatabaseAction.typeConstants
257: .get(entry.getAttribute("type"));
258: String attribute = entry.getAttribute("param", "");
259: String dbcol = entry.getAttribute("dbcol", "");
260: Object value = null;
261:
262: switch (type.intValue()) {
263: case Types.CLOB:
264: Clob dbClob = set.getClob(dbcol);
265: if (dbClob != null) {
266: int length = (int) dbClob.length();
267: InputStream is = new BufferedInputStream(dbClob
268: .getAsciiStream());
269: try {
270: byte[] buffer = new byte[length];
271: length = is.read(buffer);
272: value = new String(buffer, 0, length);
273: } finally {
274: is.close();
275: }
276: }
277: break;
278: case Types.BIGINT:
279: value = set.getBigDecimal(dbcol);
280: break;
281: case Types.TINYINT:
282: value = new Byte(set.getByte(dbcol));
283: break;
284: case Types.VARCHAR:
285: value = set.getString(dbcol);
286: break;
287: case Types.DATE:
288: value = set.getDate(dbcol);
289: break;
290: case Types.DOUBLE:
291: value = new Double(set.getDouble(dbcol));
292: break;
293: case Types.FLOAT:
294: value = new Float(set.getFloat(dbcol));
295: break;
296: case Types.INTEGER:
297: value = new Integer(set.getInt(dbcol));
298: break;
299: case Types.NUMERIC:
300: value = new Long(set.getLong(dbcol));
301: break;
302: case Types.SMALLINT:
303: value = new Short(set.getShort(dbcol));
304: break;
305: case Types.TIME:
306: value = set.getTime(dbcol);
307: break;
308: case Types.TIMESTAMP:
309: value = set.getTimestamp(dbcol);
310: break;
311: case Types.ARRAY:
312: value = set.getArray(dbcol);
313: break;
314: case Types.BIT:
315: value = new Integer(set.getInt(dbcol));
316: break;
317: case Types.CHAR:
318: value = new Integer(set.getInt(dbcol));
319: break;
320: case Types.STRUCT:
321: value = set.getObject(dbcol);
322: break;
323: case Types.OTHER:
324: value = set.getObject(dbcol);
325: break;
326:
327: default:
328: // The blob types have to be requested separately, via a Reader.
329: value = "";
330: break;
331: }
332:
333: setRequestAttribute(request, attribute, value);
334:
335: return value;
336: }
337:
338: /**
339: * Set the Statement column so that the results are mapped correctly.
340: * The name of the parameter is retrieved from the configuration object.
341: *
342: * @param statement the prepared statement
343: * @param position the position of the column
344: * @param request the request
345: * @param entry the configuration object
346: */
347: protected void setColumn(PreparedStatement statement, int position,
348: Request request, Configuration entry) throws Exception {
349: setColumn(statement, position, request, entry, entry
350: .getAttribute("param", ""));
351: }
352:
353: /**
354: * Set the Statement column so that the results are mapped correctly. The
355: * value of the column is retrieved from the request object. If the
356: * named parameter exists in the request object's parameters, that value
357: * is used. Otherwise if the named parameter exists in the request object's
358: * attributes, that value is used. Otherwise the request object is
359: * retrieved using Request.get(attribute), which is documented to be the
360: * same as Request.getAttribute(attribute), so something weird must be
361: * going on.
362: *
363: * @param statement the prepared statement
364: * @param position the position of the column
365: * @param request the request
366: * @param entry the configuration object
367: * @param param the name of the request parameter
368: */
369: protected void setColumn(PreparedStatement statement, int position,
370: Request request, Configuration entry, String param)
371: throws Exception {
372: Object value = request.getParameter(param);
373: if (value == null)
374: value = request.getAttribute(param);
375: if (value == null)
376: value = request.get(param);
377: setColumn(statement, position, request, entry, param, value);
378: }
379:
380: /**
381: * Set the Statement column so that the results are mapped correctly.
382: *
383: * @param statement the prepared statement
384: * @param position the position of the column
385: * @param request the request
386: * @param entry the configuration object
387: * @param param the name of the request parameter
388: * @param value the value of the column
389: */
390: protected void setColumn(PreparedStatement statement, int position,
391: Request request, Configuration entry, String param,
392: Object value) throws Exception {
393: setColumn(statement, position, request, entry, param, value, 0);
394: }
395:
396: /**
397: * Set the Statement column so that the results are mapped correctly.
398: *
399: * @param statement the prepared statement
400: * @param position the position of the column
401: * @param request the request
402: * @param entry the configuration object
403: * @param param the name of the request parameter
404: * @param value the value of the column
405: * @param rowIndex the index of the current row for manyrows inserts
406: */
407: protected void setColumn(PreparedStatement statement, int position,
408: Request request, Configuration entry, String param,
409: Object value, int rowIndex) throws Exception {
410: getLogger().debug(
411: "Setting column " + position + " named " + param
412: + " with value " + value);
413: if (value instanceof String) {
414: value = ((String) value).trim();
415: }
416: String typeName = entry.getAttribute("type");
417: Integer typeObject = (Integer) AbstractDatabaseAction.typeConstants
418: .get(typeName);
419: if (typeObject == null) {
420: throw new SQLException("Can't set column because the type "
421: + typeName + " is unrecognized");
422: }
423: if (value == null) {
424: /** If the value is null, set the column value null and return **/
425: if (typeName.equals("image-width")
426: || typeName.equals("image-height")
427: || typeName.equals("image-size")
428: || typeName.equals("row-index")
429: || typeName.equals("image-mime-type")) {
430: /** these column types are automatically generated so it's ok **/
431: } else {
432: statement.setNull(position, typeObject.intValue());
433: return;
434: }
435: }
436: if ("".equals(value)) {
437: switch (typeObject.intValue()) {
438: case Types.CHAR:
439: case Types.CLOB:
440: case Types.VARCHAR:
441: /** If the value is an empty string and the column is
442: a string type, we can continue **/
443: break;
444: case Types.INTEGER:
445: if (typeName.equals("image-width")
446: || typeName.equals("image-height")
447: || typeName.equals("image-size")
448: || typeName.equals("row-index")) {
449: /** again, these types are okay to be absent **/
450: break;
451: }
452: default:
453: /** If the value is an empty string and the column
454: is something else, we treat it as a null value **/
455: statement.setNull(position, typeObject.intValue());
456: return;
457: }
458: }
459:
460: /** Store the column value in the request attribute
461: keyed by the request parameter name. we do this so possible future
462: actions can access this data. not sure about the key tho... **/
463: setRequestAttribute(request, param, value);
464: File file;
465:
466: switch (typeObject.intValue()) {
467: case Types.CLOB:
468: int length = -1;
469: InputStream asciiStream = null;
470:
471: if (value instanceof File) {
472: File asciiFile = (File) value;
473: asciiStream = new BufferedInputStream(
474: new FileInputStream(asciiFile));
475: length = (int) asciiFile.length();
476: } else {
477: String asciiText = (String) value;
478: asciiStream = new BufferedInputStream(
479: new ByteArrayInputStream(asciiText.getBytes()));
480: length = asciiText.length();
481: }
482:
483: statement.setAsciiStream(position, asciiStream, length);
484: break;
485: case Types.BIGINT:
486: BigDecimal bd = null;
487:
488: if (value instanceof BigDecimal) {
489: bd = (BigDecimal) value;
490: } else {
491: bd = new BigDecimal((String) value);
492: }
493:
494: statement.setBigDecimal(position, bd);
495: break;
496: case Types.TINYINT:
497: Byte b = null;
498:
499: if (value instanceof Byte) {
500: b = (Byte) value;
501: } else {
502: b = new Byte((String) value);
503: }
504:
505: statement.setByte(position, b.byteValue());
506: break;
507: case Types.DATE:
508: Date d = null;
509:
510: if (value instanceof Date) {
511: d = (Date) value;
512: } else if (value instanceof java.util.Date) {
513: d = new Date(((java.util.Date) value).getTime());
514: } else {
515: d = new Date(this .dateValue((String) value, entry
516: .getAttribute("format", "M/d/yyyy")));
517: }
518:
519: statement.setDate(position, d);
520: break;
521: case Types.DOUBLE:
522: Double db = null;
523:
524: if (value instanceof Double) {
525: db = (Double) value;
526: } else {
527: db = new Double((String) value);
528: }
529:
530: statement.setDouble(position, db.doubleValue());
531: break;
532: case Types.FLOAT:
533: Float f = null;
534:
535: if (value instanceof Float) {
536: f = (Float) value;
537: } else {
538: f = new Float((String) value);
539: }
540:
541: statement.setFloat(position, f.floatValue());
542: break;
543: case Types.NUMERIC:
544: Long l = null;
545:
546: if (value instanceof Long) {
547: l = (Long) value;
548: } else {
549: l = new Long((String) value);
550: }
551:
552: statement.setLong(position, l.longValue());
553: break;
554: case Types.SMALLINT:
555: Short s = null;
556:
557: if (value instanceof Short) {
558: s = (Short) value;
559: } else {
560: s = new Short((String) value);
561: }
562:
563: statement.setShort(position, s.shortValue());
564: break;
565: case Types.TIME:
566: Time t = null;
567:
568: if (value instanceof Time) {
569: t = (Time) value;
570: } else {
571: t = new Time(this .dateValue((String) value, entry
572: .getAttribute("format", "h:m:s a")));
573: }
574:
575: statement.setTime(position, t);
576: break;
577: case Types.TIMESTAMP:
578: Timestamp ts = null;
579:
580: if (value instanceof Time) {
581: ts = (Timestamp) value;
582: } else {
583: ts = new Timestamp(this .dateValue((String) value, entry
584: .getAttribute("format", "M/d/yyyy h:m:s a")));
585: }
586:
587: statement.setTimestamp(position, ts);
588: break;
589: case Types.ARRAY:
590: statement.setArray(position, (Array) value); // no way to convert string to array
591: break;
592: case Types.STRUCT:
593: case Types.OTHER:
594: statement.setObject(position, value);
595: break;
596: case Types.LONGVARBINARY:
597: statement.setTimestamp(position, new Timestamp(
598: (new java.util.Date()).getTime()));
599: break;
600: case Types.VARCHAR:
601: if ("string".equals(typeName)) {
602: statement.setString(position, (String) value);
603: break;
604: } else if ("image-mime-type".equals(typeName)) {
605: String imageAttr = param.substring(0,
606: (param.length() - "-mime-type".length()));
607: file = (File) request.get(imageAttr);
608: synchronized (this .files) {
609: Parameters parameters = (Parameters) this .files
610: .get(file);
611: String imageMimeType = parameters.getParameter(
612: "image-mime-type", (String) settings.get(
613: "image-mime-type", ""));
614: statement.setString(position, imageMimeType);
615: /** Store the image mime type in the request attributes.
616: Why do we do this? **/
617: setRequestAttribute(request, param, imageMimeType);
618: }
619: break;
620: }
621: case Types.BLOB:
622: if (value instanceof File) {
623: file = (File) value;
624: } else if (value instanceof String) {
625: file = new File((String) value);
626: } else {
627: throw new SQLException("Invalid type for blob: "
628: + value.getClass().getName());
629: }
630: //InputStream input = new BufferedInputStream(new FileInputStream(file));
631: FileInputStream input = new FileInputStream(file);
632: statement.setBinaryStream(position, input, (int) file
633: .length());
634: if ("image".equals(typeName)) {
635: /** If this column type is an image, store the
636: size, width, and height in a static table **/
637: Parameters parameters = new Parameters();
638: parameters.setParameter("image-size", Long
639: .toString(file.length()));
640: ImageProperties prop = ImageUtils
641: .getImageProperties(file);
642: parameters.setParameter("image-width", Integer
643: .toString(prop.width));
644: parameters.setParameter("image-height", Integer
645: .toString(prop.height));
646: // TC: if it's really mime-type shouldn't we prepend "image/"?
647: parameters.setParameter("image-mime-type", prop.type);
648: synchronized (this .files) {
649: this .files.put(file, parameters);
650: }
651: }
652: break;
653: case Types.INTEGER:
654: if ("int".equals(typeName)) {
655: Integer i = null;
656: if (value instanceof Integer) {
657: i = (Integer) value;
658: } else {
659: i = new Integer((String) value);
660: }
661: statement.setInt(position, i.intValue());
662: break;
663: } else if ("image-width".equals(typeName)) {
664: /** Get the image width from the cached image data **/
665: /** Is this why we store the values in the request
666: attributes? **/
667: String imageAttr = param.substring(0,
668: (param.length() - "-width".length()));
669: file = (File) request.get(imageAttr);
670: synchronized (this .files) {
671: Parameters parameters = (Parameters) this .files
672: .get(file);
673: statement
674: .setInt(
675: position,
676: parameters
677: .getParameterAsInteger(
678: "image-width",
679: Integer
680: .parseInt((String) settings
681: .get(
682: "image-width",
683: "-1"))));
684: /** Store the image width in the request attributes.
685: Why do we do this? **/
686: setRequestAttribute(request, param, parameters
687: .getParameter("image-width",
688: (String) settings.get(
689: "image-width", "")));
690: }
691: break;
692: } else if ("image-height".equals(typeName)) {
693: /** Get the image height from the cached image data **/
694: String imageAttr = param.substring(0,
695: (param.length() - "-height".length()));
696: file = (File) request.get(imageAttr);
697: synchronized (this .files) {
698: Parameters parameters = (Parameters) this .files
699: .get(file);
700: statement
701: .setInt(
702: position,
703: parameters
704: .getParameterAsInteger(
705: "image-height",
706: Integer
707: .parseInt((String) settings
708: .get(
709: "image-height",
710: "-1"))));
711: setRequestAttribute(request, param, parameters
712: .getParameter("image-height",
713: (String) settings.get(
714: "image-height", "")));
715: }
716: break;
717: } else if ("image-size".equals(typeName)) {
718: /** Get the image file size from the cached image data **/
719: String imageAttr = param.substring(0,
720: (param.length() - "-size".length()));
721: file = (File) request.get(imageAttr);
722: synchronized (this .files) {
723: Parameters parameters = (Parameters) this .files
724: .get(file);
725: statement
726: .setInt(
727: position,
728: parameters
729: .getParameterAsInteger(
730: "image-size",
731: Integer
732: .parseInt((String) settings
733: .get(
734: "image-height",
735: "-1"))));
736: setRequestAttribute(request, param, parameters
737: .getParameter("image-size",
738: (String) settings.get("image-size",
739: "")));
740: }
741: break;
742: } else if ("row-index".equals(typeName)) {
743: statement.setInt(position, rowIndex);
744: break;
745: }
746: default:
747: throw new SQLException(
748: "Impossible exception - invalid type " + typeName);
749: }
750: }
751:
752: /**
753: * Convert a String to a long value.
754: */
755: private final long dateValue(String value, String format)
756: throws Exception {
757: DateFormat formatter = new SimpleDateFormat(format);
758: return formatter.parse(value).getTime();
759: }
760:
761: /**
762: * dispose
763: */
764: public void dispose() {
765: this .manager.release(dbselector);
766: }
767:
768: /**
769: * Store a key/value pair in the request attributes. We prefix the key
770: * with the name of this class to prevent potential name collisions.
771: */
772: protected void setRequestAttribute(Request request, String key,
773: Object value) {
774: request.setAttribute(
775: "org.apache.cocoon.acting.AbstractDatabaseAction:"
776: + key, value);
777: }
778:
779: /**
780: * Retreive a value from the request attributes.
781: */
782: protected Object getRequestAttribute(Request request, String key) {
783: return request
784: .getAttribute("org.apache.cocoon.acting.AbstractDatabaseAction:"
785: + key);
786: }
787:
788: /**
789: * Build a separed list with the Values of a Configuration Array
790: * @param values - build the list from
791: * @param separator - Put a separator between the values of the list
792: * @return - an StringBuffer with the builded List
793: * @throws ConfigurationException
794: */
795: protected StringBuffer buildList(Configuration[] values,
796: String separator) throws ConfigurationException {
797: StringBuffer buffer = new StringBuffer();
798: for (int i = 0; i < values.length; i++) {
799: if (i > 0) {
800: buffer.append(separator);
801: }
802: buffer.append(values[i].getAttribute("dbcol"));
803: buffer.append(" = ?");
804: }
805: return buffer;
806: }
807:
808: /**
809: * Build a separed list with the Values of a Configuration Array
810: * @param values - build the list from
811: * @param begin - Initial index
812: * @return - an StringBuffer with the builded List
813: * @throws ConfigurationException
814: */
815: protected StringBuffer buildList(Configuration[] values, int begin)
816: throws ConfigurationException {
817: StringBuffer buffer = new StringBuffer();
818: int length = values.length;
819: boolean prependComma = begin > 0;
820: for (int i = 0; i < length; i++) {
821: if (prependComma) {
822: buffer.append(", ");
823: } else {
824: prependComma = true;
825: }
826: buffer.append(values[i].getAttribute("dbcol"));
827: }
828: return buffer;
829: }
830: }
|