
com.gs.obevo.api.appdata.Change Maven / Gradle / Ivy
/**
* Copyright 2017 Goldman Sachs.
* Licensed 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 com.gs.obevo.api.appdata;
import java.sql.Timestamp;
import com.gs.obevo.api.appdata.doc.TextMarkupDocumentSection;
import com.gs.obevo.api.platform.ChangeAuditDao;
import com.gs.obevo.api.platform.ChangeType;
import com.gs.obevo.api.platform.ChangeTypeBehavior;
import com.gs.obevo.impl.graph.SortableDependency;
import com.gs.obevo.impl.graph.SortableDependencyGroup;
import com.gs.obevo.impl.text.TextDependencyExtractable;
import com.gs.obevo.util.hash.DbChangeHashStrategy;
import com.gs.obevo.util.hash.ExactDbChangeHashStrategy;
import com.gs.obevo.util.hash.OldWhitespaceAgnosticDbChangeHashStrategy;
import com.gs.obevo.util.vfs.FileObject;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.set.ImmutableSet;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.impl.factory.Lists;
import org.eclipse.collections.impl.factory.Sets;
import org.eclipse.collections.impl.set.mutable.UnifiedSet;
public abstract class Change implements Restrictable, SortableDependency, SortableDependencyGroup, TextDependencyExtractable {
public static final int DEFAULT_CHANGE_ORDER = 500; // only used to control relative order changes (e.g. within a given class of changes like stored procs)
public static final Function TO_SCHEMA = new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getSchema();
}
};
public static final Function TO_DB_OBJECT_KEY = new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getDbObjectKey();
}
};
public static final Function TO_DISPLAY_STRING = new Function() {
@Override
public String valueOf(Change object) {
return object.getDisplayString();
}
};
public static final Function TO_CONTENT = new Function() {
@Override
public String valueOf(Change object) {
return object.getContent();
}
};
public static final Function TO_CHANGE_TYPE = new Function() {
@Override
public ChangeType valueOf(Change object) {
return object.getChangeType();
}
};
public static final Function TO_CHANGE_TYPE_NAME = new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getChangeType().getName();
}
};
public static final Function TO_OBJECT_KEY = new Function() {
@Override
public ObjectKey valueOf(Change arg0) {
return arg0.getObjectKey();
}
};
public static final Function TO_CHANGE_KEY = new Function() {
@Override
public ChangeKey valueOf(Change object) {
return object.getChangeKey();
}
};
public static final Function TO_TIME_INSERTED = new Function() {
@Override
public Timestamp valueOf(Change object) {
return object.getTimeInserted();
}
};
public static final Function TO_CHANGESET = new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getChangeset();
}
};
private transient ObjectKey objectKey;
private transient ChangeKey changeKey;
private String changeName;
private String objectName;
private String contentHash;
private transient FileObject fileLocation;
private transient String reason;
private boolean active;
private String schema;
private ChangeType changeType;
private ImmutableList restrictions;
private String content;
private String convertedContent;
private String rollbackContent;
private String convertedRollbackContent;
private int order = DEFAULT_CHANGE_ORDER;
private Environment environment;
private String permissionScheme; // this is really a property of the DB object, not the individual change. We have this here until we refactor to having a "DB Object" class
private transient TextMarkupDocumentSection metadataSection;
private transient String dropContent;
private transient ImmutableSet dependencies;
private transient ImmutableSet includeDependencies = Sets.immutable.with();
private transient ImmutableSet excludeDependencies = Sets.immutable.with();
private transient Boolean applyGrants = null;
private int orderWithinObject = 0;
private Timestamp timeUpdated;
private Timestamp timeInserted;
private String changeset;
public void setEnvironment(Environment environment) {
this.environment = environment;
}
protected Change() {
}
@Override
public ObjectKey getObjectKey() {
if (this.objectKey == null) {
this.objectKey = new ObjectKey(schema, changeType, objectName);
}
return this.objectKey;
}
public ChangeKey getChangeKey() {
if (this.changeKey == null) {
this.changeKey = new ChangeKey(getObjectKey(), changeName);
}
return this.changeKey;
}
public String getSchema() {
return this.schema;
}
public void setSchema(String dbSchema) {
this.schema = dbSchema;
}
public String getObjectName() {
return this.objectName;
}
public void setObjectName(String objectName) {
this.objectName = objectName;
}
public String getChangeName() {
return this.changeName;
}
public void setChangeName(String changeName) {
this.changeName = changeName;
}
public String getContentHash() {
return this.contentHash;
}
public void setContentHash(String contentHash) {
this.contentHash = contentHash;
}
public PhysicalSchema getPhysicalSchema() {
return this.environment.getPhysicalSchema(this.schema);
}
/**
* This getDbObjectKey() string concatenation is a kludge until we refactor the DB object stuff itself out to its
* own object
*/
public String getDbObjectKey() {
return this.getSchema() + ":" + this.getObjectName();
}
public ChangeType getChangeType() {
return this.changeType;
}
public void setChangeType(ChangeType changeType) {
this.changeType = changeType;
}
@Override
public ImmutableList getRestrictions() {
return this.restrictions;
}
public void setRestrictions(ImmutableList restrictions) {
this.restrictions = restrictions;
}
public Change withRestrictions(ImmutableList restrictions) {
this.setRestrictions(restrictions);
return this;
}
public String getContent() {
return this.content;
}
/**
* We have this setter kludge here for the static data dependency calculation (where we derive it based on the
* information in the associated table file, but the two objects are currently separated).
*/
private String contentForDependencyCalculation;
public String getContentForDependencyCalculation() {
if (this.contentForDependencyCalculation == null) {
return this.content;
} else {
return this.contentForDependencyCalculation;
}
}
public void setContentForDependencyCalculation(String contentForDependencyCalculation) {
this.contentForDependencyCalculation = contentForDependencyCalculation;
}
private final ImmutableList CONTENT_HASH_STRATEGIES = Lists.immutable.with(
new OldWhitespaceAgnosticDbChangeHashStrategy(),
new ExactDbChangeHashStrategy()
);
public void setContent(String content) {
this.content = content;
}
/**
* TODO rename this to something more appropriate (i.e. not hiding the convertedContent field)
*/
public String getConvertedContent() {
return this.isRollbackActivated() ? this.getRollbackToBeExecutedContent() : this.convertedContent != null ?
this.convertedContent : this.content;
}
public void setConvertedContent(String convertedContent) {
this.convertedContent = convertedContent;
}
public void setConvertedRollbackContent(String convertedRollbackContent) {
this.convertedRollbackContent = convertedRollbackContent;
}
public String getDisplayString() {
StringBuilder sb = new StringBuilder();
if (isRollbackActivated()) {
sb.append("ROLLING BACK: ");
}
sb.append(String.format(
"Object [%s]; ChangeName [%s]; Type [%s]; LogicalSchema [%s]"
, this.getObjectName()
, this.getChangeName()
, this.getChangeType().getName()
, this.getSchema()
));
if (this.environment != null) {
sb.append("; PhysicalSchema [" + this.environment.getPhysicalSchema(this.getSchema()).getPhysicalName() + "]");
}
if (this.fileLocation != null) {
sb.append("; File [" + this.fileLocation + "]");
}
if (this.reason != null) {
sb.append("; Reason [" + this.reason + "]");
}
return sb.toString();
}
public boolean isRollbackIfAlreadyDeployed() {
return false;
}
public boolean isActive() {
return this.active;
}
public void setActive(boolean active) {
this.active = active;
}
public boolean equalsOnContent(Change other) {
return new EqualsBuilder()
.append(this.getSchema(), other.getSchema())
.append(this.getObjectName(), other.getObjectName())
.append(this.getChangeType(), other.getChangeType())
.append(this.getContentHash(), other.getContentHash())
.isEquals();
}
@Override
public String toString() {
return this.toStringBuilder().toString();
}
protected ToStringBuilder toStringBuilder() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append(this.getSchema())
.append(this.getChangeName())
.append(this.getObjectName())
.append(this.getChangeType())
.append(this.getContent())
.append(this.getContentHash())
.append(this.getOrderWithinObject())
;
}
public static Function changeName() {
return new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getChangeName();
}
};
}
public static Function active() {
return new Function() {
@Override
public Boolean valueOf(Change arg0) {
return arg0.isActive();
}
};
}
public static Function objectName() {
return new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getObjectName();
}
};
}
public static Function contentHash() {
return new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getContentHash();
}
};
}
public static Function schema() {
return new Function() {
@Override
public String valueOf(Change arg0) {
return arg0.getSchema();
}
};
}
public ImmutableSet getAcceptableHashes() {
/**
* This is here for backwards-compatibility w/ systems that were doing the hashing prior to making all the
* hashing agnostic of the white-space (before, we only had the table changes be white-space agnostic).
* We need the various CONTENT_HASH_STRATEGIES to account for past versions of the algorithm.
*/
return this.CONTENT_HASH_STRATEGIES.flatCollect(new Function>() {
@Override
public Iterable valueOf(DbChangeHashStrategy hashStrategy) {
MutableSet acceptableHashes = UnifiedSet.newSet();
acceptableHashes.add(hashStrategy.hashContent(content));
if (convertedContent != null) {
acceptableHashes.add(hashStrategy.hashContent(convertedContent));
}
return acceptableHashes;
}
}).toSet().toImmutable();
}
public String getPermissionScheme() {
return this.permissionScheme == null ? this.changeType.getName() : this.permissionScheme;
}
public void setPermissionScheme(String permissionScheme) {
this.permissionScheme = permissionScheme;
}
public TextMarkupDocumentSection getMetadataSection() {
return this.metadataSection;
}
public String getMetadataAttribute(String attrName) {
return this.metadataSection == null ? null : this.metadataSection.getAttr(attrName);
}
public void setMetadataSection(TextMarkupDocumentSection metadataSection) {
this.metadataSection = metadataSection;
}
public String getDropContent() {
return dropContent;
}
public void setDropContent(String dropContent) {
this.dropContent = dropContent;
}
@Override
public ImmutableSet getDependencies() {
return this.dependencies;
}
@Override
public void setDependencies(ImmutableSet dependencies) {
this.dependencies = dependencies;
}
@Override
public ImmutableSet getExcludeDependencies() {
return this.excludeDependencies;
}
public void setExcludeDependencies(ImmutableSet excludeDependencies) {
this.excludeDependencies = excludeDependencies;
}
@Override
public ImmutableSet getIncludeDependencies() {
return includeDependencies;
}
public void setIncludeDependencies(ImmutableSet includeDependencies) {
this.includeDependencies = includeDependencies;
}
/**
* Only for log output purposes
*/
public FileObject getFileLocation() {
return this.fileLocation;
}
public void setFileLocation(FileObject fileLocation) {
this.fileLocation = fileLocation;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public String getReason() {
return this.reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public boolean isRollbackActivated() {
return false;
}
public String getRollbackToBeExecutedContent() {
return null;
}
public String getConvertedRollbackContent() {
return this.convertedRollbackContent == null ? this.rollbackContent : this.convertedRollbackContent;
}
public String getRollbackContent() {
// Setting default as blank space for backwards-compatibility w/ Sybase 11.9 change
// (Sybase 11.9 requires TEXT data type, which cannot accept null values)
// This setting would work fine across DBs
return this.rollbackContent != null ? this.rollbackContent : "";
}
public void setRollbackContent(String rollbackContent) {
// Setting default as blank space for backwards-compatibility w/ Sybase 11.9 change
this.rollbackContent = rollbackContent != null ? rollbackContent : "";
}
public int getOrderWithinObject() {
return this.orderWithinObject;
}
public void setOrderWithinObject(int orderWithinObject) {
this.orderWithinObject = orderWithinObject;
}
public Timestamp getTimeInserted() {
return timeInserted != null ? timeInserted : timeUpdated;
}
public void setTimeInserted(Timestamp timeInserted) {
this.timeInserted = timeInserted;
}
public Timestamp getTimeUpdated() {
return timeUpdated;
}
public void setTimeUpdated(Timestamp timeUpdated) {
this.timeUpdated = timeUpdated;
}
/**
* Determines if we should force-apply (or force-not-apply) the grants. If not specified, it will default to
* whatever the default check in the code. This is here as a failsafe option.
*/
public Boolean getApplyGrants() {
return applyGrants;
}
public void setApplyGrants(Boolean applyGrants) {
this.applyGrants = applyGrants;
}
/**
* The changeset name for this change; this change will only be deployed if this particular changeset is requested
* in the input arguments (or if the "all-changesets" override is applied).
*/
public String getChangeset() {
return changeset;
}
/**
* @see #getChangeset()
*/
public void setChangeset(String changeset) {
this.changeset = changeset;
}
private ChangeTypeBehavior changeTypeBehavior;
public void deploy() {
this.changeTypeBehavior.deploy(this);
}
public void undeploy() {
this.changeTypeBehavior.undeploy(this);
}
public void dropObject() {
this.changeTypeBehavior.dropObject(this, false);
}
public void manage(ChangeAuditDao changeAuditDao, DeployExecution deployExecution) {
this.changeTypeBehavior.manage(this, changeAuditDao, deployExecution);
}
public void unmanage(ChangeAuditDao changeAuditDao) {
this.changeTypeBehavior.unmanage(this, changeAuditDao);
}
public void unmanageObject(ChangeAuditDao changeAuditDao) {
this.changeTypeBehavior.unmanageObject(this, changeAuditDao);
}
public ChangeTypeBehavior getChangeTypeBehavior() {
return changeTypeBehavior;
}
public void setChangeTypeBehavior(ChangeTypeBehavior changeTypeBehavior) {
this.changeTypeBehavior = changeTypeBehavior;
}
@Override
public ImmutableSet getComponents() {
return Sets.immutable.with(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy