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

com.gs.obevo.db.apps.reveng.RevengWriter 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.db.apps.reveng;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Locale;

import com.gs.obevo.api.appdata.ObjectTypeAndNamePredicateBuilder;
import com.gs.obevo.api.platform.ChangeAuditDao;
import com.gs.obevo.api.platform.ChangeType;
import com.gs.obevo.api.platform.DeployExecutionDao;
import com.gs.obevo.api.platform.Platform;
import com.gs.obevo.db.impl.core.checksum.DbChecksumDao;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.block.predicate.Predicate;
import org.eclipse.collections.api.block.predicate.Predicate2;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.api.multimap.set.MutableSetMultimap;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.api.tuple.Pair;
import org.eclipse.collections.impl.block.factory.Functions;
import org.eclipse.collections.impl.block.factory.HashingStrategies;
import org.eclipse.collections.impl.block.factory.Predicates;
import org.eclipse.collections.impl.block.factory.StringFunctions;
import org.eclipse.collections.impl.factory.HashingStrategyMaps;
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.factory.Sets;

public class RevengWriter {
    private final Configuration templateConfig;

    public static Predicate2 defaultShouldOverwritePredicate() {
        return new Predicate2() {
            @Override
            public boolean accept(File mainFile, RevEngDestination dbFileRep) {
                return !mainFile.exists();
            }
        };
    }

    public static Predicate2 overwriteAllPredicate() {
        return new Predicate2() {
            @Override
            public boolean accept(File mainFile, RevEngDestination dbFileRep) {
                return true;
            }
        };
    }

    public static Predicate2 overwriteForSpecificTablesPredicate(
            final MutableSet tableNames) {
        return new Predicate2() {
            @Override
            public boolean accept(File mainFile, RevEngDestination dbFileRep) {
                return !mainFile.exists()
                        || tableNames.collect(StringFunctions.toLowerCase()).contains(
                        dbFileRep.getObjectName().toLowerCase());
            }
        };
    }

    @SuppressWarnings("WeakerAccess")
    public RevengWriter() {
        this.templateConfig = new Configuration();

        // Where load the templates from:
        templateConfig.setClassForTemplateLoading(RevengWriter.class, "/");

        // Some other recommended settings:
        templateConfig.setDefaultEncoding("UTF-8");
        templateConfig.setLocale(Locale.US);
        templateConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
    }

