Package io.fathom.cloud.state

Source Code of io.fathom.cloud.state.NumberedItemCollection

package io.fathom.cloud.state;

import io.fathom.cloud.CloudException;
import io.fathom.cloud.state.StateStore.StateNode;

import java.io.IOException;
import java.util.List;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.AbstractMessage.Builder;
import com.google.protobuf.ByteString;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor.Type;
import com.google.protobuf.GeneratedMessage;
import com.google.protobuf.Message;

public class NumberedItemCollection<T extends GeneratedMessage> extends ItemCollection {

    final Builder<?> template;
    final FieldDescriptor idField;

    final PrimaryKeyIndex primaryKeyIndex;
    final Descriptor descriptor;

    public NumberedItemCollection(StateNode parentNode, Builder<?> template, FieldDescriptor idField) {
        this(parentNode, null, template, idField, null);
    }

    public NumberedItemCollection(StateNode parentNode, Codec codec, Builder<?> template, FieldDescriptor idField,
            FieldDescriptor keyField) {
        super(parentNode, codec);
        this.template = template;
        this.idField = idField;

        if (keyField == null) {
            this.primaryKeyIndex = new RandomPrimaryKeyStrategy(parentNode, idField);
        } else if (keyField.getType() == Type.STRING) {
            this.primaryKeyIndex = new StringHashPrimaryKeyStrategy(parentNode, idField, keyField);
        } else {
            throw new IllegalArgumentException("Unknown key field type: " + keyField);
        }

        this.descriptor = template.getDescriptorForType();
    }

    public List<T> list(StoreOptions... options) throws CloudException {
        List<T> items = deserializeChildren(parentNode, template.clone());
        if (!usesItemState() || showDeleted(options)) {
            return items;
        }

        List<T> ret = Lists.newArrayList();
        for (T item : items) {
            if (!ItemStates.isDeleted(item)) {
                ret.add(item);
            }
        }
        return ret;
    }

    public T find(long itemId, StoreOptions... options) throws CloudException {
        StateNode itemNode = parentNode.child(Long.toHexString(itemId));

        T t = (T) deserialize(itemNode, template.clone());
        if (t != null && usesItemState() && !showDeleted(options) && ItemStates.isDeleted(t)) {
            return null;
        }
        return t;
    }

    private static boolean showDeleted(StoreOptions[] options) {
        if (options == null || options.length == 0) {
            return false;
        }
        for (int i = 0; i < options.length; i++) {
            if (options[i] == StoreOptions.ShowDeleted) {
                return true;
            }
        }
        return false;
    }

    public T findByKey(String key) throws CloudException {
        StringHashPrimaryKeyStrategy pk = (StringHashPrimaryKeyStrategy) this.primaryKeyIndex;
        T t = pk.find(this, key);
        if (t != null && usesItemState() && ItemStates.isDeleted(t)) {
            return null;
        }
        return t;
    }

    public Watched<T> watch(long itemId) throws CloudException {
        StateNode itemNode = parentNode.child(Long.toHexString(itemId));

        SettableFuture<Object> future = SettableFuture.create();

        T t = (T) deserialize(itemNode, template.clone(), future);
        if (t != null && usesItemState() && ItemStates.isDeleted(t)) {
            return null;
        }

        return new Watched(t, future);
    }

    public T create(GeneratedMessage.Builder item) throws CloudException, DuplicateValueException {
        long id = ((Number) item.getField(idField)).longValue();

        if (usesItemState()) {
            ItemStates.setCreatedAt(item);
        }

        if (id != 0) {
            throw new IllegalStateException();
        }

        while (true) {
            id = primaryKeyIndex.createId(this, item);

            item.setField(idField, id);

            Message built = item.build();

            ByteString data;
            try {
                data = codec.serialize(built);
            } catch (IOException e) {
                throw new CloudException("Error serializing data", e);
            }
            StateNode node = parentNode.child(Long.toHexString(id));

            if (!node.create(data)) {
                continue;
            }

            return (T) built;
        }
    }

    // public T put(GeneratedMessage.Builder item) throws CloudException {
    // return (T) putItem(parentNode, item, idField);
    // }
    //
    // protected Message putItem(StateNode parent, GeneratedMessage.Builder
    // builder, FieldDescriptor idField)
    // throws CloudException {
    // long id = ((Number) builder.getField(idField)).longValue();
    // boolean isCreate = false;
    //
    // if (id == 0) {
    // isCreate = true;
    // }
    //
    // while (true) {
    // if (isCreate) {
    // // Assign a new user id, randomly
    // id = getRandom(Integer.MAX_VALUE);
    // if (parent.hasChild(Long.toHexString(id))) {
    // continue;
    // }
    // builder.setField(idField, id);
    // }
    //
    // Message built = builder.build();
    //
    // ByteString data;
    // try {
    // data = codec.serialize(built);
    // } catch (IOException e) {
    // throw new CloudException("Error serializing data", e);
    // }
    //
    // StateNode node = parent.child(Long.toHexString(id));
    //
    // if (isCreate) {
    // if (!node.create(data)) {
    // continue;
    // }
    // } else {
    // node.update(data);
    // }
    // return built;
    // }
    // }

    public T delete(long itemId) throws CloudException {
        if (usesItemState()) {
            T found = find(itemId);
            if (found == null) {
                return null;
            }
            ItemStates.markDeleted(this, found);
            return found;
        }

        if (!this.primaryKeyIndex.allowDelete()) {
            throw new UnsupportedOperationException();
        }
        StateNode itemNode = parentNode.child(Long.toHexString(itemId));

        T v = (T) deserialize(itemNode, template.clone());
        if (v == null) {
            return null;
        }

        if (!itemNode.delete()) {
            throw new IllegalStateException();
        }

        return v;
    }

    private boolean usesItemState() {
        return ItemStates.usesItemState(descriptor);
    }

    public T update(Message.Builder item) throws CloudException {
        return (T) update(parentNode, item, idField);
    }

    protected Message update(StateNode parent, Message.Builder item, FieldDescriptor idField) throws CloudException {
        if (usesItemState()) {
            ItemStates.setUpdatedAt(item);
        }

        long id = ((Number) item.getField(idField)).longValue();
        if (id == 0) {
            throw new IllegalArgumentException();
        }

        StateNode node = parent.child(Long.toHexString(id));

        return update(node, item);
    }

    public static class CollectionBuilder<T extends GeneratedMessage> extends CollectionBuilderBase<T> {
        public CollectionBuilder(StateNode parentNode, Class<T> protobufClass) {
            super(parentNode, protobufClass);
        }

        @Override
        public CollectionBuilder<T> idField(int idFieldNumber) {
            return (CollectionBuilder<T>) super.idField(idFieldNumber);
        }

        @Override
        public CollectionBuilder<T> keyField(int keyFieldNumber) {
            return (CollectionBuilder<T>) super.keyField(keyFieldNumber);
        }

        @Override
        public NumberedItemCollection<T> create() {
            Codec codec = null;

            FieldDescriptor idField = getIdField(template);

            FieldDescriptor keyField = getKeyField();

            return new NumberedItemCollection(parentNode, codec, template, idField, keyField);
        }
    }

    public static <T extends GeneratedMessage> CollectionBuilder<T> builder(StateNode parentNode, Class<T> protobufClass) {
        return new CollectionBuilder<T>(parentNode, protobufClass);
    }

}
TOP

Related Classes of io.fathom.cloud.state.NumberedItemCollection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.