OPENJPA-130. Committing Ignacio's patch, with a few whitespace and method name tweaks.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@574143 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Patrick Linskey 2007-09-10 06:11:29 +00:00
parent 1242abf2d5
commit d022b18ad5
17 changed files with 1035 additions and 12 deletions

View File

@ -40,6 +40,7 @@ import org.apache.openjpa.jdbc.meta.strats.FlatClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy; import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy; import org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.ImmutableValueHandler; import org.apache.openjpa.jdbc.meta.strats.ImmutableValueHandler;
import org.apache.openjpa.jdbc.meta.strats.LobFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedBlobFieldStrategy; import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedBlobFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedByteArrayFieldStrategy; import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedByteArrayFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedCharArrayFieldStrategy; import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedCharArrayFieldStrategy;
@ -866,6 +867,9 @@ public class MappingRepository
break; break;
return handlerMapStrategy(field, khandler, vhandler, krel, return handlerMapStrategy(field, khandler, vhandler, krel,
vrel, installHandlers); vrel, installHandlers);
case JavaTypes.INPUT_STREAM:
case JavaTypes.INPUT_READER:
return new LobFieldStrategy();
} }
return null; return null;
} }

View File

@ -0,0 +1,194 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.InputStream;
import java.io.Reader;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.ValueMappingInfo;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.Row;
import org.apache.openjpa.jdbc.sql.RowManager;
import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.OpenJPAStateManager;
/**
* Direct mapping from a stream value to a column.
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public class LobFieldStrategy extends AbstractFieldStrategy {
private int fieldType;
public void map(boolean adapt) {
assertNotMappedBy();
field.mapJoin(adapt, false);
field.getKeyMapping().getValueInfo().assertNoSchemaComponents
(field.getKey(), !adapt);
field.getElementMapping().getValueInfo().assertNoSchemaComponents
(field.getElement(), !adapt);
field.setStream(true);
ValueMappingInfo vinfo = field.getValueInfo();
vinfo.assertNoJoin(field, true);
vinfo.assertNoForeignKey(field, !adapt);
Column tmpCol = new Column();
tmpCol.setName(field.getName());
tmpCol.setJavaType(field.getTypeCode());
tmpCol.setType(fieldType);
tmpCol.setSize(-1);
Column[] cols = vinfo.getColumns(field, field.getName(),
new Column[]{ tmpCol }, field.getTable(), adapt);
field.setColumns(cols);
field.setColumnIO(vinfo.getColumnIO());
field.mapConstraints(field.getName(), adapt);
field.mapPrimaryKey(adapt);
}
public Boolean isCustomInsert(OpenJPAStateManager sm, JDBCStore store) {
return null;
}
public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
Object ob = toDataStoreValue(sm.fetchObjectField
(field.getIndex()), store);
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
if (field.getColumnIO().isInsertable(0, ob == null)) {
if (ob != null) {
if (isBlob()) {
store.getDBDictionary().insertBlobForStreamingLoad
(row, field.getColumns()[0]);
} else {
store.getDBDictionary().insertClobForStreamingLoad
(row, field.getColumns()[0]);
}
} else {
Column col = field.getColumns()[0];
col.setType(Types.OTHER);
row.setNull(col);
}
}
}
public void customInsert(OpenJPAStateManager sm, JDBCStore store)
throws SQLException {
Object ob = toDataStoreValue(sm.fetchObjectField
(field.getIndex()), store);
if (field.getColumnIO().isInsertable(0, ob == null)) {
if (ob != null) {
Select sel = createSelect(sm, store);
if (isBlob()) {
store.getDBDictionary().updateBlob
(sel, store, (InputStream)ob);
} else {
store.getDBDictionary().updateClob
(sel, store, (Reader)ob);
}
}
}
}
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
Object ob = toDataStoreValue(sm.fetchObjectField
(field.getIndex()), store);
if (field.getColumnIO().isUpdatable(0, ob == null)) {
if (ob != null) {
Select sel = createSelect(sm, store);
if (isBlob()) {
store.getDBDictionary().updateBlob
(sel, store, (InputStream)ob);
} else {
store.getDBDictionary().updateClob
(sel, store, (Reader)ob);
}
} else {
Row row = field.getRow(sm, store, rm, Row.ACTION_UPDATE);
Column col = field.getColumns()[0];
col.setType(Types.OTHER);
row.setNull(col);
}
}
}
public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
JDBCStore store, JDBCFetchConfiguration fetch) {
if (type == Select.TYPE_JOINLESS && sel.isSelected(field.getTable()))
return 1;
return 0;
}
public int select(Select sel, OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, int eagerMode) {
sel.select(field.getColumns()[0], field.join(sel));
return 1;
}
public void load(OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, Result res) throws SQLException {
Column col = field.getColumns()[0];
if (res.contains(col)) {
if (isBlob()) {
sm.storeObject(field.getIndex(), res.getBinaryStream(col));
} else {
sm.storeObject(field.getIndex(), res.getCharacterStream(col));
}
}
}
protected void assertNotMappedBy() {
if (field != null && field.getMappedBy() != null)
throw new UnsupportedOperationException();
}
public void setFieldMapping(FieldMapping owner) {
if (owner.getType().isAssignableFrom(InputStream.class)) {
fieldType = Types.BLOB;
} else if (owner.getType().isAssignableFrom(Reader.class)) {
fieldType = Types.CLOB;
}
field = owner;
}
private boolean isBlob() {
if (fieldType == Types.BLOB)
return true;
return false;
}
private Select createSelect(OpenJPAStateManager sm, JDBCStore store) {
Select sel = store.getSQLFactory().newSelect();
sel.select(field.getColumns()[0]);
sel.selectPrimaryKey(field.getDefiningMapping());
sel.wherePrimaryKey
(sm.getObjectId(), field.getDefiningMapping(), store);
sel.setLob(true);
return sel;
}
}

View File

@ -20,9 +20,11 @@ package org.apache.openjpa.jdbc.sql;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.io.Writer; import java.io.Writer;
@ -96,6 +98,7 @@ import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.Localizer.Message; import org.apache.openjpa.lib.util.Localizer.Message;
import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.GeneralException; import org.apache.openjpa.util.GeneralException;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.OpenJPAException; import org.apache.openjpa.util.OpenJPAException;
import org.apache.openjpa.util.ReferentialIntegrityException; import org.apache.openjpa.util.ReferentialIntegrityException;
import org.apache.openjpa.util.Serialization; import org.apache.openjpa.util.Serialization;
@ -125,6 +128,9 @@ public class DBDictionary
public static final String CONS_NAME_MID = "mid"; public static final String CONS_NAME_MID = "mid";
public static final String CONS_NAME_AFTER = "after"; public static final String CONS_NAME_AFTER = "after";
public int blobBufferSize = 50;
public int clobBufferSize = 50;
protected static final int RANGE_POST_SELECT = 0; protected static final int RANGE_POST_SELECT = 0;
protected static final int RANGE_PRE_DISTINCT = 1; protected static final int RANGE_PRE_DISTINCT = 1;
protected static final int RANGE_POST_DISTINCT = 2; protected static final int RANGE_POST_DISTINCT = 2;
@ -3920,6 +3926,109 @@ public class DBDictionary
return column.toString(); return column.toString();
} }
public void insertBlobForStreamingLoad(Row row, Column col)
throws SQLException {
row.setBinaryStream(col,
new ByteArrayInputStream(new byte[0]), 0);
}
public void insertClobForStreamingLoad(Row row, Column col)
throws SQLException {
row.setCharacterStream(col,
new CharArrayReader(new char[0]), 0);
}
public void updateBlob(Select sel, JDBCStore store, InputStream is)
throws SQLException {
SQLBuffer sql = sel.toSelect(true, store.getFetchConfiguration());
ResultSet res = null;
Connection conn = store.getConnection();
PreparedStatement stmnt = null;
try {
stmnt = sql.prepareStatement(conn, store.getFetchConfiguration(),
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
res = stmnt.executeQuery();
if (!res.next()) {
throw new InternalException(_loc.get("stream-exception"));
}
Blob blob = res.getBlob(1);
OutputStream os = blob.setBinaryStream(1);
copy(is, os);
os.close();
res.updateBlob(1, blob);
res.updateRow();
} catch (IOException ioe) {
throw new StoreException(ioe);
} finally {
if (res != null)
try { res.close (); } catch (SQLException e) {}
if (stmnt != null)
try { stmnt.close (); } catch (SQLException e) {}
if (conn != null)
try { conn.close (); } catch (SQLException e) {}
}
}
public void updateClob(Select sel, JDBCStore store, Reader reader)
throws SQLException {
SQLBuffer sql = sel.toSelect(true, store.getFetchConfiguration());
ResultSet res = null;
Connection conn = store.getConnection();
PreparedStatement stmnt = null;
try {
stmnt = sql.prepareStatement(conn, store.getFetchConfiguration(),
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
res = stmnt.executeQuery();
if (!res.next()) {
throw new InternalException(_loc.get("stream-exception"));
}
Clob clob = res.getClob(1);
Writer writer = clob.setCharacterStream(1);
copy(reader, writer);
writer.close();
res.updateClob(1, clob);
res.updateRow();
} catch (IOException ioe) {
throw new StoreException(ioe);
} finally {
if (res != null)
try { res.close (); } catch (SQLException e) {}
if (stmnt != null)
try { stmnt.close (); } catch (SQLException e) {}
if (conn != null)
try { conn.close (); } catch (SQLException e) {}
}
}
protected long copy(InputStream in, OutputStream out) throws IOException {
byte[] copyBuffer = new byte[blobBufferSize];
long bytesCopied = 0;
int read = -1;
while ((read = in.read(copyBuffer, 0, copyBuffer.length)) != -1) {
out.write(copyBuffer, 0, read);
bytesCopied += read;
}
return bytesCopied;
}
protected long copy(Reader reader, Writer writer) throws IOException {
char[] copyBuffer = new char[clobBufferSize];
long bytesCopied = 0;
int read = -1;
while ((read = reader.read(copyBuffer, 0, copyBuffer.length)) != -1) {
writer.write(copyBuffer, 0, read);
bytesCopied += read;
}
return bytesCopied;
}
/** /**
* Attach CAST to the current function if necessary * Attach CAST to the current function if necessary
* *
@ -3930,5 +4039,4 @@ public class DBDictionary
public String getCastFunction(Val val, String func) { public String getCastFunction(Val val, String func) {
return func; return func;
} }
} }

View File

@ -49,6 +49,7 @@ import org.apache.openjpa.lib.jdbc.DelegatingDatabaseMetaData;
import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement; import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.StoreException; import org.apache.openjpa.util.StoreException;
import serp.util.Numbers; import serp.util.Numbers;
/** /**
@ -1097,4 +1098,14 @@ public class OracleDictionary
val.appendTo(buf); val.appendTo(buf);
buf.append("')"); buf.append("')");
} }
public void insertBlobForStreamingLoad(Row row, Column col)
throws SQLException {
row.setNull(col);
}
public void insertClobForStreamingLoad(Row row, Column col)
throws SQLException {
row.setNull(col);
}
} }

View File

@ -168,4 +168,4 @@ isolation-level-config-not-supported: This DBDictionary does not support \
millis-query-timeout: JDBC locking does not support millisecond-granularity \ millis-query-timeout: JDBC locking does not support millisecond-granularity \
timeouts. Use timeouts that are multiples of 1000 for even second values. timeouts. Use timeouts that are multiples of 1000 for even second values.
db-not-supported: The database product "{0}", version "{1}" is not officially supported. db-not-supported: The database product "{0}", version "{1}" is not officially supported.
stream-exception: Unexpected error recovering the row to stream the LOB.

View File

@ -121,7 +121,7 @@ public class DataCachePCDataImpl
protected Object toData(FieldMetaData fmd, Object val, StoreContext ctx) { protected Object toData(FieldMetaData fmd, Object val, StoreContext ctx) {
// avoid caching large result set fields // avoid caching large result set fields
if (fmd.isLRS()) if (fmd.isLRS() || fmd.isStream())
return NULL; return NULL;
return super.toData(fmd, val, ctx); return super.toData(fmd, val, ctx);
} }

View File

@ -166,6 +166,7 @@ public class FieldMetaData
private String[] _fgs = null; private String[] _fgs = null;
private String _lfg = null; private String _lfg = null;
private Boolean _lrs = null; private Boolean _lrs = null;
private Boolean _stream = null;
private String _extName = null; private String _extName = null;
private String _factName = null; private String _factName = null;
private String _extString = null; private String _extString = null;
@ -1027,6 +1028,24 @@ public class FieldMetaData
_lrs = (lrs) ? Boolean.TRUE : Boolean.FALSE; _lrs = (lrs) ? Boolean.TRUE : Boolean.FALSE;
} }
/**
* Whether this field is backed by a stream.
*
* @since 1.1.0
*/
public boolean isStream() {
return _stream == Boolean.TRUE && _manage == MANAGE_PERSISTENT;
}
/**
* Whether this field is backed by a stream.
*
* @since 1.1.0
*/
public void setStream(boolean stream) {
_stream = (stream) ? Boolean.TRUE : Boolean.FALSE;
}
/** /**
* Whether this field uses intermediate data when loading/storing * Whether this field uses intermediate data when loading/storing
* information through a {@link OpenJPAStateManager}. Defaults to true. * information through a {@link OpenJPAStateManager}. Defaults to true.

View File

@ -18,6 +18,8 @@
*/ */
package org.apache.openjpa.meta; package org.apache.openjpa.meta;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -79,6 +81,8 @@ public class JavaTypes {
public static final int PC_UNTYPED = 27; public static final int PC_UNTYPED = 27;
public static final int CALENDAR = 28; public static final int CALENDAR = 28;
public static final int OID = 29; public static final int OID = 29;
public static final int INPUT_STREAM = 30;
public static final int INPUT_READER = 31;
private static final Localizer _loc = Localizer.forPackage(JavaTypes.class); private static final Localizer _loc = Localizer.forPackage(JavaTypes.class);
@ -156,6 +160,11 @@ public class JavaTypes {
return OBJECT; return OBJECT;
return PC_UNTYPED; return PC_UNTYPED;
} }
if (type.isAssignableFrom(Reader.class))
return INPUT_READER;
if (type.isAssignableFrom (InputStream.class))
return INPUT_STREAM;
return OBJECT; return OBJECT;
} }