    public void write(Platform platform, MutableList allRevEngDestinations, File outputDir, boolean generateBaseline, Predicate2 shouldOverwritePredicate, String jdbcUrl, String dbHost, Integer dbPort, String dbServer, String excludeObjects) {
        outputDir.mkdirs();
        if (shouldOverwritePredicate == null) {
            shouldOverwritePredicate = defaultShouldOverwritePredicate();
        }

        MutableSetMultimap coreTablesToExclude = Multimaps.mutable.set.empty();
        coreTablesToExclude.putAll(ChangeType.TABLE_STR, Sets.immutable.with(
                ChangeAuditDao.CHANGE_AUDIT_TABLE_NAME,
                DbChecksumDao.SCHEMA_CHECKSUM_TABLE_NAME,
                DeployExecutionDao.DEPLOY_EXECUTION_TABLE_NAME,
                DeployExecutionDao.DEPLOY_EXECUTION_ATTRIBUTE_TABLE_NAME
        ).collect(platform.convertDbObjectName()));

        ObjectTypeAndNamePredicateBuilder objectExclusionPredicateBuilder = platform.getObjectExclusionPredicateBuilder()
                .add(coreTablesToExclude.toImmutable());
        if (excludeObjects != null) {
            objectExclusionPredicateBuilder = objectExclusionPredicateBuilder.add(ObjectTypeAndNamePredicateBuilder.parse(excludeObjects, ObjectTypeAndNamePredicateBuilder.FilterType.EXCLUDE));
        }
        final Predicates objectExclusionPredicate = objectExclusionPredicateBuilder.build(
                new Function() {
                    @Override
                    public String valueOf(RevEngDestination dest) {
                        return dest.getDbObjectType().getName();
                    }
                },
                new Function() {
                    @Override
                    public String valueOf(RevEngDestination revEngDestination) {
                        return revEngDestination.getObjectName();
                    }
                }
        );

        MutableMap> revEngDestinationMap = HashingStrategyMaps.mutable.of(HashingStrategies.fromFunction(new Function() {
            @Override
            public String valueOf(RevEngDestination revEngDestination) {
                return revEngDestination.getIdentity();
            }
        }));
        for (ChangeEntry allRevEngDestination : allRevEngDestinations.select(new Predicate() {
            @Override
            public boolean accept(ChangeEntry entry) {
                return objectExclusionPredicate.accept(entry.getDestination());
            }
        })) {
            MutableList changeEntries = revEngDestinationMap.get(allRevEngDestination.getDestination());
            if (changeEntries == null) {
                changeEntries = Lists.mutable.empty();
                revEngDestinationMap.put(allRevEngDestination.getDestination(), changeEntries);
            }

            changeEntries.add(allRevEngDestination);
        }

        for (Pair> pair :
                revEngDestinationMap.keyValuesView()) {
            RevEngDestination dest = pair.getOne();

            MutableList changes = pair.getTwo()
                    .toSortedListBy(Functions.firstNotNullValue(new Function() {
                        @Override
                        public String valueOf(ChangeEntry changeEntry1) {
                            return changeEntry1.getName();
                        }
                    }, Functions.getFixedValue("")))
                    .toSortedListBy(new Function() {
                        @Override
                        public Integer valueOf(ChangeEntry changeEntry1) {
                            return changeEntry1.getOrder();
                        }
                    });
            MutableList metadataAnnotations = changes.flatCollect(new Function>() {
                @Override
                public Iterable valueOf(ChangeEntry changeEntry1) {
                    return changeEntry1.getMetadataAnnotations();
                }
            });
            String metadataString;
            if (metadataAnnotations.isEmpty()) {
                metadataString = "";
            } else {
                metadataString = "//// METADATA " + metadataAnnotations.makeString(" ");
            }
            String mainSql = (metadataString.isEmpty() ? "" : metadataString + "\n")
                    + changes.collect(new Function() {
                @Override
                public String valueOf(ChangeEntry changeEntry1) {
                    return changeEntry1.getSql();
                }
            }).collect(new Function() {
                @Override
                public String valueOf(String s) {
                    return s.trim();
                }
            }).makeString("\n");

            try {
                File mainDestinationFile = dest.getDestinationFile(outputDir, false);
                if (dest.isBaselineEligible()) {
                    if (shouldOverwritePredicate.accept(mainDestinationFile, dest)) {
                        MutableList lines = Lists.mutable.empty();

                        String prevChange = null;

                        if (!metadataString.isEmpty()) {
                            lines.add(metadataString);
                        }
                        for (ChangeEntry changeEntry : changes) {
                            if (prevChange == null || !prevChange.equals(changeEntry.getName())) {
                                lines.add(String.format("//// CHANGE%1$s name=%2$s"
                                        , StringUtils.isNotEmpty(changeEntry.getChangeAnnotation())
                                                ? " " + changeEntry.getChangeAnnotation() : ""
                                        , changeEntry.getName()));
                            }

                            lines.add(changeEntry.getSql().trim());
                            lines.add("");

                            prevChange = changeEntry.getName();
                        }

                        FileUtils.writeStringToFile(mainDestinationFile, lines.makeString("\n"));
                    }
                } else {
                    FileUtils.writeStringToFile(mainDestinationFile, mainSql);
                }

                if (generateBaseline && dest.isBaselineEligible()) {
                    FileUtils.writeStringToFile(dest.getDestinationFile(outputDir, true), mainSql);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        MutableSet schemas = allRevEngDestinations.collect(new Function() {
            @Override
            public String valueOf(ChangeEntry entry) {
                return entry.getDestination().getSchema();
            }
        }, Sets.mutable.empty());

        Writer fileWriter = null;
        try {
            Template template = templateConfig.getTemplate("deployer/reveng/system-config-template.xml.ftl");
            fileWriter = new FileWriter(new File(outputDir, "system-config.xml"));

            MutableMap params = Maps.mutable.empty();
            params.put("platform", platform.getName());
            params.put("schemas", schemas);
            params.put("jdbcUrl", jdbcUrl);
            params.put("dbHost", dbHost);
            params.put("dbPort", dbPort != null ? String.valueOf(dbPort) : null);
            params.put("dbServer", dbServer);
            template.process(params, fileWriter);
        } catch (TemplateException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(fileWriter);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy