blob: d06e347e5cd6d7bdcf515f3aeec626b2e911eca6 [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 java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import oracle.jdbc.OracleResultSet;
import oracle.sql.BLOB;
import oracle.sql.CLOB;
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.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.cocoon.util.ImageProperties;
import org.apache.cocoon.util.ImageUtils;
/**
* Add a record in a database. This Action assumes that there is
* only one table at a time to update.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
* @version CVS $Id$
*/
public class OraAddAction extends DatabaseAddAction {
private static final Map selectLOBStatements = new HashMap();
/**
* Add a record to 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;
try {
Configuration conf = this.getConfiguration(param.getParameter("descriptor", null));
String query = this.getAddQuery(conf);
datasource = this.getDataSource(conf);
conn = datasource.getConnection();
Request request = ObjectModelHelper.getRequest(objectModel);
if (conn.getAutoCommit()) {
conn.setAutoCommit(false);
}
PreparedStatement statement = conn.prepareStatement(query);
getLogger().info(query);
Configuration[] keys = conf.getChild("table").getChild("keys").getChildren("key");
Configuration[] values = conf.getChild("table").getChild("values").getChildren("value");
currentIndex = 1;
// Insert the keys into the query
for (int i = 0; i < keys.length; i++) {
String mode = keys[i].getAttribute("mode", "automatic");
if ("manual".equals(mode)) {
String selectQuery = this.getSelectQuery(keys[i]);
Statement stmt =null;
ResultSet set = null;
try {
stmt = conn.createStatement();
set = stmt.executeQuery(selectQuery);
set.next();
int value = set.getInt("maxid") + 1;
statement.setInt(currentIndex, value);
request.setAttribute(keys[i].getAttribute("param"), String.valueOf(value));
} catch (SQLException sqle){
getLogger().warn("There was an error retrieving the next key while inserting on the database", sqle);
throw sqle;
} finally {
set.close();
stmt.close();
currentIndex++;
}
} else if ("form".equals(mode)) {
String parameter = keys[i].getAttribute("param");
request.setAttribute(parameter, request.getParameter(parameter));
this.setColumn(statement, currentIndex, request, keys[i]);
currentIndex++;
}
}
// insert the values into the query
for (int i = 0; i < values.length; i++) {
String type = values[i].getAttribute("type");
String parameter = values[i].getAttribute("param");
if (type.equals("image")) {
File binaryFile = (File) request.get(parameter);
Parameters iparam = new Parameters();
iparam.setParameter("image-size", String.valueOf(binaryFile.length()));
ImageProperties prop = ImageUtils.getImageProperties(binaryFile);
iparam.setParameter("image-width", Integer.toString(prop.width));
iparam.setParameter("image-height", Integer.toString(prop.height));
synchronized (this.files) {
this.files.put(binaryFile, param);
}
}
if (! this.isLargeObject(type)) {
this.setColumn(statement, currentIndex, request, values[i]);
currentIndex++;
}
}
statement.execute();
statement.close();
query = this.getSelectLOBQuery(conf);
// Process the large objects if they exist
if (query != null) {
PreparedStatement LOBstatement = conn.prepareStatement(query);
getLogger().info(query);
if (keys.length > 0) {
currentIndex = 1;
for (int i = 0; i < keys.length; i++) {
this.setColumn(LOBstatement, currentIndex, request, keys[i]);
currentIndex++;
}
}
OracleResultSet set = (OracleResultSet) LOBstatement.executeQuery();
if (set.next()) {
int index = 0;
for (int i = 0; i < values.length; i++) {
String type = values[i].getAttribute("type", "");
if (this.isLargeObject(type)) {
Object attr = request.get(values[i].getAttribute("param"));
int length = -1;
InputStream stream = null;
OutputStream output = null;
int bufSize = 1024;
index++;
if (type.equals("ascii")) {
CLOB ascii = set.getCLOB(index);
if (attr instanceof File) {
File asciiFile = (File) attr;
stream = new BufferedInputStream(new FileInputStream(asciiFile));
} else {
String asciiText = (String) attr;
stream = new BufferedInputStream(new ByteArrayInputStream(asciiText.getBytes()));
}
output = new BufferedOutputStream(ascii.getAsciiOutputStream());
bufSize = ascii.getBufferSize();
} else {
BLOB binary = set.getBLOB(index);
File binaryFile = (File) attr;
stream = new BufferedInputStream(new FileInputStream(binaryFile));
length = (int) binaryFile.length();
output = new BufferedOutputStream(binary.getBinaryOutputStream());
bufSize = binary.getBufferSize();
}
byte[] buffer = new byte[bufSize];
while ((length = stream.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
stream.close();
output.close();
}
}
}
set.close();
set.getStatement().close();
}
conn.commit();
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException se) {
getLogger().debug("There was an error rolling back the transaction", se);
}
}
throw new ProcessingException("Could not add record :position = " + (currentIndex - 1), 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.
*/
protected final String getAddQuery(Configuration conf) throws ConfigurationException {
String query = null;
synchronized (DatabaseAddAction.addStatements) {
query = (String) DatabaseAddAction.addStatements.get(conf);
if (query == null) {
Configuration table = conf.getChild("table");
Configuration[] values = table.getChild("values").getChildren("value");
Configuration[] keys = table.getChild("keys").getChildren("key");
StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
queryBuffer.append(table.getAttribute("name"));
queryBuffer.append(" (");
int numKeys = 0;
for (int i = 0; i < keys.length; i++) {
String mode = keys[i].getAttribute("mode", "automatic");
if (numKeys > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(keys[i].getAttribute("dbcol"));
if ("manual".equals(mode)) {
this.setSelectQuery(table.getAttribute("name"), keys[i]);
}
numKeys++;
}
for (int i = 0; i < values.length; i++) {
if ((numKeys + i) > 0) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
}
queryBuffer.append(") VALUES (");
numKeys = 0;
ArrayList sequences = new ArrayList();
for (int i = 0; i < keys.length; i++) {
if (numKeys > 0) queryBuffer.append(", ");
if ("automatic".equals(keys[i].getAttribute("mode", "automatic"))) {
String sequence = keys[i].getAttribute("sequence", "");
queryBuffer.append(sequence);
if (sequences.contains(sequence)) {
queryBuffer.append(".CURRVAL");
} else {
sequences.add(sequence);
queryBuffer.append(".NEXTVAL");
}
numKeys++;
} else {
queryBuffer.append("?");
numKeys++;
}
}
for (int i = 0; i < values.length; i++) {
if ((numKeys + i) > 0) {
queryBuffer.append(", ");
}
if (this.isLargeObject(values[i].getAttribute("type"))) {
if (values[i].getAttribute("type").equals("ascii")) {
queryBuffer.append("empty_clob()");
} else {
queryBuffer.append("empty_blob()");
}
} else {
queryBuffer.append("?");
}
}
queryBuffer.append(")");
query = queryBuffer.toString();
DatabaseAddAction.addStatements.put(conf, query);
}
}
if ("".equals(query)) return null;
return query;
}
/**
* 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 getSelectLOBQuery (Configuration conf)
throws ConfigurationException {
String query = null;
synchronized (OraAddAction.selectLOBStatements) {
query = (String) OraAddAction.selectLOBStatements.get(conf);
// executes only if query is null.
if (query == null) {
StringBuffer queryBuffer = new StringBuffer("SELECT ");
Configuration table = conf.getChild("table");
Configuration[] values = table.getChild("values").getChildren("value");
Configuration[] keys = table.getChild("keys").getChildren("key");
int numLobs = 0;
// Add the values to the query
for (int i = 0; i < values.length; i++) {
if (this.isLargeObject(values[i].getAttribute("type"))) {
numLobs++;
if (numLobs > 1) {
queryBuffer.append(", ");
}
queryBuffer.append(values[i].getAttribute("dbcol"));
}
}
if (numLobs < 1) {
// if query is set to "", then the Action won't
// try to process it again.
query = "";
OraAddAction.selectLOBStatements.put(conf, query);
return null;
}
queryBuffer.append(" FROM ").append(table.getAttribute("name"));
// Process the WHERE clause
if (keys.length > 0) {
queryBuffer.append(" WHERE ");
// Add the keys to the query
queryBuffer.append(buildList(keys, " AND "));
}
query = queryBuffer.toString().trim();
OraAddAction.selectLOBStatements.put(conf, query);
}
}
return ("".equals(query)) ? null : query;
}
}