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

com.gs.obevo.mongodb.impl.MongoDbChangeAuditDao Maven / Gradle / Ivy

Go to download

POM module containing the dependencyManagement section for the modules of Obevo. All Obevo modules except obevo-bom should inherit from this. We separate obevo-bom from this so that clients can depend on the BOM without pulling in third-party dependencies.

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.mongodb.impl;

import java.sql.Timestamp;
import java.util.Date;

import com.gs.obevo.api.appdata.Change;
import com.gs.obevo.api.appdata.ChangeIncremental;
import com.gs.obevo.api.appdata.ChangeKey;
import com.gs.obevo.api.appdata.ChangeRerunnable;
import com.gs.obevo.api.appdata.DeployExecution;
import com.gs.obevo.api.appdata.PhysicalSchema;
import com.gs.obevo.api.platform.ChangeAuditDao;
import com.gs.obevo.api.platform.Platform;
import com.gs.obevo.mongodb.api.appdata.MongoDbEnvironment;
import com.gs.obevo.util.knex.InternMap;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Indexes;
import org.apache.commons.lang3.ObjectUtils;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.impl.factory.Lists;
import org.joda.time.DateTime;

public class MongoDbChangeAuditDao implements ChangeAuditDao {
    private final MongoClient mongoClient;
    private final MongoDbEnvironment env;
    private final Platform platform;
    private final String deployUserId;
    private final String changeNameColumn = "changeName";
    private final String changeTypeColumn = "changeType";
    private final String deployUserIdColumn = "deployUserId";
    private final String timeInsertedColumn = "timeInserted";
    private final String timeUpdatedColumn = "timeUpdated";
    private final String rollbackContentColumn = "rollbackContent";
    private final String insertDeployExecutionIdColumn = "insertDeployExecutionId";
    private final String updateDeployExecutionIdColumn = "updateDeployExecutionId";

    public MongoDbChangeAuditDao(MongoClient mongoClient, MongoDbEnvironment env, Platform platform, String deployUserId) {
        this.mongoClient = mongoClient;
        this.env = env;
        this.platform = platform;
        this.deployUserId = deployUserId;
    }

    @Override
    public void init() {
        for (PhysicalSchema physicalSchema : env.getPhysicalSchemas()) {
            MongoDatabase database = mongoClient.getDatabase(physicalSchema.getPhysicalName());
            try {
                database.createCollection(getAuditContainerName());
            } catch (Exception e) {
                // create if it doesn't exist already; TODO clean this up
            }
            MongoCollection collection = database.getCollection(getAuditContainerName());
            collection.createIndex(Indexes.ascending(changeNameColumn, "OBJECTNAME"));
        }
    }

    @Override
    public String getAuditContainerName() {
        return CHANGE_AUDIT_TABLE_NAME;
    }

    @Override
    public ImmutableList getDeployedChanges() {
        return env.getPhysicalSchemas().flatCollect(new Function>() {
            @Override
            public Iterable valueOf(PhysicalSchema physicalSchema) {
                MongoDatabase database = mongoClient.getDatabase(physicalSchema.getPhysicalName());
                MongoCollection auditCollection = database.getCollection(getAuditContainerName());

                MutableList changes = iterableToCollection(auditCollection.find()).collect(new Function() {
                    @Override
                    public Change valueOf(Document doc) {
                        String artfType = doc.getString("ARTFTYPE");
                        Change artf;
                        if (artfType.equals("I")) {
                            artf = new ChangeIncremental();
                        } else if (artfType.equals("R")) {
                            artf = new ChangeRerunnable();
                        } else {
                            throw new IllegalArgumentException("This type does not exist " + artfType);
                        }

                        artf.setChangeKey(new ChangeKey(
                                InternMap.instance().intern(doc.getString("DBSCHEMA")),
                                platform.getChangeType(doc.getString("CHANGETYPE")),
                                InternMap.instance().intern(doc.getString("OBJECTNAME")),
                                doc.getString(changeNameColumn)
                        ));

                        artf.setActive(doc.getInteger("ACTIVE") == 1);
                        artf.setContentHash(doc.getString("CONTENTHASH"));
                        artf.setTimeInserted(new Timestamp(doc.getDate(timeInsertedColumn).getTime()));
                        artf.setTimeUpdated(new Timestamp(doc.getDate(timeUpdatedColumn).getTime()));

                        artf.setRollbackContent(doc.getString(rollbackContentColumn));

                        return artf;
                    }
                });

                return changes.toImmutable();
            }
        }).toList().toImmutable();
    }

