All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gs.obevo.api.appdata.Change Maven / Gradle / Ivy

There is a newer version: 8.2.1
Show newest version
/**
 * 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