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

Java tutorial

Introduction

Here is the source code for com.torodb.core.transaction.metainf.WrapperMutableMetaSnapshot.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.stream.Stream;

public class WrapperMutableMetaSnapshot implements MutableMetaSnapshot {

    private static final Logger LOGGER = D2RLoggerFactory.get(WrapperMutableMetaSnapshot.class);
    private final ImmutableMetaSnapshot wrapped;
    private final HashMap<String, Tuple2<MutableMetaDatabase, MetaElementState>> dbsByName;
    private final Map<String, Tuple2<MutableMetaDatabase, MetaElementState>> aliveMap;

    public WrapperMutableMetaSnapshot(ImmutableMetaSnapshot wrapped) {
        this.wrapped = wrapped;
        this.dbsByName = new HashMap<>();

        wrapped.streamMetaDatabases().forEach((db) -> {
            WrapperMutableMetaDatabase mutable = createMetaDatabase(db);
            dbsByName.put(db.getName(), new Tuple2<>(mutable, MetaElementState.NOT_CHANGED));
        });
        aliveMap = Maps.filterValues(dbsByName, tuple -> tuple.v2().isAlive());
    }

    public static WrapperMutableMetaSnapshot createEmpty() {
        return new WrapperMutableMetaSnapshot(new ImmutableMetaSnapshot(Collections.emptyMap()));
    }

    protected WrapperMutableMetaDatabase createMetaDatabase(ImmutableMetaDatabase immutable) {
        return new WrapperMutableMetaDatabase(immutable, this::onMetaDatabaseChange);
    }

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

    @Override
    public MutableMetaDatabase addMetaDatabase(String dbName, String dbId) throws IllegalArgumentException {
        if (getMetaDatabaseByName(dbName) != null) {
            throw new IllegalArgumentException("There is another database whose name is " + dbName);
        }

        assert getMetaDatabaseByIdentifier(dbId) == null : "There is another database whose id is " + dbId;

        WrapperMutableMetaDatabase result = createMetaDatabase(
                new ImmutableMetaDatabase(dbName, dbId, Collections.emptyList()));

        dbsByName.put(dbName, new Tuple2<>(result, MetaElementState.ADDED));

        return result;
    }

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

    @Override
    public boolean hasChanged() {
        return dbsByName.values().stream().anyMatch(tuple -> tuple.v2.hasChanged());
    }

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

            dbsByName.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 Stream<? extends WrapperMutableMetaDatabase> streamMetaDatabases() {
        return aliveMap.values().stream().map(tuple -> (WrapperMutableMetaDatabase) tuple.v1());
    }

    @Override
    public WrapperMutableMetaDatabase getMetaDatabaseByName(String dbName) {
        Tuple2<MutableMetaDatabase, MetaElementState> tuple = aliveMap.get(dbName);
        if (tuple == null) {
            return null;
        }
        return (WrapperMutableMetaDatabase) tuple.v1();
    }

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

    @Override
    public boolean removeMetaDatabaseByName(String dbName) {
        WrapperMutableMetaDatabase metaDb = getMetaDatabaseByName(dbName);
        if (metaDb == null) {
            return false;
        }
        removeMetaDatabase(metaDb);
        return true;
    }

    @Override
    public boolean removeMetaDatabaseByIdentifier(String dbId) {
        WrapperMutableMetaDatabase metaDb = getMetaDatabaseByIdentifier(dbId);
        if (metaDb == null) {
            return false;
        }
        removeMetaDatabase(metaDb);
        return true;
    }

    private void removeMetaDatabase(WrapperMutableMetaDatabase metaCol) {
        dbsByName.put(metaCol.getName(), new Tuple2<>(metaCol, MetaElementState.REMOVED));
    }

    private boolean isTransitionAllowed(MetaDatabase metaDb, MetaElementState newState) {
        MetaElementState oldState;
        Tuple2<MutableMetaDatabase, MetaElementState> tuple = dbsByName.get(metaDb.getName());

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

        oldState.assertLegalTransition(newState);
        return true;
    }

    private void onMetaDatabaseChange(WrapperMutableMetaDatabase changed) {
        assert isTransitionAllowed(changed, MetaElementState.MODIFIED);

        dbsByName.put(changed.getName(), new Tuple2<>(changed, MetaElementState.MODIFIED));
    }
}