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

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

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 freemarker.template.Configuration
import freemarker.template.TemplateExceptionHandler
import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.StringUtils
import org.eclipse.collections.api.block.function.Function
import org.eclipse.collections.api.block.predicate.Predicate2
import org.eclipse.collections.api.list.MutableList
import org.eclipse.collections.api.set.MutableSet
import org.eclipse.collections.impl.block.factory.HashingStrategies
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
import java.io.File
import java.io.FileWriter
import java.io.IOException
import java.util.Locale

class RevengWriter {
    private val templateConfig: Configuration = Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)

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

        // Some other recommended settings:
        templateConfig.defaultEncoding = "UTF-8"
        templateConfig.locale = Locale.US
        templateConfig.templateExceptionHandler = TemplateExceptionHandler.RETHROW_HANDLER
    }

    fun write(platform: Platform, allRevEngDestinations: List, outputDir: File, generateBaseline: Boolean, shouldOverwritePredicate: Predicate2?, excludeObjects: String?) {
        var shouldOverwritePredicate = shouldOverwritePredicate
        outputDir.mkdirs()
        if (shouldOverwritePredicate == null) {
            shouldOverwritePredicate = defaultShouldOverwritePredicate()
        }

        val coreTablesToExclude = Multimaps.mutable.set.empty()
        coreTablesToExclude.putAll(ChangeType.TABLE_STR, Sets.immutable.with(
                ChangeAuditDao.CHANGE_AUDIT_TABLE_NAME,
//                DbChecksumDao.SCHEMA_CHECKSUM_TABLE_NAME,  should reactivate this, though this functionality has been disabled for a while
                DeployExecutionDao.DEPLOY_EXECUTION_TABLE_NAME,
                DeployExecutionDao.DEPLOY_EXECUTION_ATTRIBUTE_TABLE_NAME
        ).collect(platform.convertDbObjectName()))
        // TODO using COLLECTION for MongoDB - make this generic
        coreTablesToExclude.putAll("COLLECTION", Sets.immutable.with(
                ChangeAuditDao.CHANGE_AUDIT_TABLE_NAME,
//                DbChecksumDao.SCHEMA_CHECKSUM_TABLE_NAME,  should reactivate this, though this functionality has been disabled for a while
                DeployExecutionDao.DEPLOY_EXECUTION_TABLE_NAME,
                DeployExecutionDao.DEPLOY_EXECUTION_ATTRIBUTE_TABLE_NAME
        ).collect(platform.convertDbObjectName()))

        var objectExclusionPredicateBuilder = platform.objectExclusionPredicateBuilder
                .add(coreTablesToExclude.toImmutable())
        if (excludeObjects != null) {
            objectExclusionPredicateBuilder = objectExclusionPredicateBuilder.add(ObjectTypeAndNamePredicateBuilder.parse(excludeObjects, ObjectTypeAndNamePredicateBuilder.FilterType.EXCLUDE))
        }
        val objectExclusionPredicate = objectExclusionPredicateBuilder.build(
                Function { dest -> dest.dbObjectType.name },
                Function { revEngDestination -> revEngDestination.objectName }
        )

        val revEngDestinationMap = HashingStrategyMaps.mutable.of>(HashingStrategies.fromFunction(Function { revEngDestination -> revEngDestination.identity }))
        for (allRevEngDestination in allRevEngDestinations.filter { objectExclusionPredicate.accept(it.destination) }) {
            var changeEntries: MutableList? = revEngDestinationMap[allRevEngDestination.destination]
            if (changeEntries == null) {
                changeEntries = Lists.mutable.empty()
                revEngDestinationMap[allRevEngDestination.destination] = changeEntries
            }

            changeEntries!!.add(allRevEngDestination)
        }

        for (pair in revEngDestinationMap.keyValuesView()) {
            val dest = pair.one

            var changes = pair.two
                    .sortedBy { it.name ?: "" }
                    .sortedBy { it.order }

            if (dest.isKeepLastOnly) {
                changes = changes.subList(changes.size - 1, changes.size)
            }

            val metadataAnnotations = changes.flatMap { it.metadataAnnotations }

            val metadataString = if (metadataAnnotations.isEmpty()) "" else "//// METADATA " + metadataAnnotations.joinToString(" ") + "\n"

            val mainSql = metadataString + changes.joinToString("\n") { it.sql.trim() }

            try {
                val mainDestinationFile = dest.getDestinationFile(outputDir, false)
                if (dest.isBaselineEligible) {
                    if (shouldOverwritePredicate.accept(mainDestinationFile, dest)) {
                        val lines = mutableListOf()

                        var prevChange: String? = null

                        if (!metadataString.isEmpty()) {
                            lines.add(metadataString)
                        }
                        for (changeEntry in changes) {
                            if (prevChange == null || prevChange != changeEntry.name) {
                                val annotationStr = if (StringUtils.isNotEmpty(changeEntry.changeAnnotation))
                                    " " + changeEntry.changeAnnotation
                                else
                                    ""
                                lines.add("//// CHANGE${annotationStr} name=${changeEntry.name}")
                            }

                            lines.add(changeEntry.sql.trim())
                            lines.add("")

                            prevChange = changeEntry.name
                        }

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

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

        }
    }

    fun writeConfig(templatePath: String, platform: Platform, outputDir: File, schemas: Collection, params: Map) {
        FileWriter(File(outputDir, "system-config.xml")).use { fileWriter ->
            val template = templateConfig.getTemplate(templatePath)

            val displayParams = Maps.mutable.empty()
            displayParams["platform"] = platform.name
            displayParams["schemas"] = schemas
            params.forEach { (key, value) -> displayParams[key] = value }
            template.process(displayParams, fileWriter)
        }
    }

    companion object {
        @JvmStatic
        fun defaultShouldOverwritePredicate(): Predicate2 {
            return Predicate2 { mainFile, dbFileRep -> !mainFile.exists() }
        }

        @JvmStatic
        fun overwriteAllPredicate(): Predicate2 {
            return Predicate2 { mainFile, dbFileRep -> true }
        }

        @JvmStatic
        fun overwriteForSpecificTablesPredicate(
                tableNames: MutableSet): Predicate2 {
            return Predicate2 { mainFile, dbFileRep ->
                !mainFile.exists() || tableNames.collect(StringFunctions.toLowerCase()).contains(
                        dbFileRep.objectName.toLowerCase())
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy