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:
031: import java.sql.Connection;
032: import java.sql.PreparedStatement;
033: import java.sql.SQLException;
034: import java.util.HashMap;
035: import java.util.Map;
036:
037: /**
038: * Delete a record from a database. This Action assumes that all
039: * dependant data is either automatically cleaned up by cascading
040: * deletes, or that multiple instances of this action are being used
041: * in the correct order. In other words, it removes one record by
042: * the keys.
043: *
044: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
045: * @version CVS $Id: DatabaseDeleteAction.java 433543 2006-08-22 06:22:54Z crossley $
046: */
047: public final class DatabaseDeleteAction extends AbstractDatabaseAction
048: implements ThreadSafe {
049: private static final Map deleteStatements = new HashMap();
050:
051: /**
052: * Delete a record from the database. This action assumes that
053: * the file referenced by the "descriptor" parameter conforms
054: * to the AbstractDatabaseAction specifications.
055: */
056: public final Map act(Redirector redirector,
057: SourceResolver resolver, Map objectModel, String source,
058: Parameters param) throws Exception {
059: DataSourceComponent datasource = null;
060: Connection conn = null;
061: int currentIndex = 0;
062:
063: // read global parameter settings
064: boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
065: if (this .settings.containsKey("reloadable"))
066: reloadable = Boolean.valueOf(
067: (String) this .settings.get("reloadable"))
068: .booleanValue();
069: // read local parameter settings
070: try {
071: Configuration conf = this .getConfiguration(param
072: .getParameter("descriptor", (String) this .settings
073: .get("descriptor")), resolver, param
074: .getParameterAsBoolean("reloadable", reloadable));
075:
076: String query = this .getDeleteQuery(conf);
077: datasource = this .getDataSource(conf);
078: conn = datasource.getConnection();
079: Request request = ObjectModelHelper.getRequest(objectModel);
080:
081: if (conn.getAutoCommit()) {
082: conn.setAutoCommit(false);
083: }
084:
085: PreparedStatement statement = conn.prepareStatement(query);
086:
087: Configuration[] keys = conf.getChild("table").getChild(
088: "keys").getChildren("key");
089:
090: for (int i = 0; i < keys.length; i++) {
091: this .setColumn(statement, i + 1, request, keys[i]);
092: }
093:
094: int rows = statement.executeUpdate();
095: conn.commit();
096: statement.close();
097:
098: if (rows > 0) {
099: request.setAttribute("rows", Integer.toString(rows));
100: return EMPTY_MAP;
101: }
102: } catch (Exception e) {
103: if (conn != null) {
104: conn.rollback();
105: }
106: throw new ProcessingException(
107: "Could not delete record :position = "
108: + currentIndex, e);
109: } finally {
110: if (conn != null) {
111: try {
112: conn.close();
113: } catch (SQLException sqe) {
114: getLogger()
115: .warn(
116: "There was an error closing the datasource",
117: sqe);
118: }
119: }
120: if (datasource != null) {
121: this .dbselector.release(datasource);
122: }
123: }
124: return null;
125: }
126:
127: /**
128: * Get the String representation of the PreparedStatement. This is
129: * mapped to the Configuration object itself, so if it doesn't exist,
130: * it will be created.
131: */
132: private final String getDeleteQuery(Configuration conf)
133: throws ConfigurationException {
134: String query = null;
135:
136: synchronized (DatabaseDeleteAction.deleteStatements) {
137: query = (String) DatabaseDeleteAction.deleteStatements
138: .get(conf);
139:
140: if (query == null) {
141: Configuration table = conf.getChild("table");
142: Configuration[] keys = table.getChild("keys")
143: .getChildren("key");
144:
145: StringBuffer queryBuffer = new StringBuffer(
146: "DELETE FROM ");
147: queryBuffer.append(table.getAttribute("name"));
148: queryBuffer.append(" WHERE ");
149: queryBuffer.append(buildList(keys, " AND "));
150: query = queryBuffer.toString();
151:
152: DatabaseDeleteAction.deleteStatements.put(conf, query);
153: }
154: }
155: return query;
156: }
157: }
|