|
|
|
Re: eclipselink History Policy: custom field [message #1754431 is a reply to message #1724754] |
Fri, 17 February 2017 17:28 |
Kevin Jordan Messages: 4 Registered: February 2017 |
Junior Member |
|
|
I was able to add user columns using the code below. Note that it needs a separate column for the user who modified it and the user who deleted it as it currently isn't possible to do a separate insert when someone deletes it and it uses the same row as the previous modification. Injecting the user is also difficult so I have an interface (CurrentUserProvider) that will get created in my main application that sets that interface implementation in a singleton object (CurrentUserSingleton) which it calls getCurrentUsername() whenever it needs the user below.
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.history.HistoryPolicy;
import org.eclipse.persistence.internal.expressions.SQLInsertStatement;
import org.eclipse.persistence.internal.expressions.SQLUpdateStatement;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.queries.StatementQueryMechanism;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.ManyToManyMapping;
import org.eclipse.persistence.queries.DataModifyQuery;
import org.eclipse.persistence.queries.DeleteAllQuery;
import org.eclipse.persistence.queries.ModifyQuery;
import org.eclipse.persistence.queries.ObjectLevelModifyQuery;
import org.eclipse.persistence.sessions.DatabaseRecord;
import java.util.ArrayList;
import java.util.List;
/**
* Created by kjord on 2017-02-16.
*/
public class UserHistoryPolicy extends HistoryPolicy {
protected List<DatabaseField> deleteUserFields;
protected List<DatabaseField> userFields;
public void addDeleteUserFieldName(String deleteUserFieldName) {
DatabaseField deleteUserField = new DatabaseField(deleteUserFieldName);
deleteUserField.setType(ClassConstants.STRING);
// #440278
deleteUserField.setLength(6);
if (deleteUserFields == null) {
deleteUserFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance();
deleteUserFields.add(deleteUserField);
return;
}
for (DatabaseField existing : deleteUserFields) {
if (deleteUserField.getTableName()
.equals(existing.getTableName())) {
existing.setName(deleteUserField.getName());
return;
}
}
deleteUserFields.add(deleteUserField);
}
public void addUserFieldName(String userFieldName) {
DatabaseField userField = new DatabaseField(userFieldName);
userField.setType(ClassConstants.STRING);
// #440278
userField.setLength(6);
if (userFields == null) {
userFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance();
userFields.add(userField);
return;
}
for (DatabaseField existing : userFields) {
if (userField.getTableName()
.equals(existing.getTableName())) {
existing.setName(userField.getName());
return;
}
}
userFields.add(userField);
}
@Override
public Object clone() {
UserHistoryPolicy clone = (UserHistoryPolicy) super.clone();
if (userFields != null) {
clone.setUserFields(new ArrayList(userFields.size()));
for (DatabaseField field : userFields) {
clone.getUserFields()
.add(field.clone());
}
}
if (deleteUserFields != null) {
clone.setUserFields(new ArrayList(deleteUserFields.size()));
for (DatabaseField field : deleteUserFields) {
clone.getUserFields()
.add(field.clone());
}
}
return clone;
}
protected DatabaseField getDeleteUser(int i) {
return deleteUserFields.get(i);
}
protected DatabaseField getDeleteUser() {
if (deleteUserFields != null) {
return deleteUserFields.get(0);
} else {
return null;
}
}
public List<DatabaseField> getDeleteUserFields() {
return deleteUserFields;
}
public void setDeleteUserFields(List deleteUserFields) {
this.deleteUserFields = deleteUserFields;
}
protected DatabaseField getUser(int i) {
return userFields.get(i);
}
protected DatabaseField getUser() {
if (userFields != null) {
return userFields.get(0);
} else {
return null;
}
}
public List<DatabaseField> getUserFields() {
return userFields;
}
public void setUserFields(List userFields) {
this.userFields = userFields;
}
@Override
public void initialize(AbstractSession session) {
if (getMapping() != null) {
setDescriptor(getMapping().getDescriptor());
if (getMapping().isDirectCollectionMapping()) {
DatabaseTable refTable = ((DirectCollectionMapping) getMapping()).getReferenceTable();
DatabaseTable histTable = getHistoricalTables().get(0);
histTable.setName(refTable.getName());
histTable.setTableQualifier(refTable.getTableQualifier());
getStart().setTable(histTable);
getEnd().setTable(histTable);
getUser().setTable(histTable);
getDeleteUser().setTable(histTable);
} else if (getMapping().isManyToManyMapping()) {
DatabaseTable relationTable = ((ManyToManyMapping) getMapping()).getRelationTable();
DatabaseTable histTable = getHistoricalTables().get(0);
histTable.setName(relationTable.getName());
histTable.setTableQualifier(relationTable.getTableQualifier());
getStart().setTable(histTable);
getEnd().setTable(histTable);
getUser().setTable(histTable);
getDeleteUser().setTable(histTable);
}
verifyTableQualifiers(session.getPlatform());
return;
}
// Some historicalTables will be inherited from a parent policy.
int offset = getDescriptor().getTables()
.size() - getHistoricalTables().size();
// In this configuration descriptor tables, history tables, and start/end fields
// are all in the same order.
if (!getHistoricalTables().isEmpty() && getHistoricalTables().get(0)
.getName()
.equals("")) {
for (int i = 0; i < getHistoricalTables().size(); i++) {
DatabaseTable table = getHistoricalTables().get(i);
if (table.getName()
.equals("")) {
DatabaseTable mirrored = getDescriptor().getTables()
.get(i + offset);
table.setName(mirrored.getName());
table.setTableQualifier(mirrored.getTableQualifier());
}
if (getStartFields().size() < (i + 1)) {
DatabaseField startField = getStart(0).clone();
startField.setTable(table);
getStartFields().add(startField);
} else {
DatabaseField startField = getStart(i);
startField.setTable(table);
}
if (getEndFields().size() < (i + 1)) {
DatabaseField endField = getEnd(0).clone();
endField.setTable(table);
getEndFields().add(endField);
} else {
DatabaseField endField = getEnd(i);
endField.setTable(table);
}
if (getUserFields().size() < (i + 1)) {
DatabaseField userField = getUser(0).clone();
userField.setTable(table);
getUserFields().add(userField);
} else {
DatabaseField userField = getUser(i);
userField.setTable(table);
}
if (getDeleteUserFields().size() < (i + 1)) {
DatabaseField deleteUserField = getDeleteUser(0).clone();
deleteUserField.setTable(table);
getUserFields().add(deleteUserField);
} else {
DatabaseField deleteUserField = getDeleteUser(i);
deleteUserField.setTable(table);
}
}
} else {
// The user did not specify history tables/fields in order, so
// initialize will take a little longer.
List<DatabaseTable> unsortedTables = getHistoricalTables();
List<DatabaseTable> sortedTables = new ArrayList(unsortedTables.size());
List<DatabaseField> sortedStartFields = new ArrayList(unsortedTables.size());
List<DatabaseField> sortedEndFields = new ArrayList(unsortedTables.size());
boolean universalStartField = ((getStartFields().size() == 1) && (!(getStartFields().get(0)).hasTableName()));
boolean universalEndField = ((getEndFields().size() == 1) && (!(getEndFields().get(0)).hasTableName()));
DatabaseTable descriptorTable = null;
DatabaseTable historicalTable = null;
DatabaseField historyField = null;
List<DatabaseTable> descriptorTables = getDescriptor().getTables();
for (int i = offset; i < descriptorTables.size(); i++) {
descriptorTable = descriptorTables.get(i);
int index = unsortedTables.indexOf(descriptorTable);
if (index == -1) {
// this is a configuration error!
}
historicalTable = unsortedTables.get(index);
historicalTable.setTableQualifier(descriptorTable.getTableQualifier());
sortedTables.add(historicalTable);
if (universalStartField) {
historyField = getStart(0).clone();
historyField.setTable(historicalTable);
sortedStartFields.add(historyField);
} else {
for (DatabaseField field : getStartFields()) {
if (field.getTable()
.equals(historicalTable)) {
sortedStartFields.add(field);
break;
}
}
}
if (universalEndField) {
historyField = getEnd(0).clone();
historyField.setTable(historicalTable);
sortedEndFields.add(historyField);
} else {
for (DatabaseField field : getEndFields()) {
if (field.getTable()
.equals(historicalTable)) {
sortedEndFields.add(field);
break;
}
}
}
}
setHistoricalTables(sortedTables);
setStartFields(sortedStartFields);
setEndFields(sortedEndFields);
}
verifyTableQualifiers(session.getPlatform());
// A user need not set a policy on every level of an inheritance, but
// historic tables can be inherited.
if (getDescriptor().hasInheritance()) {
ClassDescriptor parentDescriptor = getDescriptor().getInheritancePolicy()
.getParentDescriptor();
while ((parentDescriptor != null) && (parentDescriptor.getHistoryPolicy() == null)) {
parentDescriptor = parentDescriptor.getInheritancePolicy()
.getParentDescriptor();
}
if (parentDescriptor != null) {
// Unique is required because the builder can add the same table many times.
// This is done after init properties to make sure the default table is the first local one.
setHistoricalTables(Helper.concatenateUniqueLists(parentDescriptor.getHistoryPolicy()
.getHistoricalTables(),
getHistoricalTables()));
setStartFields(Helper.concatenateUniqueLists(parentDescriptor.getHistoryPolicy()
.getStartFields(),
getStartFields()));
setEndFields(Helper.concatenateUniqueLists(parentDescriptor.getHistoryPolicy()
.getEndFields(),
getEndFields()));
if (parentDescriptor.getHistoryPolicy() instanceof UserHistoryPolicy) {
setUserFields(Helper.concatenateUniqueLists(((UserHistoryPolicy) parentDescriptor.getHistoryPolicy()).getUserFields(),
getUserFields()));
setDeleteUserFields(Helper.concatenateUniqueLists(((UserHistoryPolicy) parentDescriptor.getHistoryPolicy()).getDeleteUserFields(),
getUserFields()));
}
}
}
}
@Override
public void logicalDelete(ModifyQuery writeQuery,
boolean isUpdate,
boolean isShallow) {
ClassDescriptor descriptor = writeQuery.getDescriptor();
AbstractRecord originalModifyRow = writeQuery.getModifyRow();
AbstractRecord modifyRow = new DatabaseRecord();
StatementQueryMechanism updateMechanism = new StatementQueryMechanism(writeQuery);
Object currentTime = getCurrentTime(writeQuery.getSession());
for (int i = 0; i < getHistoricalTables().size(); i++) {
DatabaseTable table = getHistoricalTables().get(i);
if (isUpdate && !checkWastedVersioning(originalModifyRow,
table)) {
continue;
}
SQLUpdateStatement updateStatement = new SQLUpdateStatement();
updateStatement.setTable(table);
Expression whereClause = null;
if (writeQuery instanceof DeleteAllQuery) {
if (writeQuery.getSelectionCriteria() != null) {
whereClause = (Expression) writeQuery.getSelectionCriteria()
.clone();
}
} else {
whereClause = descriptor.getObjectBuilder()
.buildPrimaryKeyExpression(table);
}
ExpressionBuilder builder = ((whereClause == null)
? new ExpressionBuilder()
: whereClause.getBuilder());
whereClause = builder.getField(getEnd(i))
.isNull()
.and(whereClause);
updateStatement.setWhereClause(whereClause);
modifyRow.add(getEnd(i),
currentTime);
// save a little time here and add the same timestamp value for
// the start field in the logicalInsert.
if (isUpdate) {
if (isShallow) {
// Bug 319276 - increment the timestamp by 1 to avoid unique constraint violation potential
java.sql.Timestamp incrementedTime = (java.sql.Timestamp) currentTime;
incrementedTime.setTime(incrementedTime.getTime() + getMinimumTimeIncrement(writeQuery.getSession()));
originalModifyRow.add(getStart(i),
incrementedTime);
} else {
originalModifyRow.add(getStart(i),
currentTime);
}
originalModifyRow.add(getUser(i),
CurrentUserSingleton.getCurrentUserProvider()
.getCurrentUsername());
} else {
modifyRow.add(getDeleteUser(i),
CurrentUserSingleton.getCurrentUserProvider()
.getCurrentUsername());
}
updateMechanism.getSQLStatements()
.add(updateStatement);
}
if (updateMechanism.hasMultipleStatements()) {
writeQuery.setModifyRow(modifyRow);
updateMechanism.updateObject();
writeQuery.setModifyRow(originalModifyRow);
}
}
@Override
public void logicalInsert(ObjectLevelModifyQuery writeQuery,
boolean isUpdate) {
ClassDescriptor descriptor = getDescriptor();
AbstractRecord modifyRow = null;
AbstractRecord originalModifyRow = writeQuery.getModifyRow();
Object currentTime = null;
if (isUpdate) {
modifyRow = descriptor.getObjectBuilder()
.buildRow(writeQuery.getObject(),
writeQuery.getSession(),
DatabaseMapping.WriteType.UPDATE); // Bug 319276
// If anyone added items to the modify row, then they should also be added here.
modifyRow.putAll(originalModifyRow);
} else {
modifyRow = originalModifyRow;
// If update would have already discovered timestamp to use.
currentTime = getCurrentTime(writeQuery.getSession());
}
StatementQueryMechanism insertMechanism = new StatementQueryMechanism(writeQuery);
for (int i = 0; i < getHistoricalTables().size(); i++) {
DatabaseTable table = getHistoricalTables().get(i);
if (isUpdate && !checkWastedVersioning(originalModifyRow,
table)) {
continue;
}
if (!isUpdate) {
modifyRow.add(getStart(i),
currentTime);
modifyRow.add(getUser(i),
CurrentUserSingleton.getCurrentUserProvider()
.getCurrentUsername());
}
SQLInsertStatement insertStatement = new SQLInsertStatement();
insertStatement.setTable(table);
insertMechanism.getSQLStatements()
.add(insertStatement);
}
if (insertMechanism.hasMultipleStatements()) {
writeQuery.setTranslationRow(modifyRow);
writeQuery.setModifyRow(modifyRow);
insertMechanism.insertObject();
}
}
@Override
public void mappingLogicalInsert(DataModifyQuery originalQuery,
AbstractRecord arguments,
AbstractSession session) {
DataModifyQuery historyQuery = new DataModifyQuery();
SQLInsertStatement historyStatement = new SQLInsertStatement();
DatabaseTable histTable = getHistoricalTables().get(0);
historyStatement.setTable(histTable);
AbstractRecord modifyRow = originalQuery.getModifyRow()
.clone();
AbstractRecord translationRow = arguments.clone();
// Start could be the version field in timestamp locking.
if (!modifyRow.containsKey(getStart())) {
Object time = getCurrentTime(session);
modifyRow.add(getStart(),
time);
translationRow.add(getStart(),
time);
}
if (!modifyRow.containsKey(getUser())) {
modifyRow.add(getUser(),
CurrentUserSingleton.getCurrentUserProvider()
.getCurrentUsername());
translationRow.add(getUser(),
CurrentUserSingleton.getCurrentUserProvider()
.getCurrentUsername());
}
historyQuery.setSQLStatement(historyStatement);
historyQuery.setModifyRow(modifyRow);
historyStatement.setModifyRow(modifyRow);
session.executeQuery(historyQuery,
translationRow);
}
}
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.02835 seconds