    @Override
    public void insertNewChange(Change change, DeployExecution deployExecution) {
        MongoCollection auditCollection = getAuditCollection(change);

        auditCollection.insertOne(createDocFromChange(change, deployExecution, null));
    }

    private Document createDocFromChange(Change change, DeployExecution deployExecution, Date insertTimestamp) {
        Date currentTimestamp = getCurrentTimestamp();
        return new Document()
                .append("ARTFTYPE", change instanceof ChangeIncremental ? "I" : "R")
                .append("DBSCHEMA", change.getSchema())
                .append("ACTIVE", change.isActive() ? 1 : 0)
                .append("CHANGETYPE", change.getChangeType().getName())
                .append("CONTENTHASH", change.getContentHash())
                .append(changeNameColumn, change.getChangeName())
                .append("OBJECTNAME", change.getObjectName())
                .append(rollbackContentColumn, change.getRollbackContent())
                .append(deployUserIdColumn, deployUserId)
                .append(timeInsertedColumn, ObjectUtils.firstNonNull(insertTimestamp, currentTimestamp))
                .append(timeUpdatedColumn, currentTimestamp)
                .append(insertDeployExecutionIdColumn, deployExecution.getId())
                .append(updateDeployExecutionIdColumn, deployExecution.getId());
    }

    private MongoCollection getAuditCollection(Change change) {
        MongoDatabase database = mongoClient.getDatabase(change.getPhysicalSchema(env).getPhysicalName());
        return database.getCollection(getAuditContainerName());
    }

    private Date getCurrentTimestamp() {
        return new DateTime().toDate();
    }

    @Override
    public void updateOrInsertChange(Change change, DeployExecution deployExecution) {
        MongoCollection auditCollection = getAuditCollection(change);
        MutableList docs = iterableToCollection(auditCollection.find(getChangeFilter(change)));

        if (docs.size() > 1) {
            throw new IllegalStateException("Not expecting multiple changes for this key [" + change.getObjectName() + "." + change.getChangeName() + "], but found " + docs);
        } else if (docs.isEmpty()) {
            insertNewChange(change, deployExecution);
        } else {
            Document previousDoc = docs.get(0);
            Date timeInserted = previousDoc.getDate(timeInsertedColumn);
            auditCollection.replaceOne(getChangeFilter(change), createDocFromChange(change, deployExecution, timeInserted));
        }
    }

    private Bson getChangeFilter(Change change) {
        return Filters.and(
                Filters.eq(changeNameColumn, change.getChangeName()),
                Filters.eq("OBJECTNAME", change.getObjectName())
        );
    }

    static  MutableList iterableToCollection(FindIterable iterable) {
        MutableList list = Lists.mutable.empty();
        try (MongoCursor iterator = iterable.iterator()) {
            while (iterator.hasNext()) {
                list.add(iterator.next());
            }
        }

        return list;
    }

    @Override
    public void deleteChange(Change change) {
        MongoCollection auditCollection = getAuditCollection(change);
        auditCollection.deleteOne(Filters.and(
                Filters.eq(changeNameColumn, change.getChangeName()),
                Filters.eq("OBJECTNAME", change.getObjectName())
        ));
    }

    @Override
    public void deleteObjectChanges(Change change) {
        MongoCollection auditCollection = getAuditCollection(change);
        auditCollection.deleteOne(
                Filters.eq("OBJECTNAME", change.getObjectName())
        );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy