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 org.apache.avalon.excalibur.datasource.DataSourceComponent;
020: import org.apache.avalon.framework.configuration.Configuration;
021: import org.apache.avalon.framework.configuration.ConfigurationException;
022: import org.apache.avalon.framework.parameters.Parameters;
023: import org.apache.avalon.framework.thread.ThreadSafe;
024: import org.apache.cocoon.Constants;
025: import org.apache.cocoon.ProcessingException;
026: import org.apache.cocoon.environment.ObjectModelHelper;
027: import org.apache.cocoon.environment.Redirector;
028: import org.apache.cocoon.environment.Request;
029: import org.apache.cocoon.environment.SourceResolver;
030: import org.apache.commons.lang.StringUtils;
031:
032: import java.sql.Connection;
033: import java.sql.PreparedStatement;
034: import java.sql.ResultSet;
035: import java.sql.SQLException;
036: import java.util.HashMap;
037: import java.util.Map;
038:
039: /**
040: * Select a record from a database. If request parameters are present,
041: * their values are used to populate request attributes. Otherwise,
042: * values from database are used.
043: *
044: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
045: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
046: * @version CVS $Id: DatabaseSelectAction.java 433543 2006-08-22 06:22:54Z crossley $
047: */
048: public class DatabaseSelectAction extends AbstractDatabaseAction
049: implements ThreadSafe {
050:
051: private static final Map selectStatements = new HashMap();
052:
053: /**
054: * Select a record from the database. This action assumes that
055: * the file referenced by the "descriptor" parameter conforms
056: * to the AbstractDatabaseAction specifications.
057: */
058: public Map act(Redirector redirector, SourceResolver resolver,
059: Map objectModel, String source, Parameters param)
060: throws Exception {
061: DataSourceComponent datasource = null;
062: Connection conn = null;
063: int currentIndex = 0;
064:
065: // read global parameter settings
066: boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
067: if (this .settings.containsKey("reloadable"))
068: reloadable = Boolean.valueOf(
069: (String) this .settings.get("reloadable"))
070: .booleanValue();
071: // read local parameter settings
072: try {
073: Configuration conf = this .getConfiguration(param
074: .getParameter("descriptor", (String) this .settings
075: .get("descriptor")), resolver, param
076: .getParameterAsBoolean("reloadable", reloadable));
077:
078: Request request = ObjectModelHelper.getRequest(objectModel);
079:
080: Configuration[] keys = conf.getChild("table").getChild(
081: "keys").getChildren("key");
082: Configuration[] values = conf.getChild("table").getChild(
083: "values").getChildren("value");
084:
085: PreparedStatement statement = null;
086: ResultSet rset = null;
087: boolean result = false;
088:
089: for (int i = 0; i < keys.length; i++) {
090: final String parameter = keys[i].getAttribute("param");
091: Object value = request.getParameter(parameter);
092: if (StringUtils.isEmpty((String) value)) {
093: if (statement == null) {
094: final String query = this .getSelectQuery(conf);
095: datasource = this .getDataSource(conf);
096: conn = datasource.getConnection();
097: statement = conn.prepareStatement(query);
098: currentIndex = 1;
099: for (int j = 0; j < keys.length; j++, currentIndex++) {
100: this .setColumn(statement, currentIndex,
101: request, keys[j]);
102: }
103: rset = statement.executeQuery();
104: result = rset.next();
105: }
106: if (result) {
107: value = this .getColumn(rset, request, keys[i]);
108: }
109: }
110: if (value != null) {
111: request.setAttribute(parameter, value.toString());
112: }
113: }
114:
115: for (int i = 0; i < values.length; i++) {
116: final String parameter = values[i]
117: .getAttribute("param");
118: Object value = request.getParameter(parameter);
119: if (StringUtils.isEmpty((String) value)) {
120: if (statement == null) {
121: final String query = this .getSelectQuery(conf);
122: datasource = this .getDataSource(conf);
123: conn = datasource.getConnection();
124: statement = conn.prepareStatement(query);
125: currentIndex = 1;
126: for (int j = 0; j < keys.length; j++, currentIndex++) {
127: this .setColumn(statement, currentIndex,
128: request, keys[j]);
129: }
130: rset = statement.executeQuery();
131: result = rset.next();
132: }
133: if (result) {
134: value = this
135: .getColumn(rset, request, values[i]);
136: }
137: }
138: if (value != null) {
139: request.setAttribute(parameter, value.toString());
140: }
141: }
142: if (statement != null) {
143: statement.close();
144: }
145: return EMPTY_MAP;
146: } catch (Exception e) {
147: throw new ProcessingException(
148: "Could not prepare statement :position = "
149: + currentIndex, e);
150: } finally {
151: if (conn != null) {
152: try {
153: conn.close();
154: } catch (SQLException sqe) {
155: getLogger()
156: .warn(
157: "There was an error closing the datasource",
158: sqe);
159: }
160: }
161: if (datasource != null) {
162: this .dbselector.release(datasource);
163: }
164: }
165:
166: // Result is empty map or exception. No null.
167: }
168:
169: /**
170: * Get the String representation of the PreparedStatement. This is
171: * mapped to the Configuration object itself, so if it doesn't exist,
172: * it will be created.
173: */
174: protected String getSelectQuery(Configuration conf)
175: throws ConfigurationException {
176: String query = null;
177:
178: synchronized (DatabaseSelectAction.selectStatements) {
179: query = (String) DatabaseSelectAction.selectStatements
180: .get(conf);
181:
182: if (query == null) {
183: Configuration table = conf.getChild("table");
184: Configuration[] keys = table.getChild("keys")
185: .getChildren("key");
186: Configuration[] values = table.getChild("values")
187: .getChildren("value");
188:
189: StringBuffer queryBuffer = new StringBuffer("SELECT ");
190: queryBuffer.append(buildList(keys, 0));
191: queryBuffer.append(buildList(values, keys.length));
192: queryBuffer.append(" FROM ");
193: queryBuffer.append(table.getAttribute("name"));
194:
195: queryBuffer.append(" WHERE ");
196: queryBuffer.append(buildList(keys, " AND "));
197: query = queryBuffer.toString();
198:
199: DatabaseSelectAction.selectStatements.put(conf, query);
200: }
201: }
202: return query;
203: }
204: }
|