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