package liquibase.diff.output;
import liquibase.database.Database;
import liquibase.diff.ObjectDifferences;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.structure.DatabaseObject;
import liquibase.structure.core.*;
import liquibase.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class StandardObjectChangeFilter implements ObjectChangeFilter {
private FilterType filterType;
private List<Filter> filters = new ArrayList<Filter>();
public StandardObjectChangeFilter(FilterType type, String filter) {
this.filterType = type;
parseFilter(filter);
}
protected void parseFilter(String filter) {
filter = StringUtils.trimToNull(filter);
if (filter == null) {
return;
}
for (String subfilter : filter.split("\\s*,\\s*")) {
String[] split = subfilter.split(":");
if (split.length == 1) {
filters.add(new Filter(null, Pattern.compile(split[0]), filterType));
} else {
String className = StringUtils.upperCaseFirst(split[0]);
className = "liquibase.structure.core."+className;
try {
Class<DatabaseObject> clazz = (Class<DatabaseObject>) Class.forName(className);
filters.add(new Filter(clazz, Pattern.compile(split[1]), filterType));
} catch (ClassNotFoundException e) {
throw new UnexpectedLiquibaseException(e);
}
}
}
}
@Override
public boolean includeMissing(DatabaseObject object, Database referenceDatabase, Database comparisionDatabase) {
return include(object, referenceDatabase, comparisionDatabase);
}
@Override
public boolean includeUnexpected(DatabaseObject object, Database referenceDatabase, Database comparisionDatabase) {
return include(object, referenceDatabase, comparisionDatabase);
}
@Override
public boolean includeChanged(DatabaseObject object, ObjectDifferences differences, Database referenceDatabase, Database comparisionDatabase) {
return include(object, referenceDatabase, comparisionDatabase);
}
protected boolean include(DatabaseObject object, Database referenceDatabase, Database comparisionDatabase) {
if (filters.size() == 0) {
return true;
}
for (Filter filter : filters) {
if (filter.matches(object)) {
if (filterType == FilterType.INCLUDE) {
return true;
}
if (filterType == FilterType.EXCLUDE) {
return false;
}
}
}
return filterType == FilterType.EXCLUDE;
}
protected static class Filter {
private final FilterType filterType;
private Class<DatabaseObject> objectType;
private Pattern nameMatcher;
public Filter(Class<DatabaseObject> objectType, Pattern nameMatcher, FilterType filterType) {
this.objectType = objectType;
this.nameMatcher = nameMatcher;
this.filterType = filterType;
}
protected boolean matches(DatabaseObject object) {
if (object == null) {
return false;
}
Boolean matches = null;
if (objectType != null && !objectType.isAssignableFrom(object.getClass())) {
matches = false;
}
if (matches == null) {
matches = object.getName() != null && nameMatcher.matcher(object.getName()).matches();
}
if (!matches) {
if (object instanceof Column) {
return matches(((Column) object).getRelation());
}
if (object instanceof Index) {
return matches(((Index) object).getTable());
}
if (object instanceof ForeignKey) {
return matches(((ForeignKey) object).getForeignKeyTable());
}
if (object instanceof PrimaryKey) {
return matches(((PrimaryKey) object).getTable());
}
if (object instanceof UniqueConstraint) {
return matches(((UniqueConstraint) object).getTable());
}
if (object instanceof Data) {
return matches(((Data) object).getTable());
}
}
return matches;
}
}
public static enum FilterType {
INCLUDE,
EXCLUDE,
}
}