io.hops.transaction.context.BaseEntityContext.java Source code

Java tutorial

Introduction

Here is the source code for io.hops.transaction.context.BaseEntityContext.java

Source

/*
 * Copyright (C) 2015 hops.io.
 *
 * 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 io.hops.transaction.context;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
import io.hops.exception.StorageException;
import io.hops.exception.TransactionContextException;
import io.hops.metadata.common.CounterType;
import io.hops.metadata.common.FinderType;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

abstract class BaseEntityContext<Key, Entity> extends EntityContext<Entity> {

    private static boolean statsEnabled = false;

    public static void enableStats() {
        statsEnabled = true;
    }

    public static void disableStats() {
        statsEnabled = false;
    }

    enum State {
        DBREAD, ADDED, MODIFIED, REMOVED
    }

    class ContextEntity {
        private State firstState;
        private State state;
        private Entity entity;

        ContextEntity(Entity entity) {
            this.entity = entity;
        }

        ContextEntity(Entity entity, State state) {
            this(entity);
            this.firstState = state;
            this.state = state;
        }

        void update(Entity entity, State state) {
            this.entity = entity;
            this.state = state;
        }

        State getState() {
            return state;
        }

        Entity getEntity() {
            return entity;
        }

        @Override
        public String toString() {
            return "ContextEntity{" + "state=" + state + ", entity=" + entity + '}';
        }
    }

    private final Map<Key, ContextEntity> contextEntities = new HashMap<Key, ContextEntity>();

    private EntityContextStat contextStat;

    @Override
    public void add(Entity entity) throws TransactionContextException {
        update(entity);
    }

    @Override
    public void update(Entity entity) throws TransactionContextException {
        Key entityKey = getKey(entity);
        ContextEntity contextEntity = contextEntities.get(entityKey);
        if (contextEntity == null) {
            contextEntity = new ContextEntity(entity, State.ADDED);
            contextEntities.put(entityKey, contextEntity);
        } else {
            contextEntity.update(entity, State.MODIFIED);
        }
    }

    @Override
    public void remove(Entity entity) throws TransactionContextException {
        Key entityKey = getKey(entity);
        ContextEntity contextEntity = contextEntities.get(entityKey);
        if (contextEntity != null && contextEntity.getEntity() != null) {
            contextEntity.update(entity, State.REMOVED);
        } else {
            throw new TransactionContextException("Unattached Entity passed to be removed");
        }
    }

    @Override
    public void clear() throws TransactionContextException {
        storageCallPrevented = false;
        contextEntities.clear();
    }

    @Override
    public int count(CounterType<Entity> counter, Object... params)
            throws TransactionContextException, StorageException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Entity find(FinderType<Entity> finder, Object... params)
            throws TransactionContextException, StorageException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Collection<Entity> findList(FinderType<Entity> finder, Object... params)
            throws TransactionContextException, StorageException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void removeAll() throws TransactionContextException, StorageException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public final EntityContextStat collectSnapshotStat() throws TransactionContextException {
        return resetContextStat();
    }

    @Override
    public void snapshotMaintenance(TransactionContextMaintenanceCmds cmds, Object... params)
            throws TransactionContextException {

    }

    final Collection<Entity> getRemovedForced() {
        return filterValuesOnState(State.REMOVED);
    }

    final Collection<Entity> getRemoved() {
        Collection<Entity> entities = Maps.transformValues(contextEntities, new Function<ContextEntity, Entity>() {
            @Override
            public Entity apply(ContextEntity input) {
                if (input.getState() == State.REMOVED && input.firstState != State.ADDED) {
                    return input.getEntity();
                }
                return null;
            }
        }).values();
        return Collections2.filter(entities, Predicates.notNull());
    }

    final Collection<Entity> getAdded() {
        return filterValuesOnState(State.ADDED);
    }

    final Collection<Entity> getModified() {
        return filterValuesOnState(State.MODIFIED);
    }

    final Collection<Entity> filterValuesOnState(final State state) {
        return filterValues(state, false);
    }

    final Collection<Entity> filterValuesNotOnState(final State state) {
        return filterValues(state, true);
    }

    private Collection<Entity> filterValues(final State state, final boolean not) {
        Collection<Entity> entities = Maps.transformValues(contextEntities, new Function<ContextEntity, Entity>() {
            @Override
            public Entity apply(ContextEntity input) {
                if (not ? (input.getState() != state) : (input.getState() == state)) {
                    return input.getEntity();
                }
                return null;
            }
        }).values();
        return Collections2.filter(entities, Predicates.notNull());
    }

    abstract Key getKey(Entity entity);

    final boolean isNewlyAdded(Key key) {
        return containsFirst(key, State.ADDED);
    }

    final boolean isReadFromDB(Key key) {
        return containsFirst(key, State.DBREAD);
    }

    final boolean isRemoved(Key key) {
        return contains(key, State.REMOVED);
    }

    final boolean isModified(Key key) {
        return contains(key, State.MODIFIED);
    }

    private boolean containsFirst(Key key, State state) {
        ContextEntity ce = contextEntities.get(key);
        if (ce != null) {
            return ce.firstState == state;
        }
        return false;
    }

    private boolean contains(Key key, State state) {
        ContextEntity ce = contextEntities.get(key);
        if (ce != null) {
            return ce.getState() == state;
        }
        return false;
    }

    final boolean contains(Key key) {
        return contextEntities.containsKey(key);
    }

    final boolean contains(Predicate<ContextEntity> pred) {
        return get(pred).size() != 0;
    }

    final Entity get(Key key) {
        ContextEntity ce = contextEntities.get(key);
        if (ce != null && ce.getState() != State.REMOVED) {
            return ce.getEntity();
        }
        return null;
    }

    final Collection<Entity> get(Predicate<ContextEntity> pred) {
        Map<Key, ContextEntity> filtered = Maps.filterValues(contextEntities, pred);
        Collection<Entity> transformed = Maps.transformValues(filtered, new Function<ContextEntity, Entity>() {
            @Override
            public Entity apply(ContextEntity input) {
                return input.getEntity();
            }
        }).values();
        return Collections2.filter(transformed, Predicates.notNull());
    }

    final Collection<Entity> getAll() {
        Collection<Entity> tr = Collections2.transform(contextEntities.values(),
                new Function<ContextEntity, Entity>() {
                    @Override
                    public Entity apply(ContextEntity input) {
                        return input.getEntity();
                    }
                });
        return Collections2.filter(tr, Predicates.notNull());
    }

    final ContextEntity max(Comparator<ContextEntity> contextEntityComparator) {
        return Collections.max(contextEntities.values(), contextEntityComparator);
    }

    void gotFromDB(Collection<Entity> entityList) {
        if (entityList != null) {
            for (Entity entity : entityList) {
                gotFromDB(entity);
            }
        }
    }

    final void gotFromDB(Entity entity) {
        if (entity != null) {
            gotFromDB(getKey(entity), entity);
        }
    }

    void gotFromDB(Key entityKey, Entity entity) {
        ContextEntity contextEntity = contextEntities.get(entityKey);
        if (contextEntity == null) {
            contextEntity = new ContextEntity(entity, State.DBREAD);
            contextEntities.put(entityKey, contextEntity);
        } else {
            //if(contextEntity.getEntity() == null){
            contextEntity.update(entity, State.DBREAD);
            //}
        }
    }

    final int size() {
        return contextEntities.size();
    }

    protected void hit(FinderType finder, Entity res, Object... params) {
        hit(finder, res == null ? 0 : 1, params);
    }

    protected void hit(FinderType finder, Collection<Entity> res, Object... params) {
        hit(finder, res == null ? 0 : res.size(), params);
    }

    protected void miss(FinderType finder, Entity res, Object... params) {
        miss(finder, res == null ? 0 : 1, params);
    }

    protected void miss(FinderType finder, Collection<Entity> res, Object... params) {
        miss(finder, res == null ? 0 : res.size(), params);
    }

    protected void missUpgrade(FinderType finder, Entity res, Object... params) {
        missUpgrade(finder, res == null ? 0 : 1, params);
    }

    protected void missUpgrade(FinderType finder, Collection<Entity> res, Object... params) {
        missUpgrade(finder, res == null ? 0 : res.size(), params);
    }

    private void hit(FinderType finder, int count, Object... params) {
        log(finder, CacheHitState.HIT, params);
        hit(finder, count);
    }

    private void miss(FinderType finder, int count, Object... params) {
        miss(finder, CacheHitState.LOSS, count, params);
    }

    private void missUpgrade(FinderType finder, int count, Object... params) {
        miss(finder, CacheHitState.LOSS_LOCK_UPGRADE, count, params);
    }

    private void miss(FinderType finder, CacheHitState state, int count, Object... params) {
        log(finder, state, params);
        miss(finder, count);
    }

    private void hit(FinderType finderType, int count) {
        if (statsEnabled) {
            getContextStat().hit(finderType, count);
        }
    }

    private void miss(FinderType finderType, int count) {
        if (statsEnabled) {
            getContextStat().miss(finderType, count);
        }
    }

    private EntityContextStat getContextStat() {
        if (contextStat == null) {
            contextStat = new EntityContextStat(this.getClass().getSimpleName());
        }
        return contextStat;
    }

    private EntityContextStat resetContextStat() {
        if (statsEnabled) {
            EntityContextStat stat = getContextStat();
            stat.commited(getAdded().size(), getModified().size(), getRemoved().size());
            contextStat = null;
            if (stat.isEmpty()) {
                stat = null;
            }
            return stat;
        }
        return null;
    }

}