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:
018: package org.apache.cocoon.acting.modular;
019:
020: import java.sql.Connection;
021: import java.sql.PreparedStatement;
022: import java.sql.ResultSet;
023: import java.sql.SQLException;
024: import java.util.Map;
025:
026: import org.apache.avalon.framework.configuration.Configuration;
027: import org.apache.avalon.framework.configuration.ConfigurationException;
028: import org.apache.avalon.framework.service.ServiceException;
029:
030: import org.apache.cocoon.util.JDBCTypeConversions;
031:
032: /**
033: * Selects a record from a database. The action can select one or more
034: * tables, and can select from more than one row of a table at a
035: * time.
036: *
037: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
038: * @version CVS $Id: DatabaseSelectAction.java 433543 2006-08-22 06:22:54Z crossley $
039: */
040: public class DatabaseSelectAction extends DatabaseAction {
041:
042: /**
043: * determine which mode to use as default mode
044: * here: SELECT
045: * highly specific to operation INSERT / UPDATE / DELETE / SELECT
046: */
047: protected String selectMode(boolean isAutoIncrement, Map modes) {
048:
049: return (String) modes.get(MODE_OTHERS);
050: }
051:
052: /**
053: * determine whether autoincrement columns should be honoured by
054: * this operation. This is usually snsible only for INSERTs.
055: */
056: protected boolean honourAutoIncrement() {
057: return false;
058: }
059:
060: /**
061: * Get the String representation of the PreparedStatement. This is
062: * mapped to the Configuration object itself, so if it doesn't exist,
063: * it will be created.
064: *
065: * @param table the table's configuration object
066: * @return the insert query as a string
067: */
068: protected CacheHelper getQuery(Configuration table, Map modeTypes,
069: Map defaultModeNames) throws ConfigurationException,
070: ServiceException {
071:
072: LookUpKey lookUpKey = new LookUpKey(table, modeTypes);
073: CacheHelper queryData = null;
074: synchronized (this .cachedQueryData) {
075: queryData = (CacheHelper) this .cachedQueryData
076: .get(lookUpKey);
077: if (queryData == null) {
078: Configuration[] keys = table.getChild("keys")
079: .getChildren("key");
080: Configuration[] values = table.getChild("values")
081: .getChildren("value");
082:
083: queryData = new CacheHelper(keys.length, keys.length
084: + values.length);
085: fillModes(keys, true, defaultModeNames, modeTypes,
086: queryData);
087: fillModes(values, false, defaultModeNames, modeTypes,
088: queryData);
089:
090: StringBuffer queryBuffer = new StringBuffer("SELECT ");
091:
092: //queryBuffer.append(table.getAttribute("name")).append(" WHERE ");
093: int count = 0;
094: for (int i = 0; i < queryData.columns.length; i++) {
095: if (!queryData.columns[i].isKey) {
096: if (count > 0) {
097: queryBuffer.append(", ");
098: }
099: queryBuffer
100: .append(queryData.columns[i].columnConf
101: .getAttribute("name"));
102: count++;
103: }
104: }
105:
106: queryBuffer.append(" FROM ").append(
107: table.getAttribute("name")).append(" WHERE ");
108: count = 0;
109: for (int i = 0; i < queryData.columns.length; i++) {
110: if (queryData.columns[i].isKey) {
111: if (count > 0) {
112: queryBuffer.append(" AND ");
113: }
114: queryBuffer.append(
115: queryData.columns[i].columnConf
116: .getAttribute("name")).append(
117: "= ?");
118: count++;
119: }
120: }
121:
122: queryData.queryString = queryBuffer.toString();
123:
124: this .cachedQueryData.put(lookUpKey, queryData);
125: }
126: }
127:
128: return queryData;
129: }
130:
131: /**
132: * Fetch all values for all key columns that are needed to do the
133: * database operation.
134: */
135: protected Object[][] getColumnValues(Configuration tableConf,
136: CacheHelper queryData, Map objectModel)
137: throws ConfigurationException, ServiceException {
138:
139: Object[][] columnValues = new Object[queryData.columns.length][];
140: for (int i = 0; i < queryData.columns.length; i++) {
141: if (queryData.columns[i].isKey) {
142: columnValues[i] = this .getColumnValue(tableConf,
143: queryData.columns[i], objectModel);
144: } else {
145: // columnValues[i] = new Object[1]; // this should not be needed
146: }
147: }
148: return columnValues;
149: }
150:
151: /**
152: * set all necessary ?s and execute the query
153: */
154: protected int processRow(Map objectModel, Connection conn,
155: PreparedStatement statement, String outputMode,
156: Configuration table, CacheHelper queryData,
157: Object[][] columnValues, int rowIndex, Map results)
158: throws SQLException, ConfigurationException, Exception {
159:
160: int currentIndex = 1;
161:
162: // ordering is different for SELECT just needs keys
163: for (int i = 0; i < queryData.columns.length; i++) {
164: Column col = queryData.columns[i];
165: if (col.isKey) {
166: this .setColumn(objectModel, outputMode, results, table,
167: col.columnConf, rowIndex,
168: columnValues[i][(col.isSet ? rowIndex : 0)],
169: statement, currentIndex);
170: currentIndex++;
171: }
172: }
173: statement.execute();
174: // retrieve values
175: ResultSet resultset = statement.getResultSet();
176: rowIndex = 0;
177: while (resultset.next()) {
178: for (int i = 0; i < queryData.columns.length; i++) {
179: if (!queryData.columns[i].isKey) {
180: Object value = JDBCTypeConversions.getColumn(
181: resultset, queryData.columns[i].columnConf);
182: this .setOutput(objectModel, outputMode, results,
183: table, queryData.columns[i].columnConf,
184: rowIndex, value);
185: }
186: }
187: rowIndex++;
188: }
189: if (rowIndex == 0) {
190: results = EMPTY_MAP;
191: }
192: return rowIndex;
193: }
194:
195: }
|