com.gs.obevo.impl.AbstractEnvironmentEnricher Maven / Gradle / Ivy
The 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.impl;
import java.util.List;
import java.util.regex.Pattern;
import com.gs.obevo.api.appdata.Environment;
import com.gs.obevo.api.appdata.Schema;
import com.gs.obevo.api.factory.EnvironmentEnricher;
import com.gs.obevo.api.factory.PlatformConfiguration;
import com.gs.obevo.api.platform.ChangeType;
import com.gs.obevo.api.platform.Platform;
import com.gs.obevo.util.CollectionUtil;
import com.gs.obevo.util.VisibleForTesting;
import com.gs.obevo.util.vfs.FileObject;
import org.apache.commons.configuration2.CombinedConfiguration;
import org.apache.commons.configuration2.HierarchicalConfiguration;
import org.apache.commons.configuration2.ImmutableHierarchicalConfiguration;
import org.apache.commons.configuration2.tree.OverrideCombiner;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.FileType;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.block.predicate.Predicate;
import org.eclipse.collections.api.collection.ImmutableCollection;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.api.multimap.set.MutableSetMultimap;
import org.eclipse.collections.api.set.ImmutableSet;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.impl.block.factory.HashingStrategies;
import org.eclipse.collections.impl.factory.HashingStrategySets;
import org.eclipse.collections.impl.factory.Lists;
import org.eclipse.collections.impl.factory.Maps;
import org.eclipse.collections.impl.factory.Multimaps;
import org.eclipse.collections.impl.list.fixed.ArrayAdapter;
import org.eclipse.collections.impl.list.mutable.ListAdapter;
public abstract class AbstractEnvironmentEnricher implements EnvironmentEnricher {
private static final Pattern PATTERN = Pattern.compile("[\\w+]+");
private final PlatformConfiguration dbPlatformConfiguration = PlatformConfiguration.getInstance();
@Override
public ImmutableCollection readSystem(final HierarchicalConfiguration sysCfg, final FileObject sourcePath) {
final Platform systemDbPlatform = dbPlatformConfiguration.valueOf(sysCfg.getString("type"));
// Check for dbEnvironments first for backwards-compatibility
ImmutableList envConfigs = iterConfigMutable(sysCfg, "environments.dbEnvironment");
if (envConfigs.isEmpty()) {
envConfigs = iterConfigMutable(sysCfg, "environments.environment");
}
ImmutableList envList = envConfigs.collect(new Function() {
@Override
public E valueOf(HierarchicalConfiguration envCfg) {
E dbEnv = AbstractEnvironmentEnricher.this.createNewEnv();
// combining the sys and env configurations before passing to downstream methods so that we can support only having env configs passed in
CombinedConfiguration combinedConfiguration = new CombinedConfiguration(new OverrideCombiner());
combinedConfiguration.addConfiguration(envCfg);
combinedConfiguration.addConfiguration(sysCfg);
combinedConfiguration.setExpressionEngine(sysCfg.getExpressionEngine());
AbstractEnvironmentEnricher.this.enrich(dbEnv, combinedConfiguration, sourcePath, systemDbPlatform);
AbstractEnvironmentEnricher.this.createEnv(dbEnv, combinedConfiguration, systemDbPlatform);
return dbEnv;
}
});
CollectionUtil.verifyNoDuplicates(envList, new Function() {
@Override
public Object valueOf(E e) {
return e.getName();
}
}, "Invalid configuration from " + sourcePath + "; not expecting duplicate env names");
return envList;
}
@Override
public E readEnvironment(ImmutableHierarchicalConfiguration combinedConfiguration, FileObject sourcePath) {
E dbEnv = createNewEnv();
Platform systemDbPlatform = dbPlatformConfiguration.valueOf(combinedConfiguration.getString("type"));
enrich(dbEnv, combinedConfiguration, sourcePath, systemDbPlatform);
createEnv(dbEnv, combinedConfiguration, systemDbPlatform);
return dbEnv;
}
protected abstract E createNewEnv();
protected abstract void createEnv(E env, ImmutableHierarchicalConfiguration envCfg, Platform systemDbPlatform);
private void enrich(Environment dbEnv, ImmutableHierarchicalConfiguration envCfg, FileObject sourcePath, Platform systemDbPlatform) {
ImmutableList sourceDirs = iterString(envCfg, "sourceDirs");
ImmutableSet acceptedExtensions = iterString(envCfg, "acceptedExtensions").toSet().toImmutable();
FileObject rootDir = sourcePath.getType() == FileType.FILE ? sourcePath.getParent() : sourcePath;
// Use coreSourcePath and additionalSourceDirs here (instead of setSourceDirs) to facilitate any external integrations
dbEnv.setCoreSourcePath(rootDir);
dbEnv.setAdditionalSourceDirs(sourceDirs);
dbEnv.setAcceptedExtensions(acceptedExtensions);
dbEnv.setCleanBuildAllowed(envCfg.getBoolean("cleanBuildAllowed", false));
MutableMap tokens = iterConfig(envCfg, "tokens.token")
.toMap(new Function() {
@Override
public String valueOf(ImmutableHierarchicalConfiguration tok) {
return tok.getString("key");
}
}, new Function() {
@Override
public String valueOf(ImmutableHierarchicalConfiguration tok) {
return tok.getString("value");
}
});
dbEnv.setTokens(tokens.toImmutable());
MutableMap runtimeEnvAttrs = iterConfig(envCfg, "runtimeEnvAttrs.runtimeEnvAttr")
.toMap(new Function() {
@Override
public String valueOf(ImmutableHierarchicalConfiguration tok) {
return tok.getString("key");
}
}, new Function() {
@Override
public String valueOf(ImmutableHierarchicalConfiguration tok) {
return tok.getString("value");
}
});
dbEnv.setRuntimeEnvAttrs(runtimeEnvAttrs.toImmutable());
dbEnv.setRollbackDetectionEnabled(envCfg.getBoolean("rollbackDetectionEnabled", true));
Integer metadataLineReaderVersion = envCfg.getInteger("metadataLineReaderVersion", null);
if (metadataLineReaderVersion != null) {
dbEnv.setMetadataLineReaderVersion(metadataLineReaderVersion);
}
dbEnv.setForceEnvInfraSetup(envCfg.getBoolean("forceEnvInfraSetup", null));
String sourceEncoding = envCfg.getString("sourceEncoding");
if (sourceEncoding != null) {
dbEnv.setSourceEncoding(sourceEncoding);
}
Integer legacyDirectoryStructureEnabledVersion = envCfg.getInteger("legacyDirectoryStructureEnabled", null);
if (legacyDirectoryStructureEnabledVersion != null) {
dbEnv.setLegacyDirectoryStructureEnabledVersion(legacyDirectoryStructureEnabledVersion);
}
enrichSchemas(dbEnv, envCfg, systemDbPlatform);
}
private void enrichSchemas(Environment dbEnv, ImmutableHierarchicalConfiguration envCfg, final Platform systemDbPlatform) {
dbEnv.setName(envCfg.getString("name"));
dbEnv.setDefaultUserId(envCfg.getString("defaultUserId"));
dbEnv.setDefaultPassword(envCfg.getString("defaultPassword"));
final int schemaNameValidationVersion = envCfg.getInt("schemaNameValidation", dbPlatformConfiguration.getFeatureToggleVersion("schemaNameValidation"));
// TODO add include/exclude schemas functionality
ImmutableList schemaObjs = iterConfig(envCfg, "schemas.schema")
.collect(new Function() {
@Override
public Schema valueOf(ImmutableHierarchicalConfiguration cfg) {
return AbstractEnvironmentEnricher.this.convertCfgToSchema(cfg, systemDbPlatform, schemaNameValidationVersion);
}
});
final MutableSet schemasToInclude = iterString(envCfg, "includeSchemas").toSet();
final MutableSet schemasToExclude = iterString(envCfg, "excludeSchemas").toSet();
if (!schemasToInclude.isEmpty() && !schemasToExclude.isEmpty()) {
throw new IllegalArgumentException("Environment " + dbEnv.getName() + " has includeSchemas ["
+ schemasToInclude + "] and excludeSchemas [" + schemasToExclude
+ "] defined; please only specify one of them");
} else if (!schemasToInclude.isEmpty()) {
schemaObjs = schemaObjs.select(new Predicate() {
@Override
public boolean accept(Schema it) {
return schemasToInclude.contains(it.getName());
}
});
} else if (!schemasToExclude.isEmpty()) {
schemaObjs = schemaObjs.reject(new Predicate() {
@Override
public boolean accept(Schema it) {
return schemasToExclude.contains(it.getName());
}
});
}
MutableMap schemaNameOverrides = Maps.mutable.empty();
ImmutableSet schemaNames = schemaObjs.collect(new Function() {
@Override
public String valueOf(Schema schema1) {
return schema1.getName();
}
}).toSet().toImmutable();
for (ImmutableHierarchicalConfiguration schemaOverride : iterConfig(envCfg, "schemaOverrides.schemaOverride")) {
String schema = schemaOverride.getString("schema");
if (schemaNames.contains(schema)) {
schemaNameOverrides.put(schema, schemaOverride.getString("overrideValue"));
} else {
throw new IllegalArgumentException("Schema override definition value "
+ schema + " is not defined in the schema list " + schemaNames + " for environment " + dbEnv.getName());
}
}
dbEnv.setSchemaNameOverrides(schemaNameOverrides.toImmutable());
// ensure that we only store the unique schema names here
dbEnv.setSchemas(HashingStrategySets.mutable.ofAll(HashingStrategies.fromFunction(new Function() {
@Override
public String valueOf(Schema schema) {
return schema.getName();
}
}), schemaObjs).toImmutable());
}
private Schema convertCfgToSchema(ImmutableHierarchicalConfiguration object, final Platform systemDbPlatform, final int schemaNameValidation) {
String schemaName = object.getString("name");
if (schemaNameValidation >= 2) {
validateSchemaName(schemaName);
}
boolean readOnly = object.getBoolean("readOnly", false);
MutableSetMultimap excludedNameMap = Multimaps.mutable.set.empty();
ImmutableList excludes = iterConfig(object, "excludes");
if (!excludes.isEmpty()) {
if (excludes.size() > 1) {
throw new IllegalArgumentException("Only expecting 1 excludes element under ");
}
ImmutableHierarchicalConfiguration excludesConfig = excludes.get(0);
if (excludesConfig != null) {
for (ChangeType changeType : systemDbPlatform.getChangeTypes()) {
ImmutableList excludedNames = iterListString(excludesConfig, changeType.getName().toLowerCase());
if (excludedNames.notEmpty()) {
excludedNameMap.putAll(changeType.getName(), excludedNames);
}
ImmutableList excludedPatterns = iterListString(excludesConfig, changeType.getName().toLowerCase() + "Pattern");
if (excludedPatterns.notEmpty()) {
throw new IllegalArgumentException("The Pattern element is deprecated. Use just the element w/ wildcards (% or *)");
}
}
if (iterListString(excludesConfig, "procedure").notEmpty() || iterListString(excludesConfig, "procedurePattern").notEmpty()) {
throw new IllegalArgumentException("The procedure and procedurePattern elements are no longer supported. Use only, with wildcards (% or *) if needed");
}
}
}
return new Schema(schemaName, systemDbPlatform.getObjectExclusionPredicateBuilder().add(excludedNameMap.toImmutable()), readOnly);
}
@VisibleForTesting
static void validateSchemaName(String schemaName) {
if (!PATTERN.matcher(schemaName).matches()) {
throw new IllegalArgumentException("SchemaName " + schemaName + " does not match regexp " + PATTERN.pattern());
}
}
protected static ImmutableList iterConfig(ImmutableHierarchicalConfiguration c, String path) {
List list = c.immutableConfigurationsAt(path);
return list != null ? ListAdapter.adapt(list).toImmutable() : Lists.immutable.empty();
}
private static ImmutableList iterConfigMutable(HierarchicalConfiguration c, String path) {
List list = c.configurationsAt(path);
return list != null ? ListAdapter.adapt(list).toImmutable() : Lists.immutable.empty();
}
protected static ImmutableList iterString(ImmutableHierarchicalConfiguration c, String path) {
String string = c.getString(path);
if (!StringUtils.isBlank(string)) {
String[] parts = string.trim().split("\\s*,\\s*");
return ArrayAdapter.adapt(parts).toImmutable();
}
return Lists.immutable.empty();
}
private static ImmutableList iterListString(ImmutableHierarchicalConfiguration c, String path) {
List list = c.getList(String.class, path);
return list != null ? ListAdapter.adapt(list).toImmutable() : Lists.immutable.empty();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy