com.torodb.core.transaction.metainf.WrapperMutableMetaDatabase.java Source code

Java tutorial

Introduction

Here is the source code for com.torodb.core.transaction.metainf.WrapperMutableMetaDatabase.java

Source

/*
 * ToroDB
 * Copyright  2014 8Kdata Technology (www.8kdata.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.torodb.core.transaction.metainf;

import com.google.common.collect.Maps;
import com.torodb.core.d2r.D2RLoggerFactory;
import org.apache.logging.log4j.Logger;
import org.jooq.lambda.tuple.Tuple2;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;

public class WrapperMutableMetaDatabase implements MutableMetaDatabase {

    private static final Logger LOGGER = D2RLoggerFactory.get(WrapperMutableMetaDatabase.class);
    private final ImmutableMetaDatabase wrapped;
    private final HashMap<String, Tuple2<MutableMetaCollection, MetaElementState>> collectionsByName;
    private final Consumer<WrapperMutableMetaDatabase> changeConsumer;
    private final Map<String, Tuple2<MutableMetaCollection, MetaElementState>> aliveCollectionsMap;

    public WrapperMutableMetaDatabase(ImmutableMetaDatabase wrapped,
            Consumer<WrapperMutableMetaDatabase> changeConsumer) {
        this.wrapped = wrapped;
        this.changeConsumer = changeConsumer;

        this.collectionsByName = new HashMap<>();

        wrapped.streamMetaCollections().forEach((collection) -> {
            WrapperMutableMetaCollection mutable = createMetaColletion(collection);

            collectionsByName.put(collection.getName(), new Tuple2<>(mutable, MetaElementState.NOT_CHANGED));
        });
        aliveCollectionsMap = Maps.filterValues(collectionsByName, tuple -> tuple.v2().isAlive());
    }

    protected WrapperMutableMetaCollection createMetaColletion(ImmutableMetaCollection immutable) {
        return new WrapperMutableMetaCollection(immutable, this::onMetaCollectionChange);
    }

    @Override
    public ImmutableMetaDatabase getOrigin() {
        return wrapped;
    }

    @Override
    public WrapperMutableMetaCollection addMetaCollection(String colName, String colId)
            throws IllegalArgumentException {
        if (getMetaCollectionByName(colName) != null) {
            throw new IllegalArgumentException("There is another collection whose name is " + colName);
        }

        assert getMetaCollectionByIdentifier(colId) == null : "There is another collection whose id is " + colId;

        WrapperMutableMetaCollection result = createMetaColletion(
                new ImmutableMetaCollection(colName, colId, Collections.emptyMap(), Collections.emptyMap()));

        collectionsByName.put(colName, new Tuple2<>(result, MetaElementState.ADDED));
        changeConsumer.accept(this);

        return result;
    }

    @Override
    public Stream<ChangedElement<MutableMetaCollection>> streamModifiedCollections() {
        return collectionsByName.values().stream().filter(tuple -> tuple.v2().hasChanged())
                .map(PojoChangedElement::new);
    }

    @Override
    public ImmutableMetaDatabase immutableCopy() {
        if (collectionsByName.values().stream().noneMatch(tuple -> tuple.v2().hasChanged())) {
            return wrapped;
        } else {
            ImmutableMetaDatabase.Builder builder = new ImmutableMetaDatabase.Builder(wrapped);

            collectionsByName.values().forEach(tuple -> {
                switch (tuple.v2()) {
                case ADDED:
                case MODIFIED:
                case NOT_CHANGED:
                    builder.put(tuple.v1().immutableCopy());
                    break;
                case REMOVED:
                    builder.remove(tuple.v1());
                    break;
                case NOT_EXISTENT:
                default:
                    throw new AssertionError("Unexpected case" + tuple.v2());
                }
            });
            return builder.build();
        }
    }

    @Override
    public String getName() {
        return wrapped.getName();
    }

    @Override
    public String getIdentifier() {
        return wrapped.getIdentifier();
    }

    @Override
    public Stream<? extends WrapperMutableMetaCollection> streamMetaCollections() {
        return aliveCollectionsMap.values().stream().map(tuple -> (WrapperMutableMetaCollection) tuple.v1());
    }

    @Override
    public WrapperMutableMetaCollection getMetaCollectionByName(String collectionName) {
        Tuple2<MutableMetaCollection, MetaElementState> tuple = aliveCollectionsMap.get(collectionName);
        if (tuple == null) {
            return null;
        }
        return (WrapperMutableMetaCollection) tuple.v1();
    }

    @Override
    public WrapperMutableMetaCollection getMetaCollectionByIdentifier(String collectionIdentifier) {
        LOGGER.debug(
                "Looking for a meta collection by the unindexed attribute 'id'. " + "Performance lost is expected");
        return aliveCollectionsMap.values().stream().map(tuple -> (WrapperMutableMetaCollection) tuple.v1())
                .filter((collection) -> collection.getIdentifier().equals(collectionIdentifier)).findAny()
                .orElse(null);
    }

    @Override
    public boolean removeMetaCollectionByName(String collectionName) {
        WrapperMutableMetaCollection metaCol = getMetaCollectionByName(collectionName);
        if (metaCol == null) {
            return false;
        }
        removeMetaCollection(metaCol);
        return true;
    }

    @Override
    public boolean removeMetaCollectionByIdentifier(String collectionId) {
        WrapperMutableMetaCollection metaCol = getMetaCollectionByIdentifier(collectionId);
        if (metaCol == null) {
            return false;
        }
        removeMetaCollection(metaCol);
        return true;
    }

    private void removeMetaCollection(WrapperMutableMetaCollection metaCol) {
        collectionsByName.put(metaCol.getName(), new Tuple2<>(metaCol, MetaElementState.REMOVED));
        changeConsumer.accept(this);
    }

    @Override
    public String toString() {
        return defautToString();
    }

    private boolean isTransitionAllowed(MetaCollection metaCol, MetaElementState newState) {
        MetaElementState oldState;
        Tuple2<MutableMetaCollection, MetaElementState> tuple = collectionsByName.get(metaCol.getName());

        if (tuple == null) {
            oldState = MetaElementState.NOT_EXISTENT;
        } else {
            oldState = tuple.v2();
        }

        oldState.assertLegalTransition(newState);
        return true;
    }

    private void onMetaCollectionChange(WrapperMutableMetaCollection changed) {
        assert isTransitionAllowed(changed, MetaElementState.MODIFIED);

        collectionsByName.put(changed.getName(), new Tuple2<>(changed, MetaElementState.MODIFIED));
        changeConsumer.accept(this);
    }

}