/*
* Copyright 2006-2012 Amazon Technologies, Inc. or its affiliates.
* Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
* of Amazon Technologies, Inc. or its affiliates. All rights reserved.
*
* 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.
*/
package com.amazon.carbonado.repo.jdbc;
import java.io.Reader;
import java.io.Writer;
import java.io.IOException;
import java.sql.SQLException;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.FetchNoneException;
import com.amazon.carbonado.PersistException;
import com.amazon.carbonado.PersistNoneException;
import com.amazon.carbonado.lob.AbstractClob;
/**
*
*
* @author Brian S O'Neill
*/
class JDBCClob extends AbstractClob implements JDBCLob {
private static final int DEFAULT_BUFFER = 4000;
protected final JDBCRepository mRepo;
private java.sql.Clob mClob;
private final JDBCClobLoader mLoader;
JDBCClob(JDBCRepository repo, java.sql.Clob clob, JDBCClobLoader loader) {
super(repo);
mRepo = repo;
mClob = clob;
mLoader = loader;
}
// FIXME: I/O streams must have embedded transaction
public Reader openReader() throws FetchException {
try {
return getInternalClobForFetch().getCharacterStream();
} catch (SQLException e) {
throw mRepo.toFetchException(e);
}
}
public Reader openReader(long pos) throws FetchException {
try {
if (pos == 0) {
return getInternalClobForFetch().getCharacterStream();
}
return new Input(getInternalClobForFetch(), DEFAULT_BUFFER, pos);
} catch (SQLException e) {
throw mRepo.toFetchException(e);
}
}
public Reader openReader(long pos, int bufferSize) throws FetchException {
try {
if (pos == 0) {
return getInternalClobForFetch().getCharacterStream();
}
if (bufferSize <= 0) {
bufferSize = DEFAULT_BUFFER;
}
return new Input(getInternalClobForFetch(), bufferSize, pos);
} catch (SQLException e) {
throw mRepo.toFetchException(e);
}
}
public long getLength() throws FetchException {
try {
return getInternalClobForFetch().length();
} catch (SQLException e) {
throw mRepo.toFetchException(e);
}
}
public Writer openWriter() throws PersistException {
return openWriter(0);
}
public Writer openWriter(long pos) throws PersistException {
try {
return getInternalClobForPersist().setCharacterStream(pos);
} catch (SQLException e) {
throw mRepo.toPersistException(e);
}
}
public Writer openWriter(long pos, int bufferSize) throws PersistException {
return openWriter(pos);
}
public void setLength(long length) throws PersistException {
// FIXME: Add special code to support increasing length
try {
getInternalClobForPersist().truncate(length);
} catch (SQLException e) {
throw mRepo.toPersistException(e);
}
}
public Object getLocator() {
// FIXME
return null;
}
public void close() {
mClob = null;
}
java.sql.Clob getInternalClobForFetch() throws FetchException {
if (mClob == null) {
if ((mClob = mLoader.load(mRepo)) == null) {
throw new FetchNoneException("Clob value is null");
}
try {
JDBCTransaction txn = mRepo.localTransactionScope().getTxn();
if (txn != null) {
txn.register(this);
}
} catch (Exception e) {
throw mRepo.toFetchException(e);
}
}
return mClob;
}
java.sql.Clob getInternalClobForPersist() throws PersistException {
if (mClob == null) {
try {
if ((mClob = mLoader.load(mRepo)) == null) {
throw new PersistNoneException("Clob value is null");
}
JDBCTransaction txn = mRepo.localTransactionScope().getTxn();
if (txn != null) {
txn.register(this);
}
} catch (Exception e) {
throw mRepo.toPersistException(e);
}
}
return mClob;
}
private static class Input extends Reader {
private final java.sql.Clob mClob;
private final int mBufferSize;
private long mPos;
private String mBuffer;
private int mBufferPos;
Input(java.sql.Clob clob, int bufferSize, long pos) {
mClob = clob;
mBufferSize = bufferSize;
mPos = pos;
}
@Override
public int read() throws IOException {
if (fillBuffer() <= 0) {
return -1;
}
return mBuffer.charAt(mBufferPos++);
}
@Override
public int read(char[] c, int off, int len) throws IOException {
int avail = fillBuffer();
if (avail <= 0) {
return -1;
}
if (len > avail) {
len = avail;
}
mBuffer.getChars(mBufferPos, mBufferPos + len, c, off);
mBufferPos += len;
return len;
}
@Override
public long skip(long n) throws IOException {
if (n <= 0) {
return 0;
}
long newPos = mPos + n;
long length;
try {
length = mClob.length();
} catch (SQLException e) {
IOException ioe = new IOException();
ioe.initCause(e);
throw ioe;
}
if (newPos >= length) {
newPos = length;
n = newPos - mPos;
}
long newBufferPos = mBufferPos + n;
if (mBuffer == null || newBufferPos >= mBuffer.length()) {
mBuffer = null;
mBufferPos = 0;
} else {
mBufferPos = (int) newBufferPos;
}
mPos = newPos;
return n;
}
@Override
public void close() {
}
private int fillBuffer() throws IOException {
try {
if (mBuffer == null || mBufferPos >= mBuffer.length()) {
mBuffer = mClob.getSubString(mPos, mBufferSize);
mPos += mBuffer.length();
mBufferPos = 0;
}
return mBuffer.length() - mBufferPos;
} catch (SQLException e) {
IOException ioe = new IOException();
ioe.initCause(e);
throw ioe;
}
}
}
}