blob: a00b5a31ed51486c07e6365c6c50ee879c3ab155 [file] [log] [blame]
/*
* 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.kernel;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.Connection;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.FetchConfigurationImpl;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.lib.rop.EagerResultList;
import org.apache.openjpa.lib.rop.ListResultObjectProvider;
import org.apache.openjpa.lib.rop.ResultList;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.lib.rop.SimpleResultList;
import org.apache.openjpa.lib.rop.SoftRandomAccessResultList;
import org.apache.openjpa.lib.rop.WindowResultList;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.util.UserException;
/**
* JDBC extensions to OpenJPA's {@link FetchConfiguration}.
*
* @author Abe White
* @nojavadoc
*/
public class JDBCFetchConfigurationImpl
extends FetchConfigurationImpl
implements JDBCFetchConfiguration {
private static final Localizer _loc = Localizer.forPackage
(JDBCFetchConfigurationImpl.class);
/**
* Configurable JDBC state shared throughout a traversal chain.
*/
protected static class JDBCConfigurationState implements Serializable {
public int eagerMode = 0;
public int subclassMode = 0;
public int type = 0;
public int direction = 0;
public int size = 0;
public int syntax = 0;
public Set joins = null;
public Set fetchInnerJoins = null;
public int isolationLevel = -1;
}
protected final JDBCConfigurationState _state;
public JDBCFetchConfigurationImpl() {
this(null, null);
}
protected JDBCFetchConfigurationImpl(ConfigurationState state,
JDBCConfigurationState jstate) {
super(state);
_state = (jstate == null) ? new JDBCConfigurationState() : jstate;
}
protected FetchConfigurationImpl newInstance(ConfigurationState state) {
JDBCConfigurationState jstate = (state == null) ? null : _state;
return new JDBCFetchConfigurationImpl(state, jstate);
}
public void setContext(StoreContext ctx) {
super.setContext(ctx);
JDBCConfiguration conf = getJDBCConfiguration();
if (conf == null)
return;
setEagerFetchMode(conf.getEagerFetchModeConstant());
setSubclassFetchMode(conf.getSubclassFetchModeConstant());
setResultSetType(conf.getResultSetTypeConstant());
setFetchDirection(conf.getFetchDirectionConstant());
setLRSSize(conf.getLRSSizeConstant());
setJoinSyntax(conf.getDBDictionaryInstance().joinSyntax);
}
public void copy(FetchConfiguration fetch) {
super.copy(fetch);
JDBCFetchConfiguration jf = (JDBCFetchConfiguration) fetch;
setEagerFetchMode(jf.getEagerFetchMode());
setSubclassFetchMode(jf.getSubclassFetchMode());
setResultSetType(jf.getResultSetType());
setFetchDirection(jf.getFetchDirection());
setLRSSize(jf.getLRSSize());
setJoinSyntax(jf.getJoinSyntax());
addJoins(jf.getJoins());
}
public int getEagerFetchMode() {
return _state.eagerMode;
}
public JDBCFetchConfiguration setEagerFetchMode(int mode) {
if (mode == DEFAULT) {
JDBCConfiguration conf = getJDBCConfiguration();
if (conf != null)
mode = conf.getEagerFetchModeConstant();
}
if (mode != DEFAULT)
_state.eagerMode = mode;
return this;
}
public int getSubclassFetchMode() {
return _state.subclassMode;
}
public int getSubclassFetchMode(ClassMapping cls) {
if (cls == null)
return _state.subclassMode;
int mode = cls.getSubclassFetchMode();
if (mode == DEFAULT)
return _state.subclassMode;
return Math.min(mode, _state.subclassMode);
}
public JDBCFetchConfiguration setSubclassFetchMode(int mode) {
if (mode == DEFAULT) {
JDBCConfiguration conf = getJDBCConfiguration();
if (conf != null)
mode = conf.getSubclassFetchModeConstant();
}
if (mode != DEFAULT)
_state.subclassMode = mode;
return this;
}
public int getResultSetType() {
return _state.type;
}
public JDBCFetchConfiguration setResultSetType(int type) {
if (type == DEFAULT) {
JDBCConfiguration conf = getJDBCConfiguration();
if (conf != null)
_state.type = conf.getResultSetTypeConstant();
} else
_state.type = type;
return this;
}
public int getFetchDirection() {
return _state.direction;
}
public JDBCFetchConfiguration setFetchDirection(int direction) {
if (direction == DEFAULT) {
JDBCConfiguration conf = getJDBCConfiguration();
if (conf != null)
_state.direction = conf.getFetchDirectionConstant();
} else
_state.direction = direction;
return this;
}
public int getLRSSize() {
return _state.size;
}
public JDBCFetchConfiguration setLRSSize(int size) {
if (size == DEFAULT) {
JDBCConfiguration conf = getJDBCConfiguration();
if (conf != null)
_state.size = conf.getLRSSizeConstant();
} else
_state.size = size;
return this;
}
public int getJoinSyntax() {
return _state.syntax;
}
public JDBCFetchConfiguration setJoinSyntax(int syntax) {
if (syntax == DEFAULT) {
JDBCConfiguration conf = getJDBCConfiguration();
if (conf != null)
_state.syntax = conf.getDBDictionaryInstance().joinSyntax;
} else
_state.syntax = syntax;
return this;
}
public ResultList newResultList(ResultObjectProvider rop) {
// if built around a list, just use a simple wrapper
if (rop instanceof ListResultObjectProvider)
return new SimpleResultList(rop);
// if built around a paging list, use a window provider with the
// same window size
if (rop instanceof PagingResultObjectProvider)
return new WindowResultList(rop, ((PagingResultObjectProvider)
rop).getPageSize());
// if fetch size < 0 just read in all results immediately
if (getFetchBatchSize() < 0)
return new EagerResultList(rop);
// if foward only or forward direction use a forward window
if (_state.type == ResultSet.TYPE_FORWARD_ONLY
|| _state.direction == ResultSet.FETCH_FORWARD
|| !rop.supportsRandomAccess()) {
if (getFetchBatchSize() > 0 && getFetchBatchSize() <= 50)
return new WindowResultList(rop, getFetchBatchSize());
return new WindowResultList(rop, 50);
}
// if skipping around use a caching random access list
if (_state.direction == ResultSet.FETCH_UNKNOWN)
return new SoftRandomAccessResultList(rop);
// scrolling reverse... just use non-caching simple result list
return new SimpleResultList(rop);
}
public Set getJoins() {
return (_state.joins == null) ? Collections.EMPTY_SET : _state.joins;
}
public boolean hasJoin(String field) {
return _state.joins != null && _state.joins.contains(field);
}
public JDBCFetchConfiguration addJoin(String join) {
if (StringUtils.isEmpty(join))
throw new UserException(_loc.get("null-join"));
lock();
try {
if (_state.joins == null)
_state.joins = new HashSet();
_state.joins.add(join);
} finally {
unlock();
}
return this;
}
public JDBCFetchConfiguration addJoins(Collection joins) {
if (joins == null || joins.isEmpty())
return this;
for (Iterator itr = joins.iterator(); itr.hasNext();)
addJoin((String) itr.next());
return this;
}
public JDBCFetchConfiguration removeJoin(String field) {
lock();
try {
if (_state.joins != null)
_state.joins.remove(field);
} finally {
unlock();
}
return this;
}
public JDBCFetchConfiguration removeJoins(Collection joins) {
lock();
try {
if (_state.joins != null)
_state.joins.removeAll(joins);
} finally {
unlock();
}
return this;
}
public JDBCFetchConfiguration clearJoins() {
lock();
try {
if (_state.joins != null)
_state.joins.clear();
} finally {
unlock();
}
return this;
}
public int getIsolation() {
return _state.isolationLevel;
}
public JDBCFetchConfiguration setIsolation(int level) {
if (level != -1 && level != DEFAULT
&& level != Connection.TRANSACTION_NONE
&& level != Connection.TRANSACTION_READ_UNCOMMITTED
&& level != Connection.TRANSACTION_READ_COMMITTED
&& level != Connection.TRANSACTION_REPEATABLE_READ
&& level != Connection.TRANSACTION_SERIALIZABLE)
throw new IllegalArgumentException(
_loc.get("bad-level", new Integer(level)).getMessage());
if (level == DEFAULT)
_state.isolationLevel = -1;
else
_state.isolationLevel = level;
return this;
}
public JDBCFetchConfiguration traverseJDBC(FieldMetaData fm) {
return (JDBCFetchConfiguration) traverse(fm);
}
/**
* Access JDBC configuration information. May return null if not a
* JDBC back-end (possible to get a JDBCFetchConfiguration on non-JDBC
* back end in remote client).
*/
private JDBCConfiguration getJDBCConfiguration() {
StoreContext ctx = getContext();
if (ctx == null)
return null;
OpenJPAConfiguration conf = ctx.getConfiguration();
if (!(conf instanceof JDBCConfiguration))
return null;
return (JDBCConfiguration) conf;
}
public Set getFetchInnerJoins() {
return (_state.fetchInnerJoins == null) ? Collections.EMPTY_SET
: _state.fetchInnerJoins;
}
public boolean hasFetchInnerJoin(String field) {
return _state.fetchInnerJoins != null &&
_state.fetchInnerJoins.contains(field);
}
public JDBCFetchConfiguration addFetchInnerJoin(String join) {
if (StringUtils.isEmpty(join))
throw new UserException(_loc.get("null-join"));
lock();
try {
if (_state.fetchInnerJoins == null)
_state.fetchInnerJoins = new HashSet();
_state.fetchInnerJoins.add(join);
} finally {
unlock();
}
return this;
}
public JDBCFetchConfiguration addFetchInnerJoins(Collection joins) {
if (joins == null || joins.isEmpty())
return this;
for (Iterator itr = joins.iterator(); itr.hasNext();)
addFetchInnerJoin((String) itr.next());
return this;
}
}