View File

@ -436,11 +436,19 @@ public class DelegatingResultSet implements ResultSet, Closeable {
_rs.updateBinaryStream(a, in, b); _rs.updateBinaryStream(a, in, b);
} }
public void updateBlob(int a, Blob blob) throws SQLException {
_rs.updateBlob(a, blob);
}
public void updateCharacterStream(int a, Reader reader, int b) public void updateCharacterStream(int a, Reader reader, int b)
throws SQLException { throws SQLException {
_rs.updateCharacterStream(a, reader, b); _rs.updateCharacterStream(a, reader, b);
} }
public void updateClob(int a, Clob clob) throws SQLException {
_rs.updateClob(a, clob);
}
public void updateObject(int a, Object ob, int b) throws SQLException { public void updateObject(int a, Object ob, int b) throws SQLException {
_rs.updateObject(a, ob, b); _rs.updateObject(a, ob, b);
} }
@ -643,18 +651,10 @@ public class DelegatingResultSet implements ResultSet, Closeable {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public void updateBlob(int column, Blob blob) throws SQLException {
throw new UnsupportedOperationException();
}
public void updateBlob(String columnName, Blob blob) throws SQLException { public void updateBlob(String columnName, Blob blob) throws SQLException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public void updateClob(int column, Clob clob) throws SQLException {
throw new UnsupportedOperationException();
}
public void updateClob(String columnName, Clob clob) throws SQLException { public void updateClob(String columnName, Clob clob) throws SQLException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -0,0 +1,247 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.datacache.DataCachePCData;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.MySQLDictionary;
import org.apache.openjpa.jdbc.sql.OracleDictionary;
import org.apache.openjpa.jdbc.sql.SQLServerDictionary;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.persistence.JPAFacadeHelper;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
* This abstract class defines all the tests for LOBS.
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public abstract class AbstractLobTest extends SingleEMFTestCase {
public void setUp() throws Exception {
super.setUp(getLobEntityClass(), CLEAR_TABLES,
"openjpa.DataCache", "true",
"openjpa.RemoteCommitProvider", "sjvm");
}
public boolean isDatabaseSupported() {
DBDictionary dict = ((JDBCConfiguration) emf.getConfiguration())
.getDBDictionaryInstance();
if (dict instanceof MySQLDictionary ||
dict instanceof SQLServerDictionary ||
dict instanceof OracleDictionary) {
return true;
}
return false;
}
public void insert(LobEntity le) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(le);
em.getTransaction().commit();
em.close();
}
public void testInsert() {
if (!isDatabaseSupported()) return;
insert(newLobEntity("oOOOOOo", 1));
}
public void testInsertAndSelect() throws IOException {
if (!isDatabaseSupported()) return;
String s = "oooOOOooo";
insert(newLobEntity(s, 1));
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query = em.createQuery(getSelectQuery());
LobEntity entity = (LobEntity) query.getSingleResult();
assertNotNull(entity.getStream());
assertEquals(s, getStreamContentAsString(entity.getStream()));
em.getTransaction().commit();
em.close();
}
public void testInsertNull() {
if (!isDatabaseSupported()) return;
insert(newLobEntity(null, 1));
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity le = (LobEntity) em.find(getLobEntityClass(), 1);
assertNull(le.getStream());
em.getTransaction().commit();
em.close();
}
public void testUpdate() throws IOException {
if (!isDatabaseSupported()) return;
insert(newLobEntity("oOOOOOo", 1));
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity entity = (LobEntity) em.find(getLobEntityClass(), 1);
String string = "iIIIIIi";
changeStream(entity, string);
em.getTransaction().commit();
em.close();
em = emf.createEntityManager();
em.getTransaction().begin();
entity = (LobEntity) em.find(getLobEntityClass(), 1);
assertEquals(string, getStreamContentAsString(entity.getStream()));
em.getTransaction().commit();
em.close();
}
public void testDelete() {
if (!isDatabaseSupported()) return;
insert(newLobEntity("oOOOOOo", 1));
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity entity = (LobEntity) em.find(getLobEntityClass(), 1);
em.remove(entity);
em.getTransaction().commit();
em.close();
em = emf.createEntityManager();
em.getTransaction().begin();
Query q = em.createQuery(getSelectQuery());
assertEquals(0, q.getResultList().size());
em.getTransaction().commit();
em.close();
}
public void testLifeCycleInsertFlushModify() {
if (!isDatabaseSupported()) return;
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity le = newLobEntity("oOOOOOo", 1);
em.persist(le);
em.flush();
changeStream(le, "iIIIIIi");
em.getTransaction().commit();
em.close();
}
public void testLifeCycleLoadFlushModifyFlush() {
if (!isDatabaseSupported()) return;
insert(newLobEntity("oOOOOOo", 1));
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity entity = (LobEntity) em.find(getLobEntityClass(), 1);
em.flush();
changeStream(entity, "iIIIIIi");
em.flush();
em.getTransaction().commit();
em.close();
}
public void testReadingMultipleTimesWithASingleConnection()
throws IOException {
if (!isDatabaseSupported()) return;
insert(newLobEntity("oOOOOOo", 1));
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity le = (LobEntity) em.find(getLobEntityClass(), 1);
String string = "iIIIIIi";
changeStream(le, string);
em.getTransaction().commit();
em.close();
em = emf.createEntityManager();
em.getTransaction().begin();
le = (LobEntity) em.find(getLobEntityClass(), 1);
assertNotNull(le.getStream());
LobEntity entity = newLobEntity("oOOOOOo", 2);
em.persist(entity);
assertEquals(string, getStreamContentAsString(le.getStream()));
em.getTransaction().commit();
em.close();
}
public void testDataCache() {
if (!isDatabaseSupported()) return;
OpenJPAEntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity le = newLobEntity("oOOOOOo", 1);
em.persist(le);
em.getTransaction().commit();
OpenJPAConfiguration conf = emf.getConfiguration();
Object o = em.getObjectId(le);
ClassMetaData meta = JPAFacadeHelper.getMetaData(le);
Object objectId = JPAFacadeHelper.toOpenJPAObjectId(meta, o);
DataCachePCData pcd =
conf.getDataCacheManagerInstance()
.getSystemDataCache().get(objectId);
assertFalse(pcd.isLoaded(meta.getField("stream").getIndex()));
em.close();
}
public void testSetResetAndFlush() throws IOException {
if (!isDatabaseSupported()) return;
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity le = newLobEntity("oOOOOOo", 1);
em.persist(le);
changeStream(le, "iIIIIIi");
em.flush();
em.getTransaction().commit();
em.close();
em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity entity = (LobEntity) em.find(getLobEntityClass(), 1);
assertEquals("iIIIIIi", getStreamContentAsString(entity.getStream()));
em.getTransaction().commit();
em.close();
}
public void testSetFlushAndReset() throws IOException {
if (!isDatabaseSupported()) return;
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
LobEntity le = newLobEntity("oOOOOOo", 1);
em.persist(le);
em.flush();
changeStream(le, "iIIIIIi");
LobEntity entity = (LobEntity) em.find(getLobEntityClass(), 1);
assertEquals("iIIIIIi", getStreamContentAsString(entity.getStream()));
em.getTransaction().commit();
em.close();
}
protected abstract Class getLobEntityClass();
protected abstract String getStreamContentAsString(Object o)
throws IOException;
protected abstract LobEntity newLobEntity(String s, int id);
protected abstract LobEntity newLobEntityForLoadContent(String s, int id);
protected abstract String getSelectQuery();
protected abstract void changeStream(LobEntity le, String s);
}

View File

@ -0,0 +1,58 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.InputStream;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.apache.openjpa.persistence.Persistent;
/**
* An entity with an InputStream.
*
* @author Ignacio Andreu
* @since 1.1.0
*/
@Entity
public class InputStreamLobEntity implements LobEntity {
@Id
private int id;
@Persistent
private InputStream stream;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Object getStream() {
return stream;
}
public void setStream(Object o) {
stream = (InputStream) o;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Defines all the abstract methods from AbstractLobTest to tests the
* the LOB support with an InputStream.
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public class InputStreamLobTest extends AbstractLobTest {
protected LobEntity newLobEntity(String s, int id) {
InputStreamLobEntity isle = new InputStreamLobEntity();
isle.setId(id);
if (s != null) {
isle.setStream(new ByteArrayInputStream(s.getBytes()));
} else {
isle.setStream(null);
}
return isle;
}
protected LobEntity newLobEntityForLoadContent(String s, int id) {
InputStreamLobEntity isle = new InputStreamLobEntity();
isle.setId(id);
isle.setStream(new InputStreamWrapper(s));
return isle;
}
protected Class getLobEntityClass() {
return InputStreamLobEntity.class;
}
protected String getSelectQuery() {
return "SELECT o FROM InputStreamLobEntity o";
}
protected String getStreamContentAsString(Object o) throws IOException {
InputStream is = (InputStream) o;
String content = "";
byte[] bs = new byte[4];
int read = -1;
do {
read = is.read(bs);
if (read == -1) {
return content;
}
content = content + (new String(bs)).substring(0, read);
} while (true);
}
protected void changeStream(LobEntity le, String s) {
le.setStream(new ByteArrayInputStream(s.getBytes()));
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* This class is used to kwon where the content of the InputStream is load.
* If the content is load out of the flush then throws a
* UnsupportedOperationException
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public class InputStreamWrapper extends InputStream {
private InputStream is;
public InputStreamWrapper(String s) {
this.is = new ByteArrayInputStream(s.getBytes());
}
public int read() throws IOException {
throw new UnsupportedOperationException();
}
public int available() throws IOException {
return is.available();
}
public void close() throws IOException {
is.close();
}
public int read(byte[] b, int off, int len) throws IOException {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
for (StackTraceElement element : ste) {
if ("flush".equals(element.getMethodName())) {
return is.read(b, off, len);
}
}
throw new UnsupportedOperationException();
}
public int read(byte[] b) throws IOException {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.openjpa.jdbc.meta.strats;
/**
* Defines the methods for the entities
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public interface LobEntity {
public void setStream(Object o);
public void setId(int id);
public Object getStream();
public int getId();
}

View File

@ -0,0 +1,58 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.Reader;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.apache.openjpa.persistence.Persistent;
/**
* An entity with a Reader field.
*
* @author Ignacio Andreu
* @since 1.1.0
*/
@Entity
public class ReaderLobEntity implements LobEntity {
@Id
int id;
@Persistent
Reader stream;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Object getStream() {
return stream;
}
public void setStream(Object o) {
this.stream = (Reader) o;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
/**
* Defines all the abstract methods from AbstractLobTest to tests the
* the LOB support with a Reader.
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public class ReaderLobTest extends AbstractLobTest {
protected LobEntity newLobEntity(String s, int id) {
ReaderLobEntity rle = new ReaderLobEntity();
rle.setId(id);
if (s != null) {
rle.setStream(new CharArrayReader(s.toCharArray()));
} else {
rle.setStream(null);
}
return rle;
}
protected LobEntity newLobEntityForLoadContent(String s, int id) {
ReaderLobEntity rle = new ReaderLobEntity();
rle.setId(id);
rle.setStream(new ReaderWrapper(s));
return rle;
}
protected Class getLobEntityClass() {
return ReaderLobEntity.class;
}
protected String getSelectQuery() {
return "SELECT o FROM ReaderLobEntity o";
}
protected String getStreamContentAsString(Object o) throws IOException {
Reader r = (Reader) o;
String content = "";
char[] cs = new char[4];
int read = -1;
do {
read = r.read(cs);
if (read == -1) {
return content;
}
content = content + (new String(cs)).substring(0, read);
} while (true);
}
protected void changeStream(LobEntity le, String s) {
le.setStream(new CharArrayReader(s.toCharArray()));
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.openjpa.jdbc.meta.strats;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
/**
* This class is used to kwon where the content of the Reader is load.
* If the content is load out of the flush then throws a
* UnsupportedOperationException
*
* @author Ignacio Andreu
* @since 1.1.0
*/
public class ReaderWrapper extends Reader {
private Reader reader;
public ReaderWrapper(String s) {
this.reader = new CharArrayReader(s.toCharArray());
}
public void close() throws IOException {
reader.close();
}
public int read(char[] cbuf, int off, int len) throws IOException {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
for (StackTraceElement element : ste) {
if ("flush".equals(element.getMethodName())) {
return reader.read(cbuf, off, len);
}
}
throw new UnsupportedOperationException();
}
}