Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 2018 invoked from network); 13 Mar 2007 09:59:52 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 13 Mar 2007 09:59:52 -0000 Received: (qmail 71958 invoked by uid 500); 13 Mar 2007 10:00:01 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 71928 invoked by uid 500); 13 Mar 2007 10:00:00 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 71914 invoked by uid 99); 13 Mar 2007 10:00:00 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 13 Mar 2007 03:00:00 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 13 Mar 2007 02:59:51 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 505431A9838; Tue, 13 Mar 2007 02:59:31 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r517625 - /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java Date: Tue, 13 Mar 2007 09:59:31 -0000 To: commits@jackrabbit.apache.org From: tripod@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070313095931.505431A9838@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: tripod Date: Tue Mar 13 02:59:30 2007 New Revision: 517625 URL: http://svn.apache.org/viewvc?view=rev&rev=517625 Log: JCR-786 OracleBundlePersistenceManager needs special blob handling for JDBC drivers prior to oracle 10 Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java (with props) Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java?view=auto&rev=517625 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java Tue Mar 13 02:59:30 2007 @@ -0,0 +1,284 @@ +/* + * 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.jackrabbit.core.persistence.bundle; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.jackrabbit.core.persistence.PMContext; +import org.apache.jackrabbit.core.persistence.bundle.util.NodePropBundle; +import org.apache.jackrabbit.core.persistence.util.Serializer; +import org.apache.jackrabbit.core.state.ItemStateException; +import org.apache.jackrabbit.core.state.NodeReferences; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.sql.Blob; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * OracleLegacyPersistenceManager provides support for Oracle jdbc + * drivers prior to version 10 which require special handling of BLOB data. + *

+ * Configuration:
+ *

    + *
  • <param name="{@link #setBundleCacheSize(String) bundleCacheSize}" value="8"/> + *
  • <param name="{@link #setConsistencyCheck(String) consistencyCheck}" value="false"/> + *
  • <param name="{@link #setMinBlobSize(String) minBlobSize}" value="16384"/> + *
  • <param name="{@link #setDriver(String) driver}" value="oracle.jdbc.OracleDriverr"/> + *
  • <param name="{@link #setUrl(String) url}" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/> + *
  • <param name="{@link #setUser(String) user}" value="crx"/> + *
  • <param name="{@link #setPassword(String) password}" value="crx"/> + *
  • <param name="{@link #setSchema(String) schema}" value="oracle"/> + *
  • <param name="{@link #setSchemaObjectPrefix(String) schemaObjectPrefix}" value="${wsp.name}_"/> + *
  • <param name="{@link #setErrorHandling(String) errorHandling}" value=""/> + *
