com.cognifide.aet.vs.metadata.MetadataDAOMongoDBImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.cognifide.aet.vs.metadata.MetadataDAOMongoDBImpl.java

Source

/**
 * Automated Exploratory Tests
 *
 * Copyright (C) 2013 Cognifide Limited
 *
 * 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.cognifide.aet.vs.metadata;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.FluentIterable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import com.cognifide.aet.communication.api.metadata.Suite;
import com.cognifide.aet.communication.api.metadata.ValidatorException;
import com.cognifide.aet.vs.DBKey;
import com.cognifide.aet.vs.MetadataDAO;
import com.cognifide.aet.vs.SimpleDBKey;
import com.cognifide.aet.vs.StorageException;
import com.cognifide.aet.vs.mongodb.MongoDBClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.result.DeleteResult;

import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Service
@Component(label = "AET Metadata DAO implementation for MongoDB", immediate = true)
public class MetadataDAOMongoDBImpl implements MetadataDAO {

    private static final Logger LOGGER = LoggerFactory.getLogger(MetadataDAOMongoDBImpl.class);

    public static final String METADATA_COLLECTION_NAME = "metadata";

    private static final Gson GSON = new GsonBuilder()
            .registerTypeHierarchyAdapter(Collection.class, new CollectionSerializer())
            .registerTypeHierarchyAdapter(Map.class, new MapSerializer())
            .registerTypeAdapter(Suite.Timestamp.class, new TimestampSerializer()).create();

    private static final Type SUITE_TYPE = new TypeToken<Suite>() {
    }.getType();

    private static final String SUITE_VERSION_PARAM_NAME = "version";

    private static final String CORRELATION_ID_PARAM_NAME = "correlationId";

    @Reference
    private transient MongoDBClient client;

    @Override
    public Suite saveSuite(Suite suite) throws StorageException, ValidatorException {
        MongoCollection<Document> metadata = getMetadataCollection(new SimpleDBKey(suite));
        suite.validate(null);
        LOGGER.debug("Saving suite {} to metadata collection.", suite);
        metadata.insertOne(Document.parse(GSON.toJson(suite, SUITE_TYPE)));
        return getSuite(new SimpleDBKey(suite), suite.getCorrelationId());
    }

    /**
     * Updates suite in .metadata collection only if older version exist,
     * Also updates version and timestamp of a suite.
     *
     * @param suite new suite version to save
     * @return updated suite.
     */
    @Override
    public Suite updateSuite(Suite suite) throws StorageException, ValidatorException {
        MongoCollection<Document> metadata = getMetadataCollection(new SimpleDBKey(suite));
        LOGGER.debug("Updating suite {} in  metadata collection.", suite);
        if (isNewestSuite(suite)) {
            suite.incrementVersion();
            suite.setRunTimestamp(new Suite.Timestamp(System.currentTimeMillis()));
            suite.validate(null);
            metadata.insertOne(Document.parse(GSON.toJson(suite, SUITE_TYPE)));
        } else {
            throw new StorageException("Trying to update old version or not existing suite.");
        }
        return getSuite(new SimpleDBKey(suite), suite.getCorrelationId());
    }

    private boolean isNewestSuite(Suite suite) throws StorageException {
        final Suite latestSuite = getLatestRun(new SimpleDBKey(suite), suite.getName());
        return latestSuite == null || suite.getVersion().equals(latestSuite.getVersion());
    }

    @Override
    public Suite getSuite(DBKey dbKey, String correlationId) throws StorageException {
        Suite suite = null;
        MongoCollection<Document> metadata = getMetadataCollection(dbKey);

        LOGGER.debug("Fetching suite with correlationId: {} ", correlationId);

        final FindIterable<Document> found = metadata.find(Filters.eq(CORRELATION_ID_PARAM_NAME, correlationId))
                .sort(Sorts.descending(SUITE_VERSION_PARAM_NAME)).limit(1);
        final Document result = found.first();
        if (result != null) {
            suite = GSON.fromJson(result.toJson(), SUITE_TYPE);
        }

        return suite;
    }

    @Override
    public Suite getLatestRun(DBKey dbKey, String name) throws StorageException {
        Suite suite = null;
        MongoCollection<Document> metadata = getMetadataCollection(dbKey);
        LOGGER.debug("Fetching latest suite run for company: `{}`, project: `{}`, name `{}`.", dbKey.getCompany(),
                dbKey.getProject(), name);

        final FindIterable<Document> found = metadata.find(Filters.eq("name", name))
                .sort(Sorts.descending(SUITE_VERSION_PARAM_NAME)).limit(1);
        final Document result = found.first();
        if (result != null) {
            suite = GSON.fromJson(result.toJson(), SUITE_TYPE);
        }

        return suite;
    }

    @Override
    public List<Suite> listSuites(DBKey dbKey) throws StorageException {
        MongoCollection<Document> metadata = getMetadataCollection(dbKey);
        LOGGER.debug("Fetching all suites for company: `{}`, project: `{}`.", dbKey.getCompany(),
                dbKey.getProject());

        final FindIterable<Document> found = metadata.find().sort(Sorts.descending(SUITE_VERSION_PARAM_NAME));

        return FluentIterable.from(found).transform(new Function<Document, Suite>() {
            @Override
            public Suite apply(Document result) {
                return GSON.fromJson(result.toJson(), SUITE_TYPE);
            }
        }).toList();
    }

    @Override
    public boolean removeSuite(DBKey dbKey, String correlationId, Long version) throws StorageException {
        LOGGER.debug("Removing suite with correlationId {}, version {} from {}.", correlationId, version, dbKey);
        MongoCollection<Document> metadata = getMetadataCollection(dbKey);

        final DeleteResult deleteResult = metadata
                .deleteOne(Filters.and(Filters.eq(CORRELATION_ID_PARAM_NAME, correlationId),
                        Filters.eq(SUITE_VERSION_PARAM_NAME, version)));

        return deleteResult.getDeletedCount() == 1;
    }

    @Override
    public Collection<DBKey> getProjects(String company) {
        final Collection<DBKey> result = new ArrayList<>();

        final Collection<String> databaseNames;
        if (!StringUtils.isBlank(company)) {
            databaseNames = Collections2.filter(client.getAetsDBNames(), Predicates.containsPattern("^" + company));
        } else {
            databaseNames = client.getAetsDBNames();
        }

        for (String dbName : databaseNames) {
            String[] companyAndProject = StringUtils.split(dbName, MongoDBClient.DB_NAME_SEPARATOR);
            result.add(new SimpleDBKey(companyAndProject[0], companyAndProject[1]));
        }
        return result;
    }

    private MongoCollection<Document> getMetadataCollection(DBKey dbKey) throws StorageException {
        final String dbName = MongoDBClient.getDbName(dbKey.getCompany(), dbKey.getProject());
        final MongoDatabase database = client.getDatabase(dbName, true);
        if (database == null) {
            throw new StorageException(
                    String.format("Database %s does not exist! Contact AET administrators.", dbName));
        }
        return database.getCollection(METADATA_COLLECTION_NAME);
    }
}