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

liquibase.snapshot.SnapshotControl Maven / Gradle / Ivy

The newest version!
package liquibase.snapshot;

import liquibase.database.Database;
import liquibase.database.core.FirebirdDatabase;
import liquibase.diff.output.ObjectChangeFilter;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.parser.core.ParsedNode;
import liquibase.parser.core.ParsedNodeException;
import liquibase.resource.ResourceAccessor;
import liquibase.serializer.LiquibaseSerializable;
import liquibase.structure.DatabaseObject;
import liquibase.structure.core.Catalog;
import liquibase.structure.core.DatabaseObjectFactory;
import lombok.Getter;
import lombok.Setter;

import java.util.*;
import java.util.stream.Stream;

/**
 * Allows the class user to influence various aspects of the database object snapshot generation, e.g.
 * what types of database objects they want.
 */
public class SnapshotControl implements LiquibaseSerializable {

    private Set> types;
    private ObjectChangeFilter objectChangeFilter;
    private SnapshotListener snapshotListener;
    private boolean warnIfObjectNotFound = true;
    @Setter
    private boolean searchNestedObjects = true;
    
    
    /**
     * Create a SnapshotControl for a given database and mark the database's standard types for inclusion.
     * @param database the DBMS for which snapshots should be generated
     */
    public SnapshotControl(Database database) {
        setTypes(DatabaseObjectFactory.getInstance().getStandardTypes(), database);
    }
    
    /**
     * Create a Snapshot control for a given database, but explicitly set the object types to be included in snapshots.
     * @param database the DBMS for which snapshots should be generated
     * @param types the list of object types to be included in the snapshot
     */
    @SafeVarargs
    public SnapshotControl(Database database, Class... types) {
        this(database, true, types);
    }

    @SafeVarargs
    public SnapshotControl(Database database, boolean expandTypesIfNeeded, Class... types) {
        if ((types == null) || (types.length == 0)) {
            setTypes(DatabaseObjectFactory.getInstance().getStandardTypes(), database);
        } else {
            if (expandTypesIfNeeded) {
                setTypes(new HashSet<>(Arrays.asList(types)), database);
            } else {
                this.types = new HashSet<>(Arrays.asList(types));
            }
        }
    }
    
    /**
     * Create a Snapshot control for a given database, but explicitly set the object types to be included in snapshots.
     * @param database the DBMS for which snapshots should be generated
     * @param types the list of object types to be included in the snapshot, separated by commas
     */
    public SnapshotControl(Database database, String types) {
        setTypes(DatabaseObjectFactory.getInstance().parseTypes(types), database);
    }

    public SnapshotControl(Database database, ObjectChangeFilter objectChangeFilter, Class... types) {
        this(database, true, types);

        this.objectChangeFilter = objectChangeFilter;
    }

    public SnapshotListener getSnapshotListener() {
        return snapshotListener;
    }

    public void setSnapshotListener(SnapshotListener snapshotListener) {
        this.snapshotListener = snapshotListener;
    }

    @Override
    public String getSerializedObjectName() {
        return "snapshotControl";
    }

    @Override
    public Set getSerializableFields() {
        return new HashSet<>(Collections.singletonList("includedType"));
    }

    @Override
    public Object getSerializableFieldValue(String field) {
        if ("includedType".equals(field)) {
            SortedSet typesNames = new TreeSet<>();
            for (Class type : this.getTypesToInclude()) {
                typesNames.add(type.getName());
            }
            return typesNames;
        } else {
            throw new UnexpectedLiquibaseException("Unknown field "+field);
        }
    }

    @Override
    public SerializationType getSerializableFieldType(String field) {
        if ("includedType".equals(field)) {
            return SerializationType.NESTED_OBJECT;
        } else {
            throw new UnexpectedLiquibaseException("Unknown field "+field);
        }
    }

    @Override
    public String getSerializedObjectNamespace() {
        return STANDARD_SNAPSHOT_NAMESPACE;
    }

    @Override
    public String getSerializableFieldNamespace(String field) {
        return getSerializedObjectNamespace();
    }

    private void setTypes(Set> types, Database database) {
        this.types = new HashSet<>();
        Stream> objectStream = types.stream();
        if (database != null) {
            // Firebird does not support catalogs, but we need to include them in the snapshot for it as it has a catalog name
            // Something incorrectly implemented in the FirebirdDatabase class that we work around here
            objectStream = objectStream.filter(t -> (database.supports(t) || (database instanceof FirebirdDatabase && t.equals(Catalog.class))));
        }
        objectStream.forEach(type -> addType(type, database));
    }
    
    /**
     * Adds a new DatabaseObject type to the list of object types to be included in snapshots.
     * @param type The type to be added
     * @param database The database to check for any dependent types that need to be included as well
     * @return true if the type was added to the list, false if it was already present.
     */
    public boolean addType(Class type, Database database) {
        boolean added = this.types.add(type);
        if (added) {
            for (Class container : SnapshotGeneratorFactory.getInstance().getContainerTypes(type, database)) {
                addType(container, database);
            }
        }
        return added;
    }
    
    /**
     * Return the types to be included in snapshots
     * @return the set of currently registered types
     */
    public Set> getTypesToInclude() {
        return types;
    }
    
    /**
     * Queries the currently registered list of types to be included and returns true if the given type is in that list
     * @param type the DatabaseObject type to be checked
     * @return true if that type is registered for inclusion, false if not
     */
    public boolean shouldInclude(Class type) {
        return types.contains(type);
    }

    @Override
    public void load(ParsedNode parsedNode, ResourceAccessor resourceAccessor) throws ParsedNodeException {
        throw new RuntimeException("TODO");
    }

    @Override
    public ParsedNode serialize() {
        throw new RuntimeException("TODO");
    }
    
    /**
     * Returns if the code should log a LogLevel.WARNING message if the object to be snapshotted could not be found.
     * @return true if WARNINGs should be emitted (default), false if not.
     */
    public boolean isWarnIfObjectNotFound() {
        return warnIfObjectNotFound;
    }

    /**
     * When searchNestedObjects is false this indicates to stop searching the snapshot the moment
     * an example object has been found. With this disabled we will not search for nested objects.
     * @return the search nested objects configuration
     */
    public boolean shouldSearchNestedObjects() {
        return searchNestedObjects;
    }
    
    /**
     * Configures the code to log a LogLevel.WARNING message if the object to be snapshotted could not be found.
     * @param warnIfObjectNotFound true if a warning should emitted (default value), false if not.
     */
    public SnapshotControl setWarnIfObjectNotFound(boolean warnIfObjectNotFound) {
        this.warnIfObjectNotFound = warnIfObjectNotFound;
        return this;
    }

    public  boolean shouldInclude(T example) {
        if (objectChangeFilter != null) {
            return objectChangeFilter.include(example);
        }
        return shouldInclude(example.getClass());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy