ch.inftec.ju.util.change.DbChangeUtils Maven / Gradle / Ivy
Show all versions of ju-dbutil Show documentation
package ch.inftec.ju.util.change;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ch.inftec.ju.db.DbConnection;
import ch.inftec.ju.util.JuBeanUtils;
import ch.inftec.ju.util.JuStringUtils;
import ch.inftec.ju.util.change.DbActionUtils.AbstractActionBuilder;
import ch.inftec.ju.util.general.Descriptor;
import ch.inftec.ju.util.general.DescriptorUtils;
import ch.inftec.ju.util.persistable.DbPersistenceStorage;
import ch.inftec.ju.util.persistable.GenericMemento;
import ch.inftec.ju.util.persistable.GenericMementoUtils;
import ch.inftec.ju.util.persistable.GenericMementoUtils.GenericMementoBuilder;
import ch.inftec.ju.util.persistable.TypeHandler;
public class DbChangeUtils {
private static final String UNDO_SUFFIX = ".undo";
/**
* TypeHandler used to get type name for DbActions when creating
* memento.
*/
static final TypeHandler TYPE_HANDLER;
static {
TYPE_HANDLER = GenericMementoUtils.newTypeHandler()
.addMapping(DeleteDbRowDbAction.class)
.addMapping(InsertDbRowDbAction.class)
.addMapping(UpdateDbRowDbAction.class)
.getHandler();
}
/**
* Creates a new builder to build DbChangeSets.
*
* Name and description of the set must be set.
*
* DbActions are added to groups. You must start a group using
* newGroup in order to be able to add actions. endGroup ends
* the current group.
* @param dbConn DbConnection instance to be used by the change set
* @return DbChangeSetBuilder instance
*/
public static DbChangeSetBuilder buildChangeSet(DbConnection dbConn) {
return new DbChangeSetBuilder(dbConn);
}
public static class DbChangeSetBuilder {
private final DbConnection dbConn;
private String name;
private String description;
private List groupBuilders = new ArrayList<>();
private DbChangeSetBuilder(DbConnection dbConn) {
this.dbConn = dbConn;
}
/**
* Sets the name of the change set.
* @return This builder to allow for chaining
*/
public DbChangeSetBuilder name(String name) {
this.name = name;
return this;
}
/**
* Sets the description of the change set
* @return This builder to allow for chaining
*/
public DbChangeSetBuilder description(String description) {
this.description = description;
return this;
}
/**
* Returns a GroupBuilder for a new change group.
*
* Use endGroup to finish the group and return to the change set builder
* @param name Name of the group
* @param description Description of the group
* @return Group builder to add actions to the group
*/
public DbChangeGroupBuilder newGroup(String name, String description) {
DbChangeGroupBuilder groupBuilder = new DbChangeGroupBuilder(this, name, description);
this.groupBuilders.add(groupBuilder);
return groupBuilder;
}
/**
* Builds the change set.
* @return DbChangeSet instance
* @throws IllegalStateException If not all mandatory fields have been set
*/
public PersistableChangeItem build() {
JuBeanUtils.checkFieldsNotNull(this, "name", "description");
DbChangeSet changeSet = new DbChangeSet(this.dbConn, this.name, this.description);
for (DbChangeGroupBuilder groupBuilder : this.groupBuilders) {
changeSet.groups.add(groupBuilder.group);
}
return changeSet;
}
}
/**
* Builder to add actions to a group.
* @author tgdmemae
*
*/
public static class DbChangeGroupBuilder {
private final DbChangeSetBuilder parentBuilder;
private final DbChangeGroup group;
private DbChangeGroupBuilder(DbChangeSetBuilder parentBuilder, String name, String description) {
this.parentBuilder = parentBuilder;
this.group = new DbChangeGroup(name, description);
}
/**
* Adds the specified DbAction to the group.
* @param action DbAction
* @return This builder to allow for chaining.
*/
public DbChangeGroupBuilder addAction(DbAction action) {
this.group.actions.add(action);
return this;
}
/**
* Returns a builder to configure a new update action to be added to the group.
* @param tableName TableName of the row to be updated
* @param primaryKeyValue Primary key value of the row to be updated
* @return Builder to define the updates to be performed
*/
public DbChangeGroupActionBuilder newUpdateAction(String tableName, Object primaryKeyValue) {
AbstractActionBuilder actionBuilder = DbActionUtils.newUpdateAction(this.parentBuilder.dbConn, tableName, primaryKeyValue);
return new DbChangeGroupActionBuilder(this, actionBuilder);
}
/**
* Returns a builder to configure a new insert action to be added to the group.
* @param tableName TableName of the row to be inserted
* @return Builder to define the values of the new row
*/
public DbChangeGroupActionBuilder newInsertAction(String tableName) {
AbstractActionBuilder actionBuilder = DbActionUtils.newInsertAction(this.parentBuilder.dbConn, tableName);
return new DbChangeGroupActionBuilder(this, actionBuilder);
}
/**
* Returns a builder to configure a new insert action to be added to the group.
* @param tableName TableName of the row to be inserted
* @param primaryKeyValue Primary Key value of the row to be deleted
* @return This builder to allow for chaining
*/
public DbChangeGroupBuilder newDeleteAction(String tableName, Object primaryKeyValue) {
this.addAction(DbActionUtils.newDeleteAction(this.parentBuilder.dbConn, tableName, primaryKeyValue));
return this;
}
/**
* Ends this group and returns the change set builder.
* @return DbChangeSetBuilder to continue building
*/
public DbChangeSetBuilder endGroup() {
return this.parentBuilder;
}
}
/**
* Builder to configure actions to be added to a change group.
* @author tgdmemae
*
*/
public static class DbChangeGroupActionBuilder {
private final DbChangeGroupBuilder groupBuilder;
private final AbstractActionBuilder actionBuilder;
private DbChangeGroupActionBuilder(DbChangeGroupBuilder groupBuilder, AbstractActionBuilder actionBuilder) {
this.groupBuilder = groupBuilder;
this.actionBuilder = actionBuilder;
}
/**
* Sets the value of the specified column for the action.
* @param columnName Column name
* @param value New value
* @return This builder to allow for chaining
*/
public DbChangeGroupActionBuilder setValue(String columnName, Object value) {
this.actionBuilder.setValue(columnName, value);
return this;
}
/**
* Ends the action and adds it the the group.
* @return Group builder to continue building the group
*/
public DbChangeGroupBuilder endAction() {
this.groupBuilder.addAction(this.actionBuilder.getAction());
return this.groupBuilder;
}
}
private static class DbChangeSet implements PersistableChangeItem {
private final DbConnection dbConn;
private final Descriptor descriptor;
private List groups = new ArrayList();
private DbChangeSet(DbConnection dbConn, String name, String description) {
this.dbConn = dbConn;
this.descriptor = DescriptorUtils.newInstance(name, description);
}
@Override
public Descriptor getDescriptor() {
return this.descriptor;
}
@Override
public List getChildItems() {
return Collections.unmodifiableList(new ArrayList(this.groups));
}
@Override
public ChangeItemHandler getHandler() {
return new DbChangeSetHandler(this);
}
private static final class DbChangeSetHandler implements ChangeItemHandler {
private final DbChangeSet set;
private DbChangeSetHandler(DbChangeSet set) {
this.set = set;
}
@Override
public ChangeItem createUndoItem() {
DbChangeSetBuilder setBuilder = DbChangeUtils.buildChangeSet(set.dbConn)
.name(set.getDescriptor().getName() + DbChangeUtils.UNDO_SUFFIX)
.description(set.getDescriptor().getDescription() + DbChangeUtils.UNDO_SUFFIX);
for (int i = set.groups.size() - 1; i >= 0; i--) {
DbChangeGroup group = set.groups.get(i);
DbChangeGroupBuilder groupBuilder = setBuilder.newGroup(group.getDescriptor().getName(), group.getDescriptor().getDescription());
for (int j = group.actions.size() - 1; j >= 0; j--) {
DbAction action = group.actions.get(j);
groupBuilder.addAction(action.createUndoAction());
}
groupBuilder.endGroup();
}
return setBuilder.build();
}
@Override
public void execute() {
for (DbChangeGroup group : set.groups) {
for (DbAction action : group.actions) {
action.getHandler().execute();
}
}
}
}
@Override
public String toString() {
return JuStringUtils.toString(this, "descriptor", this.getDescriptor(), "groupCount", this.groups.size());
}
@Override
public GenericMemento createMemento() {
GenericMementoBuilder setBuilder = GenericMementoUtils.builder()
.add(DbPersistenceStorage.ATTR_CONNECTION_NAME, this.dbConn.getName());
for (DbChangeGroup group : this.groups) {
GenericMementoBuilder groupBuilder = setBuilder.newChild()
.add("groupName", group.getDescriptor().getName())
.add("groupDescription", group.getDescriptor().getDescription());
for (DbAction action : group.actions) {
groupBuilder.newChild()
.add("@type", DbChangeUtils.TYPE_HANDLER.getTypeName(action))
.add(action.createMemento())
.childDone();
}
groupBuilder.childDone();
}
return setBuilder.build();
}
@Override
public void setMemento(GenericMemento memento) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
private static final class DbChangeGroup implements ChangeItem {
private Descriptor descriptor;
private List actions = new ArrayList<>();
private DbChangeGroup(String name, String description) {
this.descriptor = DescriptorUtils.newInstance(name, description);
}
@Override
public Descriptor getDescriptor() {
return this.descriptor;
}
@Override
public List getChildItems() {
return Collections.unmodifiableList(new ArrayList(this.actions));
}
@Override
public ChangeItemHandler getHandler() {
// TODO Auto-generated method stub
return null;
}
@Override
public String toString() {
return JuStringUtils.toString(this, "descriptor", this.getDescriptor(), "actionCount", this.actions.size());
}
}
}