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 java.io.BufferedInputStream;
020: import java.io.BufferedOutputStream;
021: import java.io.ByteArrayInputStream;
022: import java.io.File;
023: import java.io.FileInputStream;
024: import java.io.InputStream;
025: import java.io.OutputStream;
026: import java.sql.Connection;
027: import java.sql.PreparedStatement;
028: import java.sql.ResultSet;
029: import java.sql.SQLException;
030: import java.sql.Statement;
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.Map;
034:
035: import oracle.jdbc.OracleResultSet;
036: import oracle.sql.BLOB;
037: import oracle.sql.CLOB;
038:
039: import org.apache.avalon.excalibur.datasource.DataSourceComponent;
040: import org.apache.avalon.framework.configuration.Configuration;
041: import org.apache.avalon.framework.configuration.ConfigurationException;
042: import org.apache.avalon.framework.parameters.Parameters;
043: import org.apache.cocoon.ProcessingException;
044: import org.apache.cocoon.environment.ObjectModelHelper;
045: import org.apache.cocoon.environment.Redirector;
046: import org.apache.cocoon.environment.Request;
047: import org.apache.cocoon.environment.SourceResolver;
048: import org.apache.cocoon.util.ImageProperties;
049: import org.apache.cocoon.util.ImageUtils;
050:
051: /**
052: * Add a record in a database. This Action assumes that there is
053: * only one table at a time to update.
054: *
055: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
056: * @version CVS $Id: OraAddAction.java 433543 2006-08-22 06:22:54Z crossley $
057: */
058: public class OraAddAction extends DatabaseAddAction {
059: private static final Map selectLOBStatements = new HashMap();
060:
061: /**
062: * Add a record to the database. This action assumes that
063: * the file referenced by the "descriptor" parameter conforms
064: * to the AbstractDatabaseAction specifications.
065: */
066: public Map act(Redirector redirector, SourceResolver resolver,
067: Map objectModel, String source, Parameters param)
068: throws Exception {
069: DataSourceComponent datasource = null;
070: Connection conn = null;
071: int currentIndex = 0;
072:
073: try {
074: Configuration conf = this .getConfiguration(param
075: .getParameter("descriptor", null));
076: String query = this .getAddQuery(conf);
077:
078: datasource = this .getDataSource(conf);
079: conn = datasource.getConnection();
080: Request request = ObjectModelHelper.getRequest(objectModel);
081:
082: if (conn.getAutoCommit()) {
083: conn.setAutoCommit(false);
084: }
085:
086: PreparedStatement statement = conn.prepareStatement(query);
087: getLogger().info(query);
088:
089: Configuration[] keys = conf.getChild("table").getChild(
090: "keys").getChildren("key");
091: Configuration[] values = conf.getChild("table").getChild(
092: "values").getChildren("value");
093: currentIndex = 1;
094:
095: // Insert the keys into the query
096: for (int i = 0; i < keys.length; i++) {
097: String mode = keys[i].getAttribute("mode", "automatic");
098:
099: if ("manual".equals(mode)) {
100: String selectQuery = this .getSelectQuery(keys[i]);
101: Statement stmt = null;
102: ResultSet set = null;
103: try {
104: stmt = conn.createStatement();
105: set = stmt.executeQuery(selectQuery);
106: set.next();
107: int value = set.getInt("maxid") + 1;
108: statement.setInt(currentIndex, value);
109: request.setAttribute(keys[i]
110: .getAttribute("param"), String
111: .valueOf(value));
112: } catch (SQLException sqle) {
113: getLogger()
114: .warn(
115: "There was an error retrieving the next key while inserting on the database",
116: sqle);
117: throw sqle;
118: } finally {
119: set.close();
120: stmt.close();
121: currentIndex++;
122: }
123: } else if ("form".equals(mode)) {
124: String parameter = keys[i].getAttribute("param");
125: request.setAttribute(parameter, request
126: .getParameter(parameter));
127: this .setColumn(statement, currentIndex, request,
128: keys[i]);
129: currentIndex++;
130: }
131: }
132:
133: // insert the values into the query
134: for (int i = 0; i < values.length; i++) {
135: String type = values[i].getAttribute("type");
136: String parameter = values[i].getAttribute("param");
137:
138: if (type.equals("image")) {
139: File binaryFile = (File) request.get(parameter);
140: Parameters iparam = new Parameters();
141:
142: iparam.setParameter("image-size", String
143: .valueOf(binaryFile.length()));
144:
145: ImageProperties prop = ImageUtils
146: .getImageProperties(binaryFile);
147: iparam.setParameter("image-width", Integer
148: .toString(prop.width));
149: iparam.setParameter("image-height", Integer
150: .toString(prop.height));
151:
152: synchronized (this .files) {
153: this .files.put(binaryFile, param);
154: }
155: }
156:
157: if (!this .isLargeObject(type)) {
158: this .setColumn(statement, currentIndex, request,
159: values[i]);
160: currentIndex++;
161: }
162: }
163:
164: statement.execute();
165: statement.close();
166:
167: query = this .getSelectLOBQuery(conf);
168:
169: // Process the large objects if they exist
170: if (query != null) {
171: PreparedStatement LOBstatement = conn
172: .prepareStatement(query);
173: getLogger().info(query);
174:
175: if (keys.length > 0) {
176: currentIndex = 1;
177:
178: for (int i = 0; i < keys.length; i++) {
179: this .setColumn(LOBstatement, currentIndex,
180: request, keys[i]);
181: currentIndex++;
182: }
183: }
184:
185: OracleResultSet set = (OracleResultSet) LOBstatement
186: .executeQuery();
187:
188: if (set.next()) {
189: int index = 0;
190:
191: for (int i = 0; i < values.length; i++) {
192: String type = values[i]
193: .getAttribute("type", "");
194: if (this .isLargeObject(type)) {
195: Object attr = request.get(values[i]
196: .getAttribute("param"));
197: int length = -1;
198: InputStream stream = null;
199: OutputStream output = null;
200: int bufSize = 1024;
201:
202: index++;
203:
204: if (type.equals("ascii")) {
205: CLOB ascii = set.getCLOB(index);
206:
207: if (attr instanceof File) {
208: File asciiFile = (File) attr;
209: stream = new BufferedInputStream(
210: new FileInputStream(
211: asciiFile));
212: } else {
213: String asciiText = (String) attr;
214: stream = new BufferedInputStream(
215: new ByteArrayInputStream(
216: asciiText
217: .getBytes()));
218: }
219:
220: output = new BufferedOutputStream(ascii
221: .getAsciiOutputStream());
222: bufSize = ascii.getBufferSize();
223: } else {
224: BLOB binary = set.getBLOB(index);
225: File binaryFile = (File) attr;
226: stream = new BufferedInputStream(
227: new FileInputStream(binaryFile));
228: length = (int) binaryFile.length();
229:
230: output = new BufferedOutputStream(
231: binary.getBinaryOutputStream());
232: bufSize = binary.getBufferSize();
233: }
234:
235: byte[] buffer = new byte[bufSize];
236: while ((length = stream.read(buffer)) != -1) {
237: output.write(buffer, 0, length);
238: }
239:
240: stream.close();
241: output.close();
242: }
243: }
244: }
245:
246: set.close();
247: set.getStatement().close();
248: }
249:
250: conn.commit();
251: } catch (Exception e) {
252: if (conn != null) {
253: try {
254: conn.rollback();
255: } catch (SQLException se) {
256: getLogger()
257: .debug(
258: "There was an error rolling back the transaction",
259: se);
260: }
261: }
262:
263: throw new ProcessingException(
264: "Could not add record :position = "
265: + (currentIndex - 1), e);
266: } finally {
267: if (conn != null) {
268: try {
269: conn.close();
270: } catch (SQLException sqe) {
271: getLogger()
272: .warn(
273: "There was an error closing the datasource",
274: sqe);
275: }
276: }
277: if (datasource != null) {
278: this .dbselector.release(datasource);
279: }
280: }
281:
282: return null;
283: }
284:
285: /**
286: * Get the String representation of the PreparedStatement. This is
287: * mapped to the Configuration object itself, so if it doesn't exist,
288: * it will be created.
289: */
290: protected final String getAddQuery(Configuration conf)
291: throws ConfigurationException {
292: String query = null;
293:
294: synchronized (DatabaseAddAction.addStatements) {
295: query = (String) DatabaseAddAction.addStatements.get(conf);
296:
297: if (query == null) {
298: Configuration table = conf.getChild("table");
299: Configuration[] values = table.getChild("values")
300: .getChildren("value");
301: Configuration[] keys = table.getChild("keys")
302: .getChildren("key");
303:
304: StringBuffer queryBuffer = new StringBuffer(
305: "INSERT INTO ");
306: queryBuffer.append(table.getAttribute("name"));
307: queryBuffer.append(" (");
308:
309: int numKeys = 0;
310:
311: for (int i = 0; i < keys.length; i++) {
312: String mode = keys[i].getAttribute("mode",
313: "automatic");
314: if (numKeys > 0) {
315: queryBuffer.append(", ");
316: }
317:
318: queryBuffer.append(keys[i].getAttribute("dbcol"));
319:
320: if ("manual".equals(mode)) {
321: this .setSelectQuery(table.getAttribute("name"),
322: keys[i]);
323: }
324:
325: numKeys++;
326: }
327:
328: for (int i = 0; i < values.length; i++) {
329: if ((numKeys + i) > 0) {
330: queryBuffer.append(", ");
331: }
332:
333: queryBuffer.append(values[i].getAttribute("dbcol"));
334: }
335:
336: queryBuffer.append(") VALUES (");
337:
338: numKeys = 0;
339: ArrayList sequences = new ArrayList();
340:
341: for (int i = 0; i < keys.length; i++) {
342: if (numKeys > 0)
343: queryBuffer.append(", ");
344: if ("automatic".equals(keys[i].getAttribute("mode",
345: "automatic"))) {
346: String sequence = keys[i].getAttribute(
347: "sequence", "");
348: queryBuffer.append(sequence);
349:
350: if (sequences.contains(sequence)) {
351: queryBuffer.append(".CURRVAL");
352: } else {
353: sequences.add(sequence);
354: queryBuffer.append(".NEXTVAL");
355: }
356:
357: numKeys++;
358: } else {
359: queryBuffer.append("?");
360: numKeys++;
361: }
362: }
363:
364: for (int i = 0; i < values.length; i++) {
365: if ((numKeys + i) > 0) {
366: queryBuffer.append(", ");
367: }
368:
369: if (this .isLargeObject(values[i]
370: .getAttribute("type"))) {
371: if (values[i].getAttribute("type").equals(
372: "ascii")) {
373: queryBuffer.append("empty_clob()");
374: } else {
375: queryBuffer.append("empty_blob()");
376: }
377: } else {
378: queryBuffer.append("?");
379: }
380: }
381:
382: queryBuffer.append(")");
383:
384: query = queryBuffer.toString();
385:
386: DatabaseAddAction.addStatements.put(conf, query);
387: }
388: }
389:
390: if ("".equals(query))
391: return null;
392:
393: return query;
394: }
395:
396: /**
397: * Get the String representation of the PreparedStatement. This is
398: * mapped to the Configuration object itself, so if it doesn't exist,
399: * it will be created.
400: */
401: private final String getSelectLOBQuery(Configuration conf)
402: throws ConfigurationException {
403: String query = null;
404:
405: synchronized (OraAddAction.selectLOBStatements) {
406: query = (String) OraAddAction.selectLOBStatements.get(conf);
407:
408: // executes only if query is null.
409: if (query == null) {
410: StringBuffer queryBuffer = new StringBuffer("SELECT ");
411: Configuration table = conf.getChild("table");
412: Configuration[] values = table.getChild("values")
413: .getChildren("value");
414: Configuration[] keys = table.getChild("keys")
415: .getChildren("key");
416: int numLobs = 0;
417:
418: // Add the values to the query
419: for (int i = 0; i < values.length; i++) {
420: if (this .isLargeObject(values[i]
421: .getAttribute("type"))) {
422: numLobs++;
423: if (numLobs > 1) {
424: queryBuffer.append(", ");
425: }
426: queryBuffer.append(values[i]
427: .getAttribute("dbcol"));
428: }
429: }
430:
431: if (numLobs < 1) {
432: // if query is set to "", then the Action won't
433: // try to process it again.
434: query = "";
435: OraAddAction.selectLOBStatements.put(conf, query);
436: return null;
437: }
438:
439: queryBuffer.append(" FROM ").append(
440: table.getAttribute("name"));
441:
442: // Process the WHERE clause
443: if (keys.length > 0) {
444: queryBuffer.append(" WHERE ");
445: // Add the keys to the query
446: queryBuffer.append(buildList(keys, " AND "));
447: }
448: query = queryBuffer.toString().trim();
449: OraAddAction.selectLOBStatements.put(conf, query);
450: }
451: }
452: return ("".equals(query)) ? null : query;
453: }
454: }
|