Return-Path: Delivered-To: apmail-db-ojb-dev-archive@www.apache.org Received: (qmail 95216 invoked from network); 1 May 2006 23:11:28 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 1 May 2006 23:11:28 -0000 Received: (qmail 90554 invoked by uid 500); 1 May 2006 23:11:19 -0000 Delivered-To: apmail-db-ojb-dev-archive@db.apache.org Received: (qmail 90510 invoked by uid 500); 1 May 2006 23:11:19 -0000 Mailing-List: contact ojb-dev-help@db.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "OJB Developers List" Reply-To: "OJB Developers List" Delivered-To: mailing list ojb-dev@db.apache.org Received: (qmail 90499 invoked by uid 500); 1 May 2006 23:11:18 -0000 Received: (qmail 90496 invoked by uid 99); 1 May 2006 23:11:18 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 May 2006 16:11:18 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Mon, 01 May 2006 16:11:16 -0700 Received: (qmail 94517 invoked by uid 65534); 1 May 2006 23:10:55 -0000 Message-ID: <20060501231055.94516.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r398725 - in /db/ojb/branches/OJB_1_0_RELEASE/src: java/org/apache/ojb/broker/lob/ test/org/apache/ojb/broker/lob/ Date: Mon, 01 May 2006 23:10:52 -0000 To: ojb-commits@db.apache.org From: arminw@apache.org X-Mailer: svnmailer-1.0.8 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: arminw Date: Mon May 1 16:10:50 2006 New Revision: 398725 URL: http://svn.apache.org/viewcvs?rev=398725&view=rev Log: initial, LOB support Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobHandle.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobImpl.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobHandle.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobImpl.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/InactiveLobException.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/Lob.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobException.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHandle.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelper.java db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelperImpl.java db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/lob/ db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/lob/LOBTest.java Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobHandle.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobHandle.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobHandle.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobHandle.java Mon May 1 16:10:50 2006 @@ -0,0 +1,115 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.Blob; +import java.sql.SQLException; + +import org.apache.ojb.broker.PersistenceBroker; + +/** + * This class is a wrapper for {@link java.sql.Blob} objects. + * + * @version $Id: $ + */ +public class BlobHandle extends LobHandle implements Blob +{ + private Blob blob; + + BlobHandle(PersistenceBroker broker, Blob blob) + { + super(broker); + this.blob = blob; + if(blob instanceof Lob) + { + setTransient(true); + } + } + + protected void txFail() + { + super.txFail(); + if(!isTransient()) this.blob = null; + } + + protected void txSuccess() + { + super.txSuccess(); + this.blob = null; + } + + protected void inactivate() + { + super.inactivate(); + if(!isTransient()) this.blob = null; + } + + public long length() throws SQLException + { + checkActive(); + return blob.length(); + } + + public void truncate(long len) throws SQLException + { + checkActive(); + blob.truncate(len); + } + + public byte[] getBytes(long pos, int length) throws SQLException + { + checkActive(); + return blob.getBytes(pos, length); + } + + public int setBytes(long pos, byte[] bytes) throws SQLException + { + checkActive(); + return blob.setBytes(pos, bytes); + } + + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException + { + checkActive(); + return blob.setBytes(pos, bytes, offset, len); + } + + public long position(byte pattern[], long start) throws SQLException + { + checkActive(); + return blob.position(pattern, start); + } + + public InputStream getBinaryStream() throws SQLException + { + checkActive(); + return blob.getBinaryStream(); + } + + public OutputStream setBinaryStream(long pos) throws SQLException + { + checkActive(); + return blob.setBinaryStream(pos); + } + + public long position(Blob pattern, long start) throws SQLException + { + checkActive(); + return blob.position(pattern, start); + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobImpl.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobImpl.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobImpl.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/BlobImpl.java Mon May 1 16:10:50 2006 @@ -0,0 +1,181 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2004 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.sql.Blob; +import java.sql.SQLException; + +import org.apache.commons.lang.ArrayUtils; + +/** + * This class is OJB's implementation of the {@link java.sql.Blob} interface. + * + * @version $Id: $ + */ +class BlobImpl implements Blob, Lob, Serializable +{ + private byte[] bytes = new byte[]{}; + private transient InputStream in; + + public BlobImpl() + { + } + + public BlobImpl(byte[] value) + { + if(value != null) this.bytes = value; + } + + public BlobImpl(InputStream in) + { + this.in = in; + } + + private void checkMethod() + { + if(in != null) + { + throw new UnsupportedOperationException("Unsupported method when using this Blob implementation with InputStream"); + } + } + + public byte[] getBytes() + { + return bytes; + } + + public byte[] getBytes(long pos, int length) throws SQLException + { + checkMethod(); + pos--; + return ArrayUtils.subarray(bytes, (int) pos, (int) (pos + length)); + } + + public int setBytes(long pos, byte[] bytes) throws SQLException + { + return setBytes(pos, bytes, 1, bytes.length); + } + + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException + { + checkMethod(); + offset--; + OJBStream out = prepareStream(pos); + out.write(bytes, offset, len); + try + { + out.close(); + } + catch(IOException e) + { + throw new LobException("Unexpected failure while write bytes", e); + } + return len; + } + + public InputStream getBinaryStream() throws SQLException + { + if(in != null) return in; + else return new ByteArrayInputStream(bytes); + } + + public OutputStream setBinaryStream(long pos) throws SQLException + { + checkMethod(); + return prepareStream(pos); + } + + public OJBStream prepareStream(long pos) throws SQLException + { + if(pos < 1) + { + throw new IndexOutOfBoundsException("Invalid index: " + pos); + } + + OJBStream out = new OJBStream(this); + if(this.bytes.length > 0) out.write(this.bytes, 0, (int) --pos); + return out; + } + + public long length() throws SQLException + { + return in != null ? -1 : bytes.length; + } + + public long position(byte pattern[], long start) throws SQLException + { + throw new UnsupportedOperationException("Not supported method"); + } + + public long position(Blob pattern, long start) throws SQLException + { + throw new UnsupportedOperationException("Not supported method"); + } + + public void truncate(long len) throws SQLException + { + checkMethod(); + bytes = ArrayUtils.subarray(bytes, 0, (int) len); + } + + public void streamClosed(OJBStream out) + { + int streamSize = out.size(); + if(streamSize < this.bytes.length) + { + out.write(this.bytes, streamSize, this.bytes.length - streamSize); + } + this.bytes = out.toByteArray(); + } + +// public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException +// { +// byte[] array = (byte[]) in.readObject(); +// bytes.write(array); +// } +// +// public void writeExternal(ObjectOutput out) throws IOException +// { +// out.writeObject(bytes.toByteArray()); +// } + + static class OJBStream extends ByteArrayOutputStream + { + BlobImpl home; + + public OJBStream(BlobImpl home) + { + this.home = home; + } + + byte[] getBytes() + { + return buf; + } + + public void close() throws IOException + { + super.close(); + home.streamClosed(this); + } + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobHandle.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobHandle.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobHandle.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobHandle.java Mon May 1 16:10:50 2006 @@ -0,0 +1,129 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.sql.Clob; +import java.sql.SQLException; + +import org.apache.ojb.broker.PersistenceBroker; + +/** + * This class is a wrapper for {@link java.sql.Clob} objects. + * + * @version $Id: $ + */ +public class ClobHandle extends LobHandle implements Clob +{ + private Clob clob; + + ClobHandle(PersistenceBroker broker, Clob clob) + { + super(broker); + this.clob = clob; + if(clob instanceof Lob) + { + setTransient(true); + } + } + + protected void txFail() + { + super.txFail(); + if(!isTransient()) this.clob = null; + } + + protected void txSuccess() + { + super.txSuccess(); + this.clob = null; + } + + protected void inactivate() + { + super.inactivate(); + if(!isTransient()) this.clob = null; + } + + public long length() throws SQLException + { + checkActive(); + return clob.length(); + } + + public void truncate(long len) throws SQLException + { + checkActive(); + clob.truncate(len); + } + + public InputStream getAsciiStream() throws SQLException + { + checkActive(); + return clob.getAsciiStream(); + } + + public OutputStream setAsciiStream(long pos) throws SQLException + { + checkActive(); + return clob.setAsciiStream(pos); + } + + public Reader getCharacterStream() throws SQLException + { + checkActive(); + return clob.getCharacterStream(); + } + + public Writer setCharacterStream(long pos) throws SQLException + { + checkActive(); + return clob.setCharacterStream(pos); + } + + public String getSubString(long pos, int length) throws SQLException + { + checkActive(); + return clob.getSubString(pos, length); + } + + public int setString(long pos, String str) throws SQLException + { + checkActive(); + return clob.setString(pos, str); + } + + public int setString(long pos, String str, int offset, int len) throws SQLException + { + checkActive(); + return clob.setString(pos, str, offset, len); + } + + public long position(String searchstr, long start) throws SQLException + { + checkActive(); + return clob.position(searchstr, start); + } + + public long position(Clob searchstr, long start) throws SQLException + { + checkActive(); + return clob.position(searchstr, start); + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobImpl.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobImpl.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobImpl.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/ClobImpl.java Mon May 1 16:10:50 2006 @@ -0,0 +1,185 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.sql.Clob; +import java.sql.SQLException; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.ojb.broker.util.ReaderInputStream; + +/** + * This class is OJB's implementation of the {@link java.sql.Clob} interface. + * + * @version $Id: $ + */ +class ClobImpl implements Clob, Externalizable, Lob +{ + private transient StringWriter writer; + private transient Reader reader; + + public ClobImpl() + { + this.writer = new StringWriter(); + } + + public ClobImpl(String str) + { + this(); + if(str != null) writer.write(str); + } + + public ClobImpl(Reader reader) + { + this.reader = reader; + } + + private void checkMethod() + { + if(reader != null) + { + throw new UnsupportedOperationException("Unsupported method when using this Blob implementation with Reader"); + } + } + + protected StringWriter getWriter() + { + return writer; + } + + public InputStream getAsciiStream() throws SQLException + { + if(reader != null) + { + return new ReaderInputStream(reader); + } + else return new ByteArrayInputStream(getWriter().toString().getBytes()); + } + + public OutputStream setAsciiStream(long pos) throws SQLException + { + checkMethod(); + String str = getWriter().toString(); + byte[] bytes = str.getBytes(); + bytes = ArrayUtils.subarray(bytes, 0, (int) --pos); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try + { + bos.write(bytes); + } + catch(IOException e) + { + throw new SQLException("Can't write existing bytes: " + ExceptionUtils.getFullStackTrace(e)); + } + return bos; + } + + public Reader getCharacterStream() throws SQLException + { + if(reader != null) return reader; + return new StringReader(getWriter().toString()); + } + + public Writer setCharacterStream(long pos) throws SQLException + { + checkMethod(); + String result = getWriter().getBuffer().substring(0, (int) --pos); + writer = new StringWriter(); + writer.write(result); + return getWriter(); + } + + public String getSubString(long pos, int length) throws SQLException + { + checkMethod(); + pos--; + return getWriter().getBuffer().substring((int) pos, (int) (pos + length)); + } + + public int setString(long pos, String str) throws SQLException + { + checkMethod(); + return setString(pos, str, 0, str.length()); + } + + public int setString(long pos, String str, int offset, int len) throws SQLException + { + checkMethod(); + if(pos < 1) + { + throw new IndexOutOfBoundsException("Illegal start position: " + pos); + } + if(str == null) + { + throw new NullPointerException("Specified string is 'null'"); + } + pos--; + StringBuffer charBuf = this.writer.getBuffer(); + String replaceString = str.substring(offset, len); + charBuf.replace((int) pos, (int) (pos + replaceString.length()), replaceString); + return replaceString.length(); + } + + public long length() throws SQLException + { + return reader != null ? -1 : getWriter().getBuffer().length(); + } + + public long position(String searchstr, long start) throws SQLException + { + checkMethod(); + return getWriter().getBuffer().indexOf(searchstr, (int) --start); + } + + public long position(Clob searchstr, long start) throws SQLException + { + checkMethod(); + return getWriter().getBuffer().indexOf( + searchstr.getSubString(0, (int) searchstr.length()), (int) --start); + } + + public void truncate(long len) throws SQLException + { + checkMethod(); + String str = getWriter().getBuffer().substring(0, (int) len); + writer = new StringWriter(); + writer.write(str); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + String str = (String) in.readObject(); + writer.write(str); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + out.writeObject(writer.toString()); + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/InactiveLobException.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/InactiveLobException.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/InactiveLobException.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/InactiveLobException.java Mon May 1 16:10:50 2006 @@ -0,0 +1,43 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +/** + * Thrown if access or usage of current LOB object isn't valid. + * + * @version $Id: $ + */ +public class InactiveLobException extends LobException +{ + public InactiveLobException() + { + } + + public InactiveLobException(String msg) + { + super(msg); + } + + public InactiveLobException(Throwable cause) + { + super(cause); + } + + public InactiveLobException(String msg, Throwable cause) + { + super(msg, cause); + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/Lob.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/Lob.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/Lob.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/Lob.java Mon May 1 16:10:50 2006 @@ -0,0 +1,26 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + + +/** + * Marker interface for OJB LOB objects. + * + * @version $Id: $ + */ +public interface Lob +{ +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobException.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobException.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobException.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobException.java Mon May 1 16:10:50 2006 @@ -0,0 +1,46 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + + +import org.apache.ojb.broker.OJBRuntimeException; + +/** + * Thrown when an invalid LOB opertation occurs. + * + * @version $Id: $ + */ +public class LobException extends OJBRuntimeException +{ + public LobException() + { + } + + public LobException(String msg) + { + super(msg); + } + + public LobException(Throwable cause) + { + super(cause); + } + + public LobException(String msg, Throwable cause) + { + super(msg, cause); + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHandle.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHandle.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHandle.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHandle.java Mon May 1 16:10:50 2006 @@ -0,0 +1,129 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +import org.apache.ojb.broker.PBStateEvent; +import org.apache.ojb.broker.PBStateListener; +import org.apache.ojb.broker.PersistenceBroker; + +/** + * Base class for OJB LOB-objects. + * + * @version $Id: $ + */ +abstract class LobHandle implements PBStateListener +{ + private boolean active; + private boolean isTransient; + + public LobHandle(PersistenceBroker broker) + { + isTransient = false; + active = broker.isInTransaction(); + if(active) + { + broker.addListener(this, false); + } + /* + Think we should allow to query objects with LOB fields without a running + PB-tx. If the user try to access the LOB field, method #checkActive() will throw an + exception. + */ +// else +// { +// throw new LobException("LOB opertations only valid when the used PersistanceBroker is in PB-tx"); +// } + } + + public boolean isTransient() + { + return isTransient; + } + + protected void setTransient(boolean aTransient) + { + isTransient = aTransient; + } + + protected void txFail() + { + this.active = false; + } + + protected void txSuccess() + { + this.active = false; + this.isTransient = false; + } + + protected void inactivate() + { + this.active = false; + this.isTransient = false; + } + + protected boolean isActive() + { + return this.active; + } + + protected void checkActive() + { + if(!isTransient() && !isActive()) throw new InactiveLobException( + "Current LOB is not valid for access (no active PB-tx or PB-tx changed), " + + "refresh the persistent object this LOB belongs too"); + } + + + //=================================================================== + // Listener methods + //=================================================================== + public void beforeClose(PBStateEvent event) + { + inactivate(); + } + + public void beforeRollback(PBStateEvent event) + { + txFail(); + } + + public void afterCommit(PBStateEvent event) + { + txSuccess(); + } + + public void afterBegin(PBStateEvent event) + { + if(isTransient()) this.active = true; + } + + public void afterOpen(PBStateEvent event) + { + } + + public void beforeBegin(PBStateEvent event) + { + } + + public void beforeCommit(PBStateEvent event) + { + } + + public void afterRollback(PBStateEvent event) + { + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelper.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelper.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelper.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelper.java Mon May 1 16:10:50 2006 @@ -0,0 +1,190 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.InputStream; +import java.io.Reader; +import java.sql.Blob; +import java.sql.Clob; + +import org.apache.ojb.broker.metadata.ClassDescriptor; + +/** + * Helper class support handling of LOB-locator-object + * fields ({@link java.sql.Blob} and {@link java.sql.Clob} fields) + * in persistence capable objects. + * + * @version $Id: $ + */ +public interface LobHelper +{ + /** + * Returns a new {@link java.sql.Blob} instance. + * + * @param in The data source stream. + * @return The new {@link java.sql.Blob} instance. + */ + public Blob newBlob(InputStream in); + + /** + * Returns a new {@link java.sql.Blob} instance. + * + * @param value The byte array data. + * @return The new {@link java.sql.Blob} instance. + */ + public Blob newBlob(byte[] value); + + /** + * Returns a new empty {@link java.sql.Blob} instance. + * + * @return The new {@link java.sql.Blob} instance. + */ + public Blob newBlob(); + + /** + * Returns a new {@link java.sql.Clob} instance. + * + * @param reader The data source reader. + * @return The new {@link java.sql.Clob} instance. + */ + public Clob newClob(Reader reader); + + /** + * Returns a new {@link java.sql.Clob} instance. + * + * @param value The data source as {@link String}. + * @return The new {@link java.sql.Clob} instance. + */ + public Clob newClob(String value); + + /** + * Returns a new empty {@link java.sql.Clob} instance. + * + * @return The new {@link java.sql.Clob} instance. + */ + public Clob newClob(); + + /** + * Returns true if automatic refresh of LOB-locator + * fields is enabled. + * + * @see #setLobAutoRefresh(boolean) + */ + public boolean isLobAutoRefresh(); + + /** + * @param autoRefresh If true automatic refresh for LOB-locator + * objects will be enabled. + */ + public void setLobAutoRefresh(boolean autoRefresh); + + /** + * INTERNAL USED METHOD! + * This method was internally called when automatic refresh of + * LOB-locator-object field is enabled - see {@link #setLobAutoRefresh(boolean)}. + */ + public void internalAutoRefresh(Object target, ClassDescriptor cld); + + /** + * See method {@link #refreshLob(Object, org.apache.ojb.broker.metadata.ClassDescriptor)}. + * + * @param target The target object with the LOB-fields to refresh. + */ + public void refreshLob(Object target); + + /** + * Refresh all LOB-locator instances of the specified persistence capable object + * if the following conditions are true for the target object: + *
    + *
  • active {@link org.apache.ojb.broker.PersistenceBroker}-tx is running
  • + *
  • contains LOB fields
  • + *
  • LOB fields wrapped by OJB's LOB wrapping classes (normally + * all LOB fields of persistence capable objects are automatically wrapped + * with OJB specific wrapper classes by internal calls to + * {@link #wrapLobFields(org.apache.ojb.broker.metadata.ClassDescriptor, Object)})
  • + *
  • one or more fields are inactive/invalid (there is no active + * {@link org.apache.ojb.broker.PersistenceBroker} instance associated with detected LOB-fields)
  • + *