+ */ +public class Oracle9PersistenceManager extends OraclePersistenceManager { + + /** + * the cvs/svn id + */ + static final String CVS_ID = "$URL$ $Rev$ $Date$"; + + /** + * the default logger + */ + private static Logger log = LoggerFactory.getLogger(Oracle9PersistenceManager.class); + + private Class blobClass; + private Integer DURATION_SESSION_CONSTANT; + private Integer MODE_READWRITE_CONSTANT; + + public Oracle9PersistenceManager() { + } + + //-----------------------------------< OraclePersistenceManager overrides > + /** + * {@inheritDoc} + *

+ * Retrieve the oracle.sql.BLOB class via reflection, and + * initialize the values for the DURATION_SESSION and + * MODE_READWRITE constants defined there. + * + * @see oracle.sql.BLOB#DURATION_SESSION + * @see oracle.sql.BLOB#MODE_READWRITE + */ + public void init(PMContext context) throws Exception { + super.init(context); + + // initialize oracle.sql.BLOB class & constants + + // use the Connection object for using the exact same + // class loader that the Oracle driver was loaded with + blobClass = con.getClass().getClassLoader().loadClass("oracle.sql.BLOB"); + DURATION_SESSION_CONSTANT = + new Integer(blobClass.getField("DURATION_SESSION").getInt(null)); + MODE_READWRITE_CONSTANT = + new Integer(blobClass.getField("MODE_READWRITE").getInt(null)); + } + + /** + * @inheritDoc + */ + protected BundleDbPersistenceManager.CloseableBLOBStore createDBBlobStore(PMContext context) throws Exception { + return new OracleBLOBStore(); + } + + /** + * @inheritDoc + */ + protected synchronized void storeBundle(NodePropBundle bundle) + throws ItemStateException { + PreparedStatement stmt = null; + Blob blob = null; + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(INITIAL_BUFFER_SIZE); + DataOutputStream dout = new DataOutputStream(out); + binding.writeBundle(dout, bundle); + dout.close(); + + if (bundle.isNew()) { + stmt = bundleInsert; + } else { + stmt = bundleUpdate; + } + blob = createTemporaryBlob(new ByteArrayInputStream(out.toByteArray())); + stmt.setBlob(1, blob); + stmt.setBytes(2, bundle.getId().getUUID().getRawBytes()); + stmt.execute(); + } catch (Exception e) { + String msg = "failed to write bundle: " + bundle.getId(); + log.error(msg, e); + throw new ItemStateException(msg, e); + } finally { + resetStatement(stmt); + if (blob != null) { + try { + freeTemporaryBlob(blob); + } catch (Exception e1) { + } + } + } + } + + /** + * @inheritDoc + */ + public synchronized void store(NodeReferences refs) + throws ItemStateException { + if (!initialized) { + throw new IllegalStateException("not initialized"); + } + + PreparedStatement stmt = null; + Blob blob = null; + try { + // check if insert or update + if (exists(refs.getId())) { + stmt = nodeReferenceUpdate; + } else { + stmt = nodeReferenceInsert; + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(INITIAL_BUFFER_SIZE); + // serialize references + Serializer.serialize(refs, out); + + // we are synchronized on this instance, therefore we do not + // not have to additionally synchronize on the preparedStatement + + blob = createTemporaryBlob(new ByteArrayInputStream(out.toByteArray())); + stmt.setBlob(1, blob); + stmt.setBytes(2, refs.getTargetId().getUUID().getRawBytes()); + stmt.execute(); + + // there's no need to close a ByteArrayOutputStream + //out.close(); + } catch (Exception e) { + String msg = "failed to write property state: " + refs.getTargetId(); + log.error(msg, e); + throw new ItemStateException(msg, e); + } finally { + resetStatement(stmt); + if (blob != null) { + try { + freeTemporaryBlob(blob); + } catch (Exception e1) { + } + } + } + } + + //----------------------------------------< oracle-specific blob handling > + /** + * Creates a temporary oracle.sql.BLOB instance via reflection and spools + * the contents of the specified stream. + */ + protected Blob createTemporaryBlob(InputStream in) throws Exception { + /* + BLOB blob = BLOB.createTemporary(con, false, BLOB.DURATION_SESSION); + blob.open(BLOB.MODE_READWRITE); + OutputStream out = blob.getBinaryOutputStream(); + ... + out.flush(); + out.close(); + blob.close(); + return blob; + */ + Method createTemporary = blobClass.getMethod("createTemporary", + new Class[]{Connection.class, Boolean.TYPE, Integer.TYPE}); + Object blob = createTemporary.invoke(null, + new Object[]{con, Boolean.FALSE, DURATION_SESSION_CONSTANT}); + Method open = blobClass.getMethod("open", new Class[]{Integer.TYPE}); + open.invoke(blob, new Object[]{MODE_READWRITE_CONSTANT}); + Method getBinaryOutputStream = blobClass.getMethod("getBinaryOutputStream", new Class[0]); + OutputStream out = (OutputStream) getBinaryOutputStream.invoke(blob, null); + try { + int read; + byte[] buf = new byte[8192]; + while ((read = in.read(buf, 0, buf.length)) > -1) { + out.write(buf, 0, read); + } + } finally { + try { + out.flush(); + } catch (IOException ioe) { + } + out.close(); + } + Method close = blobClass.getMethod("close", new Class[0]); + close.invoke(blob, null); + return (Blob) blob; + } + + /** + * Frees a temporary oracle.sql.BLOB instance via reflection. + */ + protected void freeTemporaryBlob(Object blob) throws Exception { + // blob.freeTemporary(); + Method freeTemporary = blobClass.getMethod("freeTemporary", new Class[0]); + freeTemporary.invoke(blob, null); + } + + //--------------------------------------------------------< inner classes > + class OracleBLOBStore extends DbBlobStore { + + public OracleBLOBStore() throws SQLException { + } + + /** + * {@inheritDoc} + */ + public synchronized void put(String blobId, InputStream in, long size) + throws Exception { + PreparedStatement stmt = blobSelectExist; + Blob blob = null; + try { + stmt.setString(1, blobId); + stmt.execute(); + ResultSet rs = stmt.getResultSet(); + // a BLOB exists if the result has at least one entry + boolean exists = rs.next(); + resetStatement(stmt); + closeResultSet(rs); + + stmt = (exists) ? blobUpdate : blobInsert; + + blob = createTemporaryBlob(in); + stmt.setBlob(1, blob); + stmt.setString(2, blobId); + stmt.executeUpdate(); + } finally { + resetStatement(stmt); + if (blob != null) { + try { + freeTemporaryBlob(blob); + } catch (Exception e1) { + } + } + } + } + } +} Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/Oracle9PersistenceManager.java ------------------------------------------------------------------------------ svn:keywords = author date id revision url rev