StoreManager plugin that uses JDBC to store persistent data in a
relational data store.
| Method from org.apache.openjpa.jdbc.kernel.JDBCStoreManager Detail: |
public boolean assignField(OpenJPAStateManager sm,
int field,
boolean preFlush) {
FieldMetaData fmd = sm.getMetaData().getField(field);
Object val = ImplHelper.generateFieldValue(_ctx, fmd);
if (val == null)
return false;
sm.store(field, val);
return true;
}
|
public boolean assignObjectId(OpenJPAStateManager sm,
boolean preFlush) {
ClassMetaData meta = sm.getMetaData();
if (meta.getIdentityType() == ClassMetaData.ID_APPLICATION)
return ApplicationIds.assign(sm, this, preFlush);
// datastore identity
Object val = ImplHelper.generateIdentityValue(_ctx, meta,
JavaTypes.LONG);
if (val == null && meta.getIdentityStrategy() != ValueStrategies.NATIVE)
return false;
if (val == null)
val = getDataStoreIdSequence(meta).next(_ctx, meta);
sm.setObjectId(newDataStoreId(val, meta));
return true;
}
|
public void beforeStateChange(OpenJPAStateManager sm,
PCState fromState,
PCState toState) {
}
|
public void begin() {
_active = true;
try {
if ((!_ctx.isManaged() || !_conf.isConnectionFactoryModeManaged())
&& _conn.getAutoCommit())
_conn.setAutoCommit(false);
} catch (SQLException se) {
_active = false;
throw SQLExceptions.getStore(se, _dict);
}
}
|
public void beginOptimistic() {
}
|
public boolean cancelAll() {
// note that this method does not lock the context, since
// we want to allow a different thread to be able to cancel the
// outstanding statement on a different context
Collection stmnts;
synchronized (_stmnts) {
if (_stmnts.isEmpty())
return false;
stmnts = new ArrayList(_stmnts);
}
try {
for (Iterator itr = stmnts.iterator(); itr.hasNext();)
((Statement) itr.next()).cancel();
return true;
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
}
}
|
public void close() {
if (_conn != null)
_conn.free();
}
|
public void commit() {
try {
if (!_ctx.isManaged() || !_conf.isConnectionFactoryModeManaged())
_conn.commit();
} catch (SQLException se) {
try {
_conn.rollback();
} catch (SQLException se2) {
}
throw SQLExceptions.getStore(se, _dict);
} finally {
_active = false;
}
}
|
public int compareVersion(OpenJPAStateManager state,
Object v1,
Object v2) {
ClassMapping mapping = (ClassMapping) state.getMetaData();
return mapping.getVersion().compareVersion(v1, v2);
}
|
protected JDBCStoreManager.RefCountConnection connectInternal() throws SQLException {
return new RefCountConnection(_ds.getConnection());
}
Connect to the database. This method is separated out so that it
can be overridden. |
public Object copyDataStoreId(Object oid,
ClassMetaData meta) {
Id id = (Id) oid;
return new Id(meta.getDescribedType(), id.getId(), id.hasSubclasses());
}
|
public ResultObjectProvider executeExtent(ClassMetaData meta,
boolean subclasses,
FetchConfiguration fetch) {
ClassMapping mapping = (ClassMapping) meta;
final ClassMapping[] mappings;
if (subclasses)
mappings = mapping.getIndependentAssignableMappings();
else
mappings = new ClassMapping[] { mapping };
ResultObjectProvider[] rops = null;
final JDBCFetchConfiguration jfetch = (JDBCFetchConfiguration) fetch;
if (jfetch.getSubclassFetchMode(mapping) != jfetch.EAGER_JOIN)
rops = new ResultObjectProvider[mappings.length];
try {
// check for custom loads
ResultObjectProvider rop;
for (int i = 0; i < mappings.length; i++) {
rop = mappings[i].customLoad(this, subclasses, jfetch, 0,
Long.MAX_VALUE);
if (rop != null) {
if (rops == null)
rops = new ResultObjectProvider[mappings.length];
rops[i] = rop;
}
}
// if we're selecting independent mappings separately or have
// custom loads, do individual selects for each class
rop = null;
if (rops != null) {
for (int i = 0; i < mappings.length; i++) {
if (rops[i] != null)
continue;
Select sel = _sql.newSelect();
sel.setLRS(true);
BitSet paged = selectExtent(sel, mappings[i], jfetch,
subclasses);
if (paged == null)
rops[i] = new InstanceResultObjectProvider(sel,
mappings[i], this, jfetch);
else
rops[i] = new PagingResultObjectProvider(sel,
mappings[i], this, jfetch, paged, Long.MAX_VALUE);
}
if (rops.length == 1)
return rops[0];
return new MergedResultObjectProvider(rops);
}
// perform a union on all independent classes
Union union = _sql.newUnion(mappings.length);
union.setLRS(true);
final BitSet[] paged = new BitSet[mappings.length];
union.select(new Union.Selector() {
public void select(Select sel, int idx) {
paged[idx] = selectExtent(sel, mappings[idx], jfetch,
subclasses);
}
});
// using paging rop if any union element has paged fields
for (int i = 0; i < paged.length; i++) {
if (paged[i] != null)
return new PagingResultObjectProvider(union, mappings,
JDBCStoreManager.this, jfetch, paged, Long.MAX_VALUE);
}
return new InstanceResultObjectProvider(union, mappings[0], this,
jfetch);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
}
}
|
public boolean exists(OpenJPAStateManager sm,
Object context) {
// add where conditions on base class to avoid joins if subclass
// doesn't use oid as identifier
ClassMapping mapping = (ClassMapping) sm.getMetaData();
return exists(mapping, sm.getObjectId(), context);
}
|
public Object find(Object oid,
ValueMapping vm,
JDBCFetchConfiguration fetch) {
if (oid == null)
return null;
Object pc = _ctx.find(oid, fetch, null, null, 0);
if (pc == null && vm != null) {
OrphanedKeyAction action = _conf.getOrphanedKeyActionInstance();
pc = action.orphan(oid, null, vm);
}
return pc;
}
Find the object with the given oid. |
public Collection flush(Collection sms) {
return _conf.getUpdateManagerInstance().flush(sms, this);
}
|
public Object getClientConnection() {
return new ClientConnection(getConnection());
}
|
public JDBCConfiguration getConfiguration() {
return _conf;
}
|
public Connection getConnection() {
connect(true);
return _conn;
}
|
public StoreContext getContext() {
return _ctx;
}
|
public DBDictionary getDBDictionary() {
return _dict;
}
|
protected DataSource getDataSource() {
return _ds;
}
|
public Seq getDataStoreIdSequence(ClassMetaData meta) {
if (meta.getIdentityStrategy() == ValueStrategies.NATIVE
|| meta.getIdentityStrategy() == ValueStrategies.NONE)
return _conf.getSequenceInstance();
return null;
}
|
public Class getDataStoreIdType(ClassMetaData meta) {
return Id.class;
}
|
public JDBCFetchConfiguration getFetchConfiguration() {
return (JDBCFetchConfiguration) _ctx.getFetchConfiguration();
}
|
public JDBCLockManager getLockManager() {
return _lm;
}
|
public Class getManagedType(Object oid) {
if (oid instanceof Id)
return ((Id) oid).getType();
return null;
}
|
public SQLFactory getSQLFactory() {
return _sql;
}
|
protected Class getType(Result res,
ClassMapping mapping) {
if (res == null)
return mapping.getDescribedType();
return null;
}
This method is to provide override for non-JDBC or JDBC-like
implementation of getting type from the result set. |
public Seq getValueSequence(FieldMetaData fmd) {
return null;
}
|
protected void getVersion(ClassMapping mapping,
OpenJPAStateManager sm,
Result res) throws SQLException {
mapping.getVersion().afterLoad(sm, this);
}
This method is to provide override for non-JDBC or JDBC-like
implementation of getting version from the result set. |
public boolean initialize(OpenJPAStateManager sm,
PCState state,
FetchConfiguration fetch,
Object context) {
ConnectionInfo info = (ConnectionInfo) context;
try {
return initializeState(sm, state, (JDBCFetchConfiguration) fetch,
info);
} catch (ClassNotFoundException cnfe) {
throw new UserException(cnfe);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
}
}
|
protected boolean initializeState(OpenJPAStateManager sm,
PCState state,
JDBCFetchConfiguration fetch,
ConnectionInfo info) throws ClassNotFoundException, SQLException {
Object oid = sm.getObjectId();
ClassMapping mapping = (ClassMapping) sm.getMetaData();
Result res = null;
try {
if (info != null && info.result != null) {
res = info.result;
info.sm = sm;
if (info.mapping == null)
info.mapping = mapping;
mapping = info.mapping;
} else if (oid instanceof OpenJPAId
&& !((OpenJPAId) oid).hasSubclasses()) {
Boolean custom = customLoad(sm, mapping, state, fetch);
if (custom != null)
return custom.booleanValue();
res = getInitializeStateResult(sm, mapping, fetch,
Select.SUBS_EXACT);
if (res == null && !selectPrimaryKey(sm, mapping, fetch))
return false;
if (isEmptyResult(res))
return false;
} else {
ClassMapping[] mappings = mapping.
getIndependentAssignableMappings();
if (mappings.length == 1) {
mapping = mappings[0];
Boolean custom = customLoad(sm, mapping, state, fetch);
if (custom != null)
return custom.booleanValue();
res = getInitializeStateResult(sm, mapping, fetch,
Select.SUBS_ANY_JOINABLE);
if (res == null && !selectPrimaryKey(sm, mapping, fetch))
return false;
} else
res = getInitializeStateUnionResult(sm, mapping, mappings,
fetch);
if (isEmptyResult(res))
return false;
}
// figure out what type of object this is; the state manager
// only guarantees to provide a base class
Class type;
if ((type = getType(res, mapping)) == null) {
if (res.getBaseMapping() != null)
mapping = res.getBaseMapping();
res.startDataRequest(mapping.getDiscriminator());
try {
type = mapping.getDiscriminator().getClass(this, mapping,
res);
} finally {
res.endDataRequest();
}
}
// initialize the state manager; this may change the mapping
// and the object id instance if the type as determined
// from the indicator is a subclass of expected type
sm.initialize(type, state);
// load the selected mappings into the given state manager
if (res != null) {
// re-get the mapping in case the instance was a subclass
mapping = (ClassMapping) sm.getMetaData();
load(mapping, sm, fetch, res);
getVersion(mapping, sm, res);
}
return true;
} finally {
if (res != null && (info == null || res != info.result))
res.close();
}
}
Initialize a newly-loaded instance. |
protected boolean isEmptyResult(Result res) throws SQLException {
if (res != null && !res.next())
return true;
return false;
}
This method is to provide override for non-JDBC or JDBC-like
implementation of checking whether the result set is empty or not. |
public Object load(ClassMapping mapping,
JDBCFetchConfiguration fetch,
BitSet exclude,
Result result) throws SQLException {
if (!mapping.isMapped())
throw new InvalidStateException(_loc.get("virtual-mapping",
mapping));
// get the object id for the row; base class selects pk columns
ClassMapping base = mapping;
while (base.getJoinablePCSuperclassMapping() != null)
base = base.getJoinablePCSuperclassMapping();
Object oid = base.getObjectId(this, result, null, true, null);
if (oid == null)
return null;
ConnectionInfo info = new ConnectionInfo();
info.result = result;
info.mapping = mapping;
return _ctx.find(oid, fetch, exclude, info, 0);
}
Load the object in the current row of the given result. |
public boolean load(OpenJPAStateManager sm,
BitSet fields,
FetchConfiguration fetch,
int lockLevel,
Object context) {
JDBCFetchConfiguration jfetch = (JDBCFetchConfiguration) fetch;
// get a connection, or reuse current one
ConnectionInfo info = (ConnectionInfo) context;
Result res = null;
if (info != null) {
// if initialize() fails to load required fields, then this method
// is called; make sure not to try to use the given result if it's
// the same one we just failed to completely initialize() with
if (info.sm != sm)
res = info.result;
info.sm = null;
}
try {
// if there's an existing result, load all we can from it
ClassMapping mapping = (ClassMapping) sm.getMetaData();
if (res != null) {
load(mapping, sm, jfetch, res);
removeLoadedFields(sm, fields);
}
// if the instance is hollow and there's a customized
// get by id method, use it
if (sm.getLoaded().length() == 0
&& mapping.customLoad(sm, this, null, jfetch))
removeLoadedFields(sm, fields);
//### select is kind of a big object, and in some cases we don't
//### use it... would it be worth it to have a small shell select
//### object that only creates a real select when actually used?
Select sel = _sql.newSelect();
if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
EagerFetchModes.EAGER_JOIN, true, false)) {
sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
res = sel.execute(this, jfetch, lockLevel);
try {
if (isEmptyResult(res))
return false;
load(mapping, sm, jfetch, res);
} finally {
res.close();
}
}
// now allow the fields to load themselves individually too
FieldMapping[] fms = mapping.getFieldMappings();
for (int i = 0; i < fms.length; i++)
if (fields.get(i) && !sm.getLoaded().get(i))
fms[i].load(sm, this, jfetch.traverseJDBC(fms[i]));
mapping.getVersion().afterLoad(sm, this);
return true;
} catch (ClassNotFoundException cnfe) {
throw new StoreException(cnfe);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
}
}
|
public Collection loadAll(Collection sms,
PCState state,
int load,
FetchConfiguration fetch,
Object context) {
return ImplHelper.loadAll(sms, this, state, load, fetch, context);
}
|
public void loadSubclasses(ClassMapping mapping) {
Discriminator dsc = mapping.getDiscriminator();
if (dsc.getSubclassesLoaded())
return;
// if the subclass list is set, no need to load subs
if (mapping.getRepository().getPersistentTypeNames(false,
_ctx.getClassLoader()) != null) {
dsc.setSubclassesLoaded(true);
return;
}
try {
dsc.loadSubclasses(this);
} catch (ClassNotFoundException cnfe) {
throw new StoreException(cnfe);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
}
}
Makes sure all subclasses of the given type are loaded in the JVM.
This is usually done automatically. |
public Object newDataStoreId(Object val,
ClassMetaData meta) {
return Id.newInstance(meta.getDescribedType(), val);
}
|
public Id newDataStoreId(long id,
ClassMapping mapping,
boolean subs) {
return new Id(mapping.getDescribedType(), id, subs);
}
|
public FetchConfiguration newFetchConfiguration() {
return new JDBCFetchConfigurationImpl();
}
|
public StoreQuery newQuery(String language) {
ExpressionParser ep = QueryLanguages.parserForLanguage(language);
if (ep != null)
return new JDBCStoreQuery(this, ep);
if (QueryLanguages.LANG_SQL.equals(language))
return new SQLStoreQuery(this);
return null;
}
|
public void releaseConnection() {
if (_conn != null)
_conn.setRetain(false);
}
|
public void retainConnection() {
connect(false);
_conn.setRetain(true);
}
|
public void rollback() {
// already rolled back ourselves?
if (!_active)
return;
try {
if (_conn != null
&& (!_ctx.isManaged() || !_conf
.isConnectionFactoryModeManaged()))
_conn.rollback();
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
} finally {
_active = false;
}
}
|
public void rollbackOptimistic() {
}
|
public boolean select(Select sel,
ClassMapping mapping,
int subs,
OpenJPAStateManager sm,
BitSet fields,
JDBCFetchConfiguration fetch,
int eager,
boolean ident,
boolean outer) {
// add class conditions so that they're cloned for any batched selects
boolean joinedSupers = false;
if ((sm == null || sm.getPCState() == PCState.TRANSIENT)
&& (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE)) {
loadSubclasses(mapping);
Joins joins = (outer) ? sel.newOuterJoins() : null;
joinedSupers = mapping.getDiscriminator().addClassConditions(sel,
subs == Select.SUBS_JOINABLE, joins);
}
// create all our eager selects so that those fields are reserved
// and cannot be reused during the actual eager select process,
// preventing infinite recursion
eager = Math.min(eager, fetch.getEagerFetchMode());
FieldMapping eagerToMany = createEagerSelects(sel, mapping, sm, fields,
fetch, eager);
// select all base class mappings; do this after batching so that
// the joins needed by these selects don't get in the WHERE clause
// of the batched selects
int seld = selectBaseMappings(sel, mapping, mapping, sm, fields,
fetch, eager, eagerToMany, ident, joinedSupers);
// select eager to-many relations last because during load they
// advance the result set and could exhaust it, so no other mappings
// can load afterwords
if (eagerToMany != null)
eagerToMany.selectEagerJoin(sel, sm, this,
fetch.traverseJDBC(eagerToMany), eager);
// optionally select subclass mappings
if (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_ANY_JOINABLE)
selectSubclassMappings(sel, mapping, sm, fetch);
if (sm != null)
sel.setDistinct(false);
return seld > 0;
}
For implementation use only.
Return a select for the proper mappings. Return null if no select is
needed. The method is designed to be complementary to the load methods. |
public void setContext(StoreContext ctx) {
setContext(ctx, (JDBCConfiguration) ctx.getConfiguration());
}
|
public void setContext(StoreContext ctx,
JDBCConfiguration conf) {
_ctx = ctx;
_conf = conf;
_dict = _conf.getDBDictionaryInstance();
_sql = _conf.getSQLFactoryInstance();
LockManager lm = ctx.getLockManager();
if (lm instanceof JDBCLockManager)
_lm = (JDBCLockManager) lm;
if (!ctx.isManaged() && _conf.isConnectionFactoryModeManaged())
_ds = _conf.getDataSource2(ctx);
else
_ds = _conf.getDataSource(ctx);
if (_conf.getUpdateManagerInstance().orderDirty())
ctx.setOrderDirtyObjects(true);
}
|
public boolean syncVersion(OpenJPAStateManager sm,
Object context) {
ClassMapping mapping = (ClassMapping) sm.getMetaData();
try {
return mapping.getVersion().checkVersion(sm, this, true);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _dict);
}
}
|