com.jivesoftware.os.upena.service.UpenaTable.java Source code

Java tutorial

Introduction

Here is the source code for com.jivesoftware.os.upena.service.UpenaTable.java

Source

/*
 * Copyright 2013 Jive Software, Inc
 *
 * 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.jivesoftware.os.upena.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.jivesoftware.os.mlogger.core.MetricLogger;
import com.jivesoftware.os.mlogger.core.MetricLoggerFactory;
import com.jivesoftware.os.upena.amza.service.AmzaTable;
import com.jivesoftware.os.upena.amza.shared.RowIndexKey;
import com.jivesoftware.os.upena.shared.BasicTimestampedValue;
import com.jivesoftware.os.upena.shared.Key;
import com.jivesoftware.os.upena.shared.KeyValueFilter;
import com.jivesoftware.os.upena.shared.Stored;
import com.jivesoftware.os.upena.shared.TimestampedValue;
import java.util.List;
import java.util.concurrent.ConcurrentNavigableMap;

public class UpenaTable<K extends Key, V extends Stored> implements UpenaMap<K, V> {

    private static final MetricLogger LOG = MetricLoggerFactory.getLogger();

    private final ObjectMapper mapper;
    private final AmzaTable store;
    private final Class<K> keyClass;
    private final Class<V> valueClass;
    private final UpenaKeyProvider<K, V> keyProvider;
    private final UpenaValueValidator<K, V> valueValidator;

    public UpenaTable(ObjectMapper mapper, AmzaTable store, Class<K> keyClass, Class<V> valueClass,
            UpenaKeyProvider<K, V> keyProvider, UpenaValueValidator<K, V> valueValidator) {

        this.mapper = mapper;
        this.store = store;
        this.keyClass = keyClass;
        this.valueClass = valueClass;
        this.keyProvider = keyProvider;
        this.valueValidator = valueValidator;
    }

    @Override
    public void putIfAbsent(K key, V value) throws Exception {
        if (get(key) == null) {
            update(key, value);
        }
    }

    @Override
    public V get(K key) throws Exception {
        byte[] rawKey = mapper.writeValueAsBytes(key);
        byte[] got = store.get(new RowIndexKey(rawKey));
        if (got == null) {
            return null;
        }
        return mapper.readValue(got, valueClass);
    }

    @Override
    public void scan(final Stream<K, V> stream) throws Exception {
        store.scan((l, key, value) -> {
            if (!value.getTombstoned()) {
                K k = mapper.readValue(key.getKey(), keyClass);
                V v = mapper.readValue(value.getValue(), valueClass);
                return stream.stream(k, v);
            } else {
                return true;
            }
        });
    }

    @Override
    @SuppressWarnings("unchecked")
    public ConcurrentNavigableMap<K, TimestampedValue<V>> find(boolean removeBadKeysEnabled,
            final KeyValueFilter<K, V> filter) throws Exception {
        final ConcurrentNavigableMap<K, TimestampedValue<V>> results = filter == null ? null
                : filter.createCollector();
        List<RowIndexKey> badKeys = Lists.newArrayList();
        store.scan((transactionId, key, value) -> {
            K k = null;
            try {
                if (!value.getTombstoned()) {
                    k = mapper.readValue(key.getKey(), keyClass);
                }
            } catch (Exception x) {
                LOG.warn("Failed to scan. {}", new Object[] { filter }, x);
                badKeys.add(key);
            }

            if (k != null) {
                V v = mapper.readValue(value.getValue(), valueClass);
                if (results != null && filter != null && filter.filter(k, v)) {
                    results.put(k, new BasicTimestampedValue(v, value.getTimestampId(), value.getTombstoned()));
                }
            }
            return true;
        });
        if (!badKeys.isEmpty()) {
            if (removeBadKeysEnabled) {
                for (RowIndexKey key : badKeys) {
                    store.remove(key);
                }
                LOG.info("Removed {} bad keys", badKeys.size());
            } else {
                LOG.warn("Find for filter:{} has {} bad keys.", filter, badKeys.size());
            }
        }
        return results;
    }

    @Override
    synchronized public K update(K key, V value) throws Exception {
        if (key == null) {
            key = keyProvider.getNodeKey(this, value);
        }
        if (valueValidator != null) {
            value = valueValidator.validate(this, key, value);
        }
        byte[] rawKey = mapper.writeValueAsBytes(key);
        byte[] rawValue = mapper.writeValueAsBytes(value);
        RowIndexKey set = store.set(new RowIndexKey(rawKey), rawValue);
        K gotKey = mapper.readValue(set.getKey(), keyClass);
        return gotKey;
    }

    @Override
    synchronized public boolean remove(K key) throws Exception {
        byte[] rawKey = mapper.writeValueAsBytes(key);
        return store.remove(new RowIndexKey(rawKey));
    }
}