+ * In all other cases the method will return immediately. + * On each LOB-fields refresh, OJB query a new LOB-locator instance from the database. + * + * @param target The target object with the LOB-fields to refresh. + * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the target object. + */ + public void refreshLob(Object target, ClassDescriptor cld); + +// /** +// * Internal used method! +// *
+// * Refresh the specified LOB-locator instance field of the persistence capable object. +// * For each refresh OJB query a new Locator instance from the database. +// * The refresh of LOB-fields is only possible within an active +// * {@link org.apache.ojb.broker.PersistenceBroker}-tx, else the method will return immediately. +// * +// * @param lobField The LOB field to refresh. +// * @param target The target object with the field to refresh. +// * @param pkFields The promary key values of the target object. +// */ +// public void refreshLob(FieldDescriptor lobField, Object target, FieldDescriptor[] pkFields); + + /** + * Internal used method! + *
+ * Wraps the target object LOB instances ({@link java.sql.Blob} and {@link java.sql.Clob} + * instances returned by the database) with OJB specific LOB-wrapper classes. + * + * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the target object. + * @param target The target object. + */ + public void wrapLobFields(ClassDescriptor cld, Object target); + +// /** +// * Returns true if the specified persistence capable object +// * fulfill the conditions below: +// *
    +// *
  • contains LOB fields
  • +// *
  • LOB fields wrapped by OJB's LOB wrapping classes (normally +// * all LOB fields of persistence capable objects are automatically wrapped +// * with OJB specific wrapper classes by internal calls to +// * {@link #wrapLobFields(org.apache.ojb.broker.metadata.ClassDescriptor, Object)})
  • +// *
  • one or more fields are inactive/invalid
  • +// *
