blob: db17416cbf03dff7e5de4f8cb8fd7f27a68e0dce [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.meta;
import java.sql.SQLException;
import java.util.Map;
import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ColumnIO;
import org.apache.openjpa.jdbc.schema.Index;
import org.apache.openjpa.jdbc.schema.Schemas;
import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.RowManager;
import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.MetaDataContext;
import org.apache.openjpa.meta.MetaDataModes;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.util.InternalException;
/**
* Handles optimistic lock versioning for a class.
*
* @author Abe White
*/
public class Version
implements VersionStrategy, MetaDataContext, MetaDataModes {
private static final long serialVersionUID = 1L;
private static final Localizer _loc = Localizer.forPackage(Version.class);
private final ClassMapping _mapping;
private final VersionMappingInfo _info;
private VersionStrategy _strategy = null;
private int _resMode = MODE_NONE;
private Column[] _cols = Schemas.EMPTY_COLUMNS;
private ColumnIO _io = null;
private Index _idx = null;
/**
* Constructor. Supply owning mapping.
*/
public Version(ClassMapping mapping) {
_mapping = mapping;
_info = getMappingRepository().newMappingInfo(this);
}
@Override
public MetaDataRepository getRepository() {
return _mapping.getRepository();
}
public MappingRepository getMappingRepository() {
return _mapping.getMappingRepository();
}
/**
* Return the owning mapping.
*/
public ClassMapping getClassMapping() {
return _mapping;
}
/**
* The strategy used for versioning.
*/
public VersionStrategy getStrategy() {
return _strategy;
}
/**
* The strategy used for versioning. The <code>adapt</code>
* parameter determines whether to adapt when mapping the strategy;
* use null if the strategy should not be mapped.
*/
public void setStrategy(VersionStrategy strategy, Boolean adapt) {
// set strategy first so we can access it during mapping
VersionStrategy orig = _strategy;
_strategy = strategy;
if (strategy != null) {
try {
strategy.setVersion(this);
if (adapt != null)
strategy.map(adapt);
} catch (RuntimeException re) {
// reset strategy
_strategy = orig;
throw re;
}
}
}
/**
* Raw mapping data.
*/
public VersionMappingInfo getMappingInfo() {
return _info;
}
/**
* Columns used for versioning.
*/
public Column[] getColumns() {
return _cols;
}
/**
* Columns used for versioning.
*/
public void setColumns(Column[] cols) {
if (cols == null)
cols = Schemas.EMPTY_COLUMNS;
_cols = cols;
}
/**
* I/O information on the version columns.
*/
public ColumnIO getColumnIO() {
return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
}
/**
* I/O information on the version columns.
*/
public void setColumnIO(ColumnIO io) {
_io = io;
}
/**
* Index on the version columns, or null if none.
*/
public Index getIndex() {
return _idx;
}
/**
* Index on the version columns, or null if none.
*/
public void setIndex(Index idx) {
_idx = idx;
}
/**
* Increment the reference count of used schema components.
*/
public void refSchemaComponents() {
for (int i = 0; i < _cols.length; i++)
_cols[i].ref();
}
/**
* Clear mapping information, including strategy.
*/
public void clearMapping() {
_strategy = null;
_cols = Schemas.EMPTY_COLUMNS;
_idx = null;
_info.clear();
setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
}
/**
* Update {@link MappingInfo} with our current mapping information.
*/
public void syncMappingInfo() {
_info.syncWith(this);
// setup the version field with our mapping info
FieldMapping fm = _mapping.getVersionFieldMapping();
if (fm != null) {
// erase explicit strategy if it is standard version strategy for
// field type
if (_info.getStrategy() != null
&& _info.getStrategy().equals(getMappingRepository().
defaultStrategy(this, fm).getAlias()))
_info.setStrategy(null);
fm.getMappingInfo().clear();
fm.getValueInfo().clear();
fm.getKeyMapping().getValueInfo().clear();
fm.getElementMapping().getValueInfo().clear();
fm.getValueInfo().copy(_info);
_info.clear();
}
}
/**
* Resolve mode.
*/
public int getResolve() {
return _resMode;
}
/**
* Resolve mode.
*/
public void setResolve(int mode) {
_resMode = mode;
}
/**
* Resolve mode.
*/
public void setResolve(int mode, boolean on) {
if (mode == MODE_NONE)
_resMode = mode;
else if (on)
_resMode |= mode;
else
_resMode &= ~mode;
}
/**
* Resolve mapping information.
*/
public boolean resolve(int mode) {
if ((_resMode & mode) == mode)
return true;
int cur = _resMode;
_resMode |= mode;
if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
resolveMapping();
if ((mode & MODE_MAPPING_INIT) != 0 && (cur & MODE_MAPPING_INIT) == 0)
_strategy.initialize();
return false;
}
/**
* Setup mapping.
*/
private void resolveMapping() {
// if there is a version field, copy mapping info from it
FieldMapping fm = _mapping.getVersionFieldMapping();
if (fm != null)
_info.copy(fm.getValueInfo());
// map strategy
MappingRepository repos = getMappingRepository();
if (_strategy == null)
repos.getStrategyInstaller().installStrategy(this);
Log log = repos.getLog();
if (log.isTraceEnabled())
log.trace(_loc.get("strategy", this, _strategy.getAlias()));
// mark columns as mapped
Column[] cols = getColumns();
ColumnIO io = getColumnIO();
for (int i = 0; i < cols.length; i++) {
if (io.isInsertable(i, false))
cols[i].setFlag(Column.FLAG_DIRECT_INSERT, true);
if (io.isUpdatable(i, false))
cols[i].setFlag(Column.FLAG_DIRECT_UPDATE, true);
}
}
//////////////////////////////////
// VersionStrategy implementation
//////////////////////////////////
@Override
public String getAlias() {
return assertStrategy().getAlias();
}
@Override
public void map(boolean adapt) {
assertStrategy().map(adapt);
}
@Override
public void initialize() {
assertStrategy().initialize();
}
@Override
public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
assertStrategy().insert(sm, store, rm);
}
@Override
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
assertStrategy().update(sm, store, rm);
}
@Override
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
assertStrategy().delete(sm, store, rm);
}
@Override
public Boolean isCustomInsert(OpenJPAStateManager sm, JDBCStore store) {
return assertStrategy().isCustomInsert(sm, store);
}
@Override
public Boolean isCustomUpdate(OpenJPAStateManager sm, JDBCStore store) {
return assertStrategy().isCustomUpdate(sm, store);
}
@Override
public Boolean isCustomDelete(OpenJPAStateManager sm, JDBCStore store) {
return assertStrategy().isCustomDelete(sm, store);
}
@Override
public void customInsert(OpenJPAStateManager sm, JDBCStore store)
throws SQLException {
assertStrategy().customInsert(sm, store);
}
@Override
public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
throws SQLException {
assertStrategy().customUpdate(sm, store);
}
@Override
public void customDelete(OpenJPAStateManager sm, JDBCStore store)
throws SQLException {
assertStrategy().customDelete(sm, store);
}
@Override
public void setVersion(Version owner) {
assertStrategy().setVersion(owner);
}
@Override
public boolean select(Select sel, ClassMapping mapping) {
return assertStrategy().select(sel, mapping);
}
@Override
public Object load(OpenJPAStateManager sm, JDBCStore store, Result res)
throws SQLException {
return assertStrategy().load(sm, store, res);
}
@Override
public Object load(OpenJPAStateManager sm, JDBCStore store, Result res, Joins joins)
throws SQLException {
return assertStrategy().load(sm, store, res, joins);
}
@Override
public void afterLoad(OpenJPAStateManager sm, JDBCStore store) {
assertStrategy().afterLoad(sm, store);
}
@Override
public boolean checkVersion(OpenJPAStateManager sm, JDBCStore store,
boolean updateVersion)
throws SQLException {
return assertStrategy().checkVersion(sm, store, updateVersion);
}
@Override
public int compareVersion(Object v1, Object v2) {
return assertStrategy().compareVersion(v1, v2);
}
private VersionStrategy assertStrategy() {
if (_strategy == null)
throw new InternalException();
return _strategy;
}
@Override
public String toString() {
return _mapping + "<version>";
}
/**
* @return a Map<Column,Object> specifying how to update each version
* column in this instance during a bulk update.
*
* @since 1.0.0
*/
@Override
public Map<Column,?> getBulkUpdateValues() {
return _strategy.getBulkUpdateValues();
}
}