org.apache.openjpa.jdbc.meta.ValueMappingInfo Maven / Gradle / Ivy
The newest version!
/*
* 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.util.Collections;
import java.util.List;
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ColumnIO;
import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.schema.Index;
import org.apache.openjpa.jdbc.schema.SchemaGroup;
import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.jdbc.schema.Unique;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.MetaDataException;
/**
* Information about the mapping from a field value to the schema, in
* raw form. The columns and tables used in mapping info will not be part of
* the {@link SchemaGroup} used at runtime. Rather, they will be structs
* with the relevant pieces of information filled in.
*
* @author Abe White
*/
public class ValueMappingInfo extends MappingInfo {
private static final long serialVersionUID = 1L;
private static final Localizer _loc = Localizer.forPackage
(ValueMappingInfo.class);
private boolean _criteria = false;
private boolean _canNull = true;
private List _mapsIdCols = null;
/**
* Whether to use class criteria when joining to related type.
*/
public boolean getUseClassCriteria() {
return _criteria;
}
/**
* Whether to use class criteria when joining to related type.
*/
public void setUseClassCriteria(boolean criteria) {
_criteria = criteria;
}
/**
* Whether user has explicitly turned null indicator column off.
*/
public boolean canIndicateNull() {
return _canNull;
}
/**
* Whether user has explicitly turned null indicator column off.
*/
public void setCanIndicateNull(boolean ind) {
_canNull = ind;
}
/**
* Return the join from this value to its related type.
*
* @param name base name for value mapping
* @param inversable whether an inverse join is allowed
* @deprecated
*/
@Deprecated
public ForeignKey getTypeJoin(final ValueMapping val, final String name,
boolean inversable, boolean adapt) {
return getTypeJoin(val, DBIdentifier.newForeignKey(name), inversable, adapt);
}
public ForeignKey getTypeJoin(final ValueMapping val, final DBIdentifier name,
boolean inversable, boolean adapt) {
ClassMapping rel = val.getTypeMapping();
if (rel == null)
return null;
ForeignKeyDefaults def = new ForeignKeyDefaults() {
@Override
public ForeignKey get(Table local, Table foreign, boolean inverse) {
return val.getMappingRepository().getMappingDefaults().
getForeignKey(val, name, local, foreign, inverse);
}
@Override
public void populate(Table local, Table foreign, Column col,
Object target, boolean inverse, int pos, int cols) {
val.getMappingRepository().getMappingDefaults().
populateForeignKeyColumn(val, name, local, foreign, col,
target, inverse, pos, cols);
}
};
Table table = getTable(val);
return createForeignKey(val, null, getColumns(), def,
table, val.getFieldMapping().
getDefiningMapping(), rel, inversable, adapt);
}
public Table getTable(ValueMapping val) {
FieldMapping field = val.getFieldMapping();
Table table = field.getTable();
if (table == null) {
ClassMapping cls = (ClassMapping)field.getDefiningMetaData();
ValueMapping val1 = (ValueMapping)cls.getEmbeddingMetaData();
if (val1 != null)
return getTable(val1);
}
return table;
}
/**
* Return the join from the related type to this value.
* @deprecated
*/
@Deprecated
public ForeignKey getInverseTypeJoin(final ValueMapping val,
final String name, boolean adapt) {
return getInverseTypeJoin(val, DBIdentifier.newForeignKey(name), adapt);
}
public ForeignKey getInverseTypeJoin(final ValueMapping val,
final DBIdentifier name, boolean adapt) {
ClassMapping rel = val.getTypeMapping();
if (rel == null || rel.getTable() == null)
return null;
ForeignKeyDefaults def = new ForeignKeyDefaults() {
@Override
public ForeignKey get(Table local, Table foreign, boolean inverse) {
return val.getMappingRepository().getMappingDefaults().
getForeignKey(val, name, local, foreign, !inverse);
}
@Override
public void populate(Table local, Table foreign, Column col,
Object target, boolean inverse, int pos, int cols) {
val.getMappingRepository().getMappingDefaults().
populateForeignKeyColumn(val, name, local, foreign, col,
target, !inverse, pos, cols);
}
};
return createForeignKey(val, null, getColumns(), def, rel.getTable(),
rel, val.getFieldMapping().getDefiningMapping(), false, adapt);
}
/**
* Return the columns for this value, based on the given templates.
* @deprecated
*/
@Deprecated
public Column[] getColumns(ValueMapping val, String name,
Column[] tmplates, Table table, boolean adapt) {
return getColumns(val, DBIdentifier.newColumn(name), tmplates, table, adapt);
}
public Column[] getColumns(ValueMapping val, DBIdentifier name,
Column[] tmplates, Table table, boolean adapt) {
orderColumnsByTargetField(val, tmplates, adapt);
val.getMappingRepository().getMappingDefaults().populateColumns
(val, name, table, tmplates);
return createColumns(val, null, tmplates, table, adapt);
}
/**
* Make given columns match up with the target fields supplied on the
* templates.
*/
private void orderColumnsByTargetField(ValueMapping val, Column[] tmplates,
boolean adapt) {
if (tmplates.length < 2 || tmplates[0].getTargetField() == null)
return;
List cols = getColumns();
if (cols.isEmpty() || cols.size() != tmplates.length)
return;
int pos = 0;
Column cur = cols.get(0);
Column next;
for (int i = 0; i < cols.size(); i++) {
if (cur.getTargetField() == null)
throw new MetaDataException(_loc.get("no-targetfield", val));
pos = findTargetField(tmplates, cur.getTargetField());
if (pos == -1)
throw new MetaDataException(_loc.get("bad-targetfield",
val, cur.getTargetField()));
next = cols.get(pos);
cols.set(pos, cur);
cur = next;
}
}
/**
* Return the position of the template column with the given target field.
*/
public int findTargetField(Column[] tmplates, String target) {
for (int i = 0; i < tmplates.length; i++)
if (target.equals(tmplates[i].getTargetField()))
return i;
return -1;
}
/**
* Return a unique constraint for the given columns, or null if none.
* @deprecated
*/
@Deprecated
public Unique getUnique(ValueMapping val, String name, boolean adapt) {
return getUnique(val, DBIdentifier.newConstraint(name), adapt);
}
public Unique getUnique(ValueMapping val, DBIdentifier name, boolean adapt) {
Column[] cols = val.getColumns();
if (cols.length == 0)
return null;
Unique unq = val.getMappingRepository().getMappingDefaults().
getUnique(val, name, cols[0].getTable(), cols);
return createUnique(val, null, unq, cols, adapt);
}
/**
* Return an index for the given columns, or null if none.
* @deprecated
*/
@Deprecated
public Index getIndex(ValueMapping val, String name, boolean adapt) {
return getIndex(val, DBIdentifier.newIndex(name), adapt);
}
public Index getIndex(ValueMapping val, DBIdentifier name, boolean adapt) {
Column[] cols = val.getColumns();
if (cols.length == 0)
return null;
Index idx = val.getMappingRepository().getMappingDefaults().
getIndex(val, name, cols[0].getTable(), cols);
return createIndex(val, null, idx, cols, adapt);
}
/**
* Return the null indicator column for this value, or null if none.
* @deprecated
*/
@Deprecated
public Column getNullIndicatorColumn(ValueMapping val, String name,
Table table, boolean adapt) {
return getNullIndicatorColumn(val, DBIdentifier.newColumn(name), table, adapt);
}
public Column getNullIndicatorColumn(ValueMapping val, DBIdentifier name,
Table table, boolean adapt) {
// reset IO
setColumnIO(null);
// has the user explicitly turned null indicator off?
if (!_canNull)
return null;
// extract given null-ind column
List cols = getColumns();
Column given = (cols.isEmpty()) ? null : (Column) cols.get(0);
MappingDefaults def = val.getMappingRepository().getMappingDefaults();
if (given == null && (!adapt && !def.defaultMissingInfo()))
return null;
Column tmplate = new Column();
DBIdentifier sName = DBIdentifier.append(name, "_null");
tmplate.setIdentifier(sName);
tmplate.setJavaType(JavaTypes.INT);
if (!def.populateNullIndicatorColumns(val, name, table, new Column[]
{ tmplate }) && given == null)
return null;
if (given != null && (given.getFlag(Column.FLAG_UNINSERTABLE)
|| given.getFlag(Column.FLAG_UNUPDATABLE))) {
ColumnIO io = new ColumnIO();
io.setInsertable(0, !given.getFlag(Column.FLAG_UNINSERTABLE));
io.setUpdatable(0, !given.getFlag(Column.FLAG_UNUPDATABLE));
setColumnIO(io);
}
if (given != null && !DBIdentifier.isNull(given.getIdentifier())) {
// test if given column name is actually a field name, in which
// case we use its column as the null indicator column
ClassMapping embed = val.getEmbeddedMapping();
FieldMapping efm = (embed == null) ? null
: embed.getFieldMapping(given.getIdentifier().getName());
if (efm != null && efm.getColumns().length > 0)
given.setIdentifier(efm.getColumns()[0].getIdentifier());
}
boolean compat = given == null || DBIdentifier.isNull(given.getIdentifier())
|| table == null || !table.isNameTaken(given.getIdentifier());
return mergeColumn(val, "null-ind", tmplate, compat, given,
table, adapt, def.defaultMissingInfo());
}
/**
* Synchronize internal information with the mapping data for the given
* value.
*/
public void syncWith(ValueMapping val) {
clear(false);
_criteria = val.getUseClassCriteria();
setColumnIO(val.getColumnIO());
if (val.getForeignKey() != null && val.getTypeMapping() != null
&& val.getTypeMapping().getTable() != null) {
FieldMapping fm = val.getFieldMapping();
Table local = (fm.getJoinForeignKey() != null) ? fm.getTable()
: fm.getDefiningMapping().getTable();
Table foreign;
if (val.getJoinDirection() == ValueMapping.JOIN_EXPECTED_INVERSE) {
foreign = local;
local = val.getTypeMapping().getTable();
setJoinDirection(JOIN_FORWARD);
} else {
foreign = val.getTypeMapping().getTable();
setJoinDirection((val.getJoinDirection() == ValueMapping.JOIN_FORWARD)
? JOIN_FORWARD : JOIN_INVERSE);
}
syncForeignKey(val, val.getForeignKey(), local, foreign);
} else
syncColumns(val, val.getColumns(), false);
syncIndex(val, val.getValueIndex());
syncUnique(val, val.getValueUnique());
// explicit handler strategy if the handler isn't the expected default
if (val.getHandler() != null) {
ValueHandler def = val.getFieldMapping().getMappingRepository().
defaultHandler(val);
if (def == null || val.getHandler().getClass() != def.getClass())
setStrategy(val.getHandler().getClass().getName());
}
}
@Override
protected void clear(boolean canFlags) {
super.clear(canFlags);
if (canFlags) {
_criteria = false;
_canNull = true;
}
}
@Override
public void copy(MappingInfo info) {
super.copy(info);
if (!(info instanceof ValueMappingInfo))
return;
ValueMappingInfo vinfo = (ValueMappingInfo) info;
if (!_criteria)
_criteria = vinfo.getUseClassCriteria();
if (_canNull)
_canNull = vinfo.canIndicateNull();
}
/**
* Raw column data.
*/
public List getMapsIdColumns() {
if (_mapsIdCols == null) {
return Collections.emptyList();
}
return _mapsIdCols;
}
/**
* Raw column data.
*/
public void setMapsIdColumns(List cols) {
_mapsIdCols = cols;
}
}