blob: 1f3ccd591021b5910463938367c417836a31c1e2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.acting;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.commons.lang.StringUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Select a record from a database. If request parameters are present,
* their values are used to populate request attributes. Otherwise,
* values from database are used.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
* @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
* @version CVS $Id$
*/
public class DatabaseSelectAction extends AbstractDatabaseAction implements ThreadSafe {
private static final Map selectStatements = new HashMap();
/**
* Select a record from the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters param) throws Exception {
DataSourceComponent datasource = null;
Connection conn = null;
int currentIndex = 0;
// read global parameter settings
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
if (this.settings.containsKey("reloadable"))
reloadable = Boolean.valueOf((String) this.settings.get("reloadable")).booleanValue();
// read local parameter settings
try {
Configuration conf =
this.getConfiguration(param.getParameter("descriptor", (String) this.settings.get("descriptor")),
resolver,
param.getParameterAsBoolean("reloadable",reloadable));
Request request = ObjectModelHelper.getRequest(objectModel);
Configuration[] keys = conf.getChild("table").getChild("keys").getChildren("key");
Configuration[] values = conf.getChild("table").getChild("values").getChildren("value");
PreparedStatement statement = null;
ResultSet rset = null;
boolean result = false;
for (int i = 0; i < keys.length; i++) {
final String parameter = keys[i].getAttribute("param");
Object value = request.getParameter(parameter);
if (StringUtils.isEmpty((String)value)) {
if (statement == null) {
final String query = this.getSelectQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
statement = conn.prepareStatement(query);
currentIndex = 1;
for (int j = 0; j < keys.length; j++, currentIndex++) {
this.setColumn(statement, currentIndex, request, keys[j]);
}
rset = statement.executeQuery();
result = rset.next();
}
if (result) {
value = this.getColumn(rset, request, keys[i]);
}
}
if (value != null) {
request.setAttribute(parameter, value.toString());
}
}
for (int i = 0; i < values.length; i++) {
final String parameter = values[i].getAttribute("param");
Object value = request.getParameter(parameter);
if (StringUtils.isEmpty((String)value)) {
if (statement == null) {
final String query = this.getSelectQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
statement = conn.prepareStatement(query);
currentIndex = 1;
for (int j = 0; j < keys.length; j++, currentIndex++) {
this.setColumn(statement, currentIndex, request, keys[j]);
}
rset = statement.executeQuery();
result = rset.next();
}
if (result) {
value = this.getColumn(rset, request, values[i]);
}
}
if (value != null) {
request.setAttribute(parameter, value.toString());
}
}
if(statement != null) {
statement.close();
}
return EMPTY_MAP;
} catch (Exception e) {
throw new ProcessingException("Could not prepare statement :position = " + currentIndex, e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException sqe) {
getLogger().warn("There was an error closing the datasource", sqe);
}
}
if (datasource != null) {
this.dbselector.release(datasource);
}
}
// Result is empty map or exception. No null.
}
/**
* Get the String representation of the PreparedStatement. This is
* mapped to the Configuration object itself, so if it doesn't exist,
* it will be created.
*/
protected String getSelectQuery(Configuration conf) throws ConfigurationException {
String query = null;
synchronized (DatabaseSelectAction.selectStatements) {
query = (String)DatabaseSelectAction.selectStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] keys = table.getChild("keys").getChildren("key");
Configuration[] values = table.getChild("values").getChildren("value");
StringBuffer queryBuffer = new StringBuffer("SELECT ");
queryBuffer.append(buildList(keys, 0));
queryBuffer.append(buildList(values, keys.length));
queryBuffer.append(" FROM ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" WHERE ");
queryBuffer.append(buildList(keys, " AND "));
query = queryBuffer.toString();
DatabaseSelectAction.selectStatements.put(conf, query);
}
}
return query;
}
}