+// * In all other cases false will be returned. +// * +// * @param source The persistence capable object. +// * @return True if source object has inactive/invalid LOB-fields. +// */ +// public boolean needsRefresh(Object source); +// +// /** +// * Returns true if the specified persistence capable object +// * fulfill the conditions below: +// *
    +// *
  • contains LOB fields
  • +// *
  • LOB fields wrapped by OJB's LOB wrapping classes (normally +// * all LOB fields of persistence capable objects are automatically wrapped +// * with OJB specific wrapper classes by internal calls to +// * {@link #wrapLobFields(org.apache.ojb.broker.metadata.ClassDescriptor, Object)})
  • +// *
  • one or more fields are inactive/invalid
  • +// *
+// * In all other cases false will be returned. +// * +// * @param source The persistence capable object. +// * @param cld The associated {@link org.apache.ojb.broker.metadata.ClassDescriptor}. +// * @return True if source object has inactive/invalid LOB-fields. +// */ +// public boolean needsRefresh(Object source, ClassDescriptor cld); +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelperImpl.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelperImpl.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelperImpl.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/lob/LobHelperImpl.java Mon May 1 16:10:50 2006 @@ -0,0 +1,243 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2006 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.InputStream; +import java.io.Reader; +import java.sql.Blob; +import java.sql.Clob; +import java.util.Iterator; + +import org.apache.ojb.broker.PersistenceBrokerInternal; +import org.apache.ojb.broker.metadata.ClassDescriptor; +import org.apache.ojb.broker.metadata.FieldDescriptor; +import org.apache.ojb.broker.metadata.FieldTypes; +import org.apache.ojb.broker.query.Criteria; +import org.apache.ojb.broker.query.Query; +import org.apache.ojb.broker.query.QueryFactory; +import org.apache.ojb.broker.util.logging.Logger; +import org.apache.ojb.broker.util.logging.LoggerFactory; + +/** + * Helper class for LOB object creation. + * + * @version $Id: $ + */ +public class LobHelperImpl implements LobHelper +{ + private Logger log = LoggerFactory.getLogger(LobHelperImpl.class); + + private PersistenceBrokerInternal broker; + private boolean lobAutoRefresh; + + public LobHelperImpl(PersistenceBrokerInternal broker) + { + this.broker = broker; + } + + public Blob newBlob(InputStream in) + { + BlobImpl result = new BlobImpl(in); + return new BlobHandle(broker, result); + } + + public Blob newBlob(byte[] value) + { + BlobImpl result = new BlobImpl(value); + return new BlobHandle(broker, result); + } + + public Blob newBlob() + { + return newBlob((byte[]) null); + } + + public Clob newClob(Reader reader) + { + ClobImpl result = new ClobImpl(reader); + return new ClobHandle(broker, result); + } + + public Clob newClob(String value) + { + ClobImpl result = new ClobImpl(value); + return new ClobHandle(broker, result); + } + + public Clob newClob() + { + return newClob((String) null); + } + + public boolean isLobAutoRefresh() + { + return this.lobAutoRefresh; + } + + public void setLobAutoRefresh(boolean autoRefresh) + { + this.lobAutoRefresh = autoRefresh; + } + + public void internalAutoRefresh(Object target, ClassDescriptor cld) + { + if(lobAutoRefresh) + { + refreshLob(target, cld); + } + } + + public void refreshLob(Object target) + { + ClassDescriptor cld = broker.getClassDescriptor(target.getClass()); + refreshLob(target, cld); + } + + public void refreshLob(Object target, ClassDescriptor cld) + { + if(broker.isInTransaction()) + { + if(cld.hasLobField()) + { + FieldDescriptor[] pkFields = cld.getPkFields(); + FieldDescriptor[] fields = cld.getFieldDescriptor(true); + for(int i = 0; i < fields.length; i++) + { + FieldDescriptor field = fields[i]; + if(needsRefresh(field, target)) + { + refreshLob(field, target, pkFields); + } + } + } + } + else + { + if(log.isDebugEnabled()) + { + log.debug("Can't refresh LOB-objects, an active PB-tx is needed. Specified PersistenceBroker: " + + broker); + } + } + } + + /** + * Refresh the specified LOB type field by querying a new LOB-locator object via ReportQuery + * and replace the LOB-object in source object. + */ + protected void refreshLob(FieldDescriptor lobField, Object source, FieldDescriptor[] pkFields) + { + if(source == null) + { + throw new NullPointerException("Persistent object is 'null'"); + } + if(lobField.isLobFieldType()) + { + Object result = null; + FieldDescriptor fld; + Criteria crit = new Criteria(); + for(int i = 0; i < pkFields.length; i++) + { + fld = pkFields[i]; + crit.addEqualTo(fld.getAttributeName(), fld.getPersistentField().get(source)); + } + Query query = QueryFactory.newReportQuery( + source.getClass(), new String[]{lobField.getAttributeName()}, crit, false); + Iterator iter = broker.getReportQueryIteratorByQuery(query); + while(iter.hasNext()) + { + Object[] arr = (Object[]) iter.next(); + if(arr.length > 0) + { + result = arr[0]; + break; + } + } + if(result != null) + { + if(log.isDebugEnabled()) + { + log.debug("Refresh LOB field for " + lobField.getClassDescriptor().getClassNameOfObject() + + "." + lobField.getAttributeName()); + } + if(isBlobField(lobField)) + { + result = new BlobHandle(broker, (Blob) result); + } + else + { + result = new ClobHandle(broker, (Clob) result); + } + } + lobField.getPersistentField().set(source, result); + } + else + { + throw new LobException("Specified field isn't of type LOB (Blob or Clob): " + lobField); + } + } + + /** + * Returns true if the specified field is of type LOB (Blob or Clob type) + * and wrapped by OJB's LOB wrapper and the LOB wrapper isn't active. + */ + protected boolean needsRefresh(FieldDescriptor field, Object source) + { + boolean result = field.isLobFieldType(); + if(result) + { + Object lob = field.getPersistentField().get(source); + if(lob instanceof LobHandle && ((LobHandle) lob).isActive()) + { + // used LOB value doesn't need refresh, it's already bound to a PB instance + result = false; + } + } + return result; + } + + protected boolean isBlobField(FieldDescriptor fld) + { + return FieldTypes.BlobFieldType.class.isAssignableFrom(fld.getJdbcType().getFieldType().getClass()); + } + + public void wrapLobFields(ClassDescriptor cld, Object target) + { + if(cld.hasLobField()) + { + FieldDescriptor[] fields = cld.getFieldDescriptor(true); + for(int i = 0; i < fields.length; i++) + { + FieldDescriptor field = fields[i]; + if(field.isLobFieldType()) + { + Object lob = field.getPersistentField().get(target); + if(lob != null && !(lob instanceof LobHandle)) + { + if(isBlobField(field)) + { + field.getPersistentField().set(target, new BlobHandle(broker, (Blob) lob)); + } + else + { + field.getPersistentField().set(target, new ClobHandle(broker, (Clob) lob)); + } + } + } + } + } + } +} Added: db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/lob/LOBTest.java URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/lob/LOBTest.java?rev=398725&view=auto ============================================================================== --- db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/lob/LOBTest.java (added) +++ db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/lob/LOBTest.java Mon May 1 16:10:50 2006 @@ -0,0 +1,765 @@ +package org.apache.ojb.broker.lob; + +/* Copyright 2002-2005 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.io.StringReader; +import java.io.Writer; +import java.sql.Blob; +import java.sql.Clob; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.SerializationUtils; +import org.apache.ojb.broker.Identity; +import org.apache.ojb.broker.platforms.PlatformHsqldbImpl; +import org.apache.ojb.broker.util.ObjectModification; +import org.apache.ojb.junit.PBTestCase; + +/** + * This TestCase tests OJB's handling with LOB's. Persistent objects with BLOB/CLOB and + * byte[]/String attributes are used. + * Object {@link org.apache.ojb.broker.lob.LOBTest.LobObject} has Blob/Clob fields unlike class + * {@link org.apache.ojb.broker.lob.LOBTest.LobObjectExt} which use byte[] and String fields but + * BLOB/CLOB columns in database. + * + * @version $Id: LOBTest.java 365232 2005-12-21 23:36:07 +0100 (Mi, 21 Dez 2005) tomdz $ + */ +public class LOBTest extends PBTestCase +{ + public static void main(String[] args) + { + String[] arr = {LOBTest.class.getName()}; + junit.textui.TestRunner.main(arr); + } + + public LOBTest(String name) + { + super(name); + } + + public void setUp() throws Exception + { + super.setUp(); + } + + public void tearDown() throws Exception + { + super.tearDown(); + } + + public void testLobAutoRefresh() throws Exception + { + int size = 50; + + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(); + b.setBytes(1, barr); + Clob c = broker.serviceLobHelper().newClob(); + c.setString(1, new String(carr)); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + broker.store(obj); + broker.commitTransaction(); + + broker.beginTransaction(); + broker.serviceLobHelper().setLobAutoRefresh(false); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + + // if no cache is used skip this test + if(broker.serviceObjectCache().lookup(oid) == null) return; + + LobObject objRead = (LobObject) broker.getObjectByIdentity(oid); + assertNotNull("BLOB was not stored", objRead.getBlob()); + assertNotNull("CLOB was not stored", objRead.getClob()); + + try + { + // not valid to access LOB fields + objRead.getBlob().length(); + fail("Expected an LobException"); + } + catch(LobException expected) + { + } + + broker.serviceLobHelper().refreshLob(objRead); + assertEquals(50, objRead.getBlob().length()); + broker.commitTransaction(); + + broker.beginTransaction(); + broker.serviceLobHelper().setLobAutoRefresh(true); + oid = broker.serviceIdentity().buildIdentity(obj); + + objRead = (LobObject) broker.getObjectByIdentity(oid); + assertNotNull("BLOB was not stored", objRead.getBlob()); + assertNotNull("CLOB was not stored", objRead.getClob()); + + assertEquals(50, objRead.getBlob().length()); + broker.commitTransaction(); + } + + public void testLOBStream() throws Exception + { + int size = 5000; + + byte[] barr = new byte[size]; + StringBuffer buf = new StringBuffer(); + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + buf.append('y'); + } + + ByteArrayInputStream in = new ByteArrayInputStream(barr); + StringReader reader = new StringReader(buf.toString()); + + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(in); + Clob c = broker.serviceLobHelper().newClob(reader); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + + broker.store(obj); + broker.commitTransaction(); + + //broker.clearCache(); + broker.beginTransaction(); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObject objRead = (LobObject) broker.getObjectByIdentity(oid); + broker.serviceLobHelper().refreshLob(objRead); + assertNotNull("BLOB was not stored", objRead.getBlob()); + assertNotNull("CLOB was not stored", objRead.getClob()); + byte[] result_2 = objRead.getBlob().getBytes(1, (int) objRead.getBlob().length()); + // System.out.println("result: " + result_2.length); + assertTrue(ArrayUtils.isEquals(barr, result_2)); + assertEquals(buf.toString(), + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + broker.commitTransaction(); + + broker.beginTransaction(); + objRead.setBlob(null); + objRead.setClob(null); + broker.store(objRead, ObjectModification.UPDATE); + broker.commitTransaction(); + broker.clearCache(); + + objRead = (LobObject) broker.getObjectByIdentity(oid); + assertEquals(null, objRead.getBlob()); + assertEquals(null, objRead.getClob()); + } + + public void testLOBUpdateSetBytesSetString() throws Exception + { + if(getPlatformClass().equals(PlatformHsqldbImpl.class.getName())) + { + ojbSkipTestMessage("# Skip unsupported operation for platform: " + getPlatformClass() + " #"); + return; + } + doUpdate(UpdateSetBytesSetString); + } + + public void testLOBUpdateSetBlobSetClob() throws Exception + { + if(getPlatformClass().equals(PlatformHsqldbImpl.class.getName())) + { + ojbSkipTestMessage("# Skip unsupported operation for platform: " + getPlatformClass() + " #"); + return; + } + doUpdate(UpdateSetBlobSetClob); + } + + public void testLOBUpdateSetBinaryStreamSetCharacterStream() throws Exception + { + if(getPlatformClass().equals(PlatformHsqldbImpl.class.getName())) + { + ojbSkipTestMessage("# Skip unsupported operation for platform: " + getPlatformClass() + " #"); + return; + } + doUpdate(UpdateSetBinaryStreamSetCharacterStream); + } + + final int UpdateSetBlobSetClob = 1; + final int UpdateSetBytesSetString = 2; + final int UpdateSetBinaryStreamSetCharacterStream = 3; + + public void doUpdate(int updateType) throws Exception + { + int size = 10; + + byte[] barr = new byte[size]; + String carr = "yyyyyyyyyy"; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + } + byte[] updateByteArr = new byte[]{'u', 'p', 'd', 'a', 't', 'e'}; + byte[] expectedByte = new byte[]{'u', 'p', 'd', 'a', 't', 'e', 'x', 'x', 'x', 'x'}; + String updateString = "update"; + String expectedString = "updateyyyy"; + + byte[] updateByteArr2 = new byte[]{'u', 'p', 'd', 'a', 't', 'e', '_', '2'}; + byte[] expectedByte2 = new byte[]{'u', 'p', 'd', 'a', 't', 'e', '_', '2', 'x', 'x'}; + String updateString2 = "update_2"; + String expectedString2 = "update_2yy"; + + // insert + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(); + b.setBytes(1, barr); + Clob c = broker.serviceLobHelper().newClob(); + c.setString(1, carr); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + broker.store(obj); + broker.commitTransaction(); + + broker.clearCache(); + broker.beginTransaction(); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObject objRead = (LobObject) broker.getObjectByIdentity(oid); + assertNotNull("BLOB was not stored", objRead.getBlob()); + assertNotNull("CLOB was not stored", objRead.getClob()); + byte[] resultArray = objRead.getBlob().getBytes(1, (int) objRead.getBlob().length()); + assertTrue(ArrayUtils.isEquals(barr, resultArray)); + assertEquals(carr, + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + broker.commitTransaction(); + + // update within PB-tx + broker.beginTransaction(); + objRead = (LobObject) broker.getObjectByIdentity(oid); + broker.serviceLobHelper().refreshLob(objRead); + try + { + switch(updateType) + { + case UpdateSetBinaryStreamSetCharacterStream: + OutputStream out = objRead.getBlob().setBinaryStream(1); + out.write(updateByteArr); + out.flush(); + out.close(); + Writer writer = objRead.getClob().setCharacterStream(1); + writer.write(updateString); + writer.flush(); + writer.close(); + break; + case UpdateSetBlobSetClob: + Blob blob = broker.serviceLobHelper().newBlob(expectedByte); + Clob clob = broker.serviceLobHelper().newClob(expectedString); + objRead.setBlob(blob); + objRead.setClob(clob); + break; + case UpdateSetBytesSetString: + objRead.getBlob().setBytes(1, updateByteArr); + objRead.getClob().setString(1, updateString); + break; + default: + throw new RuntimeException("Unkown LOB update type specified"); + } + } + catch(UnsupportedOperationException e) + { + ojbSkipTestMessage("Skip unsupported operation for platform: " + + getPlatformClass() + ", message: " + e.getMessage()); + return; + } + broker.store(objRead, ObjectModification.UPDATE); + broker.commitTransaction(); + + broker.beginTransaction(); + oid = broker.serviceIdentity().buildIdentity(obj); + objRead = (LobObject) broker.getObjectByIdentity(oid); + broker.serviceLobHelper().refreshLob(objRead); + resultArray = objRead.getBlob().getBytes(1, (int) objRead.getBlob().length()); +// System.out.println(""); +// System.out.println("# exp: " + ArrayUtils.toString(expectedByte)); +// System.out.println("# get: " + ArrayUtils.toString(resultArray)); +// System.out.println("# set: " + updateString); +// System.out.println("# get: " + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + assertTrue(ArrayUtils.isEquals(expectedByte, resultArray)); + assertEquals(expectedString, + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + broker.commitTransaction(); + + // try update 2 + broker.beginTransaction(); + objRead = (LobObject) broker.getObjectByIdentity(oid); + broker.serviceLobHelper().refreshLob(objRead); + try + { + switch(updateType) + { + case UpdateSetBinaryStreamSetCharacterStream: + OutputStream out = objRead.getBlob().setBinaryStream(1); + out.write(updateByteArr2); + out.flush(); + out.close(); + Writer writer = objRead.getClob().setCharacterStream(1); + writer.write(updateString2); + writer.flush(); + writer.close(); + break; + case UpdateSetBlobSetClob: + Blob blob = broker.serviceLobHelper().newBlob(expectedByte2); + Clob clob = broker.serviceLobHelper().newClob(expectedString2); + objRead.setBlob(blob); + objRead.setClob(clob); + break; + case UpdateSetBytesSetString: + objRead.getBlob().setBytes(1, updateByteArr2); + objRead.getClob().setString(1, updateString2); + break; + default: + throw new RuntimeException("Unkown LOB update type specified"); + } + } + catch(UnsupportedOperationException e) + { + ojbSkipTestMessage("# Skip unsupported operation for platform: " + getPlatformClass() + ", message: " + e.getMessage() + " #"); + return; + } + broker.store(objRead, ObjectModification.UPDATE); + broker.commitTransaction(); + + broker.beginTransaction(); + oid = broker.serviceIdentity().buildIdentity(obj); + objRead = (LobObject) broker.getObjectByIdentity(oid); + broker.serviceLobHelper().refreshLob(objRead); + resultArray = objRead.getBlob().getBytes(1, (int) objRead.getBlob().length()); + assertTrue(ArrayUtils.isEquals(expectedByte2, resultArray)); + assertEquals(expectedString2, + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + broker.commitTransaction(); + + broker.beginTransaction(); + objRead.setBlob(null); + objRead.setClob(null); + broker.store(objRead, ObjectModification.UPDATE); + broker.commitTransaction(); + + objRead = (LobObject) broker.getObjectByIdentity(oid); + assertEquals(null, objRead.getBlob()); + assertEquals(null, objRead.getClob()); + } + + + public void testLOBInsertRead() throws Exception + { + int size = 5000; + + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(); + b.setBytes(1, barr); + Clob c = broker.serviceLobHelper().newClob(); + c.setString(1, new String(carr)); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + + broker.store(obj); + broker.commitTransaction(); + + //broker.clearCache(); + broker.beginTransaction(); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObject objRead = (LobObject) broker.getObjectByIdentity(oid); + broker.serviceLobHelper().refreshLob(objRead); + assertNotNull("BLOB was not stored", objRead.getBlob()); + assertNotNull("CLOB was not stored", objRead.getClob()); + byte[] result_2 = objRead.getBlob().getBytes(1, (int) objRead.getBlob().length()); + assertTrue(ArrayUtils.isEquals(barr, result_2)); + assertEquals(new String(carr), + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + broker.commitTransaction(); + + broker.beginTransaction(); + objRead.setBlob(null); + objRead.setClob(null); + broker.store(objRead, ObjectModification.UPDATE); + broker.commitTransaction(); + broker.clearCache(); + + objRead = (LobObject) broker.getObjectByIdentity(oid); + assertEquals(null, objRead.getBlob()); + assertEquals(null, objRead.getClob()); + } + + public void testLOBDelete() throws Exception + { + int size = 5000; + + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(); + b.setBytes(1, barr); + Clob c = broker.serviceLobHelper().newClob(); + c.setString(1, new String(carr)); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + + broker.store(obj); + broker.commitTransaction(); + + broker.clearCache(); + broker.beginTransaction(); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObject objRead = (LobObject) broker.getObjectByIdentity(oid); + //LOBHelper.refreshLob( objRead); + assertNotNull("BLOB was not stored", objRead.getBlob()); + assertNotNull("CLOB was not stored", objRead.getClob()); + byte[] result_2 = objRead.getBlob().getBytes(1, (int) objRead.getBlob().length()); + assertTrue(ArrayUtils.isEquals(barr, result_2)); + assertEquals(new String(carr), + objRead.getClob().getSubString(1, (int) objRead.getClob().length())); + broker.commitTransaction(); + + broker.beginTransaction(); + broker.delete(objRead); + broker.commitTransaction(); + + objRead = (LobObject) broker.getObjectByIdentity(oid); + assertNull(objRead); + } + + public void testLOBFail_1() throws Exception + { + int size = 5; + + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(); + b.setBytes(1, barr); + Clob c = broker.serviceLobHelper().newClob(); + c.setString(1, new String(carr)); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + broker.store(obj); + broker.commitTransaction(); + + broker.beginTransaction(); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + // if object was in cache, we have to refresh the LOB fields + LobObject source = (LobObject) broker.serviceObjectCache().lookup(oid); + if(source != null) + { + try + { + source.getBlob().length(); + fail("LobException expected"); + } + catch(LobException expected) + { + } + + broker.serviceLobHelper().refreshLob(source); + assertEquals(5, source.getBlob().length()); + assertEquals(5, source.getClob().length()); + } + broker.commitTransaction(); + } + + public void testLOBFail_2() throws Exception + { + int size = 5; + + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + broker.beginTransaction(); + Blob b = broker.serviceLobHelper().newBlob(); + b.setBytes(1, barr); + Clob c = broker.serviceLobHelper().newClob(); + c.setString(1, new String(carr)); + LobObject obj = new LobObject(); + obj.setBlob(b); + obj.setClob(c); + broker.store(obj); + broker.commitTransaction(); + + broker.clearCache(); + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObject source = (LobObject) broker.getObjectByIdentity(oid); + try + { + source.getBlob().length(); + fail("LobException expected"); + } + catch(LobException expected) + { + } + broker.beginTransaction(); + broker.serviceLobHelper().refreshLob(source); + assertEquals(5, source.getBlob().length()); + broker.commitTransaction(); + } + + + public void testByteArrayStringInsertRead() throws Exception + { + int size = 5000; + + LobObjectExt obj = new LobObjectExt(); + + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + // obj.setId(1); we use autoincrement + obj.setBlobArray(barr); + obj.setClobString(new String(carr)); + broker.beginTransaction(); + broker.store(obj); + broker.commitTransaction(); + broker.clearCache(); + + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObjectExt objRead = (LobObjectExt) broker.getObjectByIdentity(oid); + assertNotNull("BLOB was not stored", objRead.getBlobArray()); + assertNotNull("CLOB was not stored", objRead.getClobString()); + assertEquals(obj.getBlobArray().length, objRead.getBlobArray().length); + assertEquals(obj.getClobString().length(), objRead.getClobString().length()); + + broker.beginTransaction(); + objRead.setBlobArray(null); + objRead.setClobString(null); + broker.store(objRead, ObjectModification.UPDATE); + broker.commitTransaction(); + broker.clearCache(); + + objRead = (LobObjectExt) broker.getObjectByIdentity(oid); + assertEquals(null, objRead.getBlobArray()); + assertEquals(null, objRead.getClobString()); + } + + public void testByteArrayStringDelete() throws Exception + { + int size = 5000; + LobObjectExt obj = new LobObjectExt(); + byte[] barr = new byte[size]; + char[] carr = new char[size]; + for(int i = 0; i < size; i++) + { + barr[i] = (byte) 'x'; + carr[i] = 'y'; + } + + // obj.setId(1); we use autoincrement + obj.setBlobArray(barr); + obj.setClobString(new String(carr)); + broker.beginTransaction(); + broker.store(obj); + broker.commitTransaction(); + broker.clearCache(); + + Identity oid = broker.serviceIdentity().buildIdentity(obj); + LobObjectExt objRead = (LobObjectExt) broker.getObjectByIdentity(oid); + assertNotNull("BLOB was not stored", objRead.getBlobArray()); + assertNotNull("CLOB was not stored", objRead.getClobString()); + assertEquals(obj.getBlobArray().length, objRead.getBlobArray().length); + assertEquals(obj.getClobString().length(), objRead.getClobString().length()); + + broker.beginTransaction(); + broker.delete(objRead); + broker.commitTransaction(); + + objRead = (LobObjectExt) broker.getObjectByIdentity(oid); + assertNull(objRead); + } + + public void testLOBImplementations_1() throws Exception + { + byte[] b = new byte[]{'a', 'b', 'c', 'd', 'e'}; + String c = "abcdefgh"; + BlobImpl blob = new BlobImpl(); + ClobImpl clob = new ClobImpl(); + + blob.setBytes(1, b); + clob.setString(1, c); + + BlobImpl blob2 = (BlobImpl) SerializationUtils.clone(blob); + ClobImpl clob2 = (ClobImpl) SerializationUtils.clone(clob); + + assertTrue(ArrayUtils.isEquals(blob.getBytes(), blob2.getBytes())); + assertTrue(ArrayUtils.isEquals(b, blob2.getBytes())); + assertEquals(clob.getSubString(1, (int) clob.length()), clob2.getSubString(1, (int) clob2.length())); + assertEquals(c, clob2.getSubString(1, (int) clob2.length())); + } + + public void testLOBImplementations_2() throws Exception + { + byte[] b = new byte[]{'a', 'b', 'c', 'd', 'e'}; + String c = "abcdefgh"; + BlobImpl blob = new BlobImpl(); + ClobImpl clob = new ClobImpl(); + + OutputStream out = blob.setBinaryStream(1); + out.write(b); + out.close(); + Writer writer = clob.setCharacterStream(1); + writer.write(c); + writer.close(); + + BlobImpl blob2 = (BlobImpl) SerializationUtils.clone(blob); + ClobImpl clob2 = (ClobImpl) SerializationUtils.clone(clob); + +// System.out.println("# old: " + ArrayUtils.toString(blob2.getBytes())); +// System.out.println("# old: " + clob2.getSubString(1, (int) clob2.length())); + assertTrue(ArrayUtils.isEquals(blob.getBytes(), blob2.getBytes())); + assertTrue(ArrayUtils.isEquals(b, blob2.getBytes())); + assertEquals(clob.getSubString(1, (int) clob.length()), clob2.getSubString(1, (int) clob2.length())); + assertEquals(c, clob2.getSubString(1, (int) clob2.length())); + + blob2.setBytes(3, new byte[]{'C', 'D'}); + clob2.setString(3, "CD"); +// System.out.println("# new: " + ArrayUtils.toString(blob2.getBytes())); +// System.out.println("# new: " + ArrayUtils.toString(clob2.getSubString(1, (int) clob2.length()))); + assertTrue(ArrayUtils.isEquals(new byte[]{'a', 'b', 'C', 'D', 'e'}, blob2.getBytes())); + assertEquals("abCDefgh", clob2.getSubString(1, (int) clob2.length())); + } + + + //******************************************************* + // inner class - test class + //******************************************************* + public static class LobObject implements Serializable + { + private int id; + private Blob blob; + private Clob clob; + + public LobObject() + { + } + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public Blob getBlob() + { + return blob; + } + + public void setBlob(Blob blob) + { + this.blob = blob; + } + + public Clob getClob() + { + return clob; + } + + public void setClob(Clob clob) + { + this.clob = clob; + } + } + + public static class LobObjectExt implements Serializable + { + private int id; + private byte[] blobArray; + private String clobString; + + public LobObjectExt() + { + } + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public byte[] getBlobArray() + { + return blobArray; + } + + public void setBlobArray(byte[] blobArray) + { + this.blobArray = blobArray; + } + + public String getClobString() + { + return clobString; + } + + public void setClobString(String clobString) + { + this.clobString = clobString; + } + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org For additional commands, e-mail: ojb-dev-help@db.apache.org