blob: 3dc5e3bc9ac2e91a515cde8114ffb2d7bb5bb726 [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 java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Delete a record from a database. This Action assumes that all
* dependant data is either automatically cleaned up by cascading
* deletes, or that multiple instances of this action are being used
* in the correct order. In other words, it removes one record by
* the keys.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
* @version CVS $Id$
*/
public final class DatabaseDeleteAction extends AbstractDatabaseAction implements ThreadSafe {
private static final Map deleteStatements = new HashMap();
/**
* Delete a record from the database. This action assumes that
* the file referenced by the "descriptor" parameter conforms
* to the AbstractDatabaseAction specifications.
*/
public final 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));
String query = this.getDeleteQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request request = ObjectModelHelper.getRequest(objectModel);
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
PreparedStatement statement = conn.prepareStatement(query);
Configuration[] keys = conf.getChild("table").getChild("keys").getChildren("key");
for (int i = 0; i < keys.length; i++) {
this.setColumn(statement, i + 1, request, keys[i]);
}
int rows = statement.executeUpdate();
conn.commit();
statement.close();
if (rows > 0) {
request.setAttribute("rows", Integer.toString(rows));
return EMPTY_MAP;
}
} catch (Exception e) {
if (conn != null) {
conn.rollback();
}
throw new ProcessingException("Could not delete record :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);
}
}
return 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.
*/
private final String getDeleteQuery(Configuration conf) throws ConfigurationException {
String query = null;
synchronized (DatabaseDeleteAction.deleteStatements) {
query = (String) DatabaseDeleteAction.deleteStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] keys = table.getChild("keys").getChildren("key");
StringBuffer queryBuffer = new StringBuffer("DELETE FROM ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" WHERE ");
queryBuffer.append(buildList(keys, " AND "));
query = queryBuffer.toString();
DatabaseDeleteAction.deleteStatements.put(conf, query);
}
}
return query;
}
}