Package com.higherfrequencytrading.chronicle.datamodel

Source Code of com.higherfrequencytrading.chronicle.datamodel.MapWrapper

/*
* Copyright 2013 Peter Lawrey
*
* 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.higherfrequencytrading.chronicle.datamodel;

import com.higherfrequencytrading.chronicle.Excerpt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.util.*;

import static com.higherfrequencytrading.chronicle.datamodel.WrapperEvent.*;

/**
* @author peter.lawrey
*/
public class MapWrapper<K, V> implements ObservableMap<K, V> {
    @NotNull
    private final DataStore dataStore;
    private final String name;
    @NotNull
    private final Class<K> kClass;
    @NotNull
    private final Class<V> vClass;
    @NotNull
    private final Map<K, V> underlying;
    private final int maxMessageSize;
    private final List<MapListener<K, V>> listeners = new ArrayList<MapListener<K, V>>();
    private final Set<K> keySet;
    private final Collection<V> values;
    private final Set<Entry<K, V>> entrySet;
    private final boolean kEnumClass;
    private final boolean vEnumClass;
    private boolean notifyOff = false;
    @NotNull
    private Annotation[] annotations = {};

    public MapWrapper(@NotNull DataStore dataStore, String name, @NotNull Class<K> kClass, @NotNull Class<V> vClass, @NotNull Map<K, V> underlying, int maxMessageSize) {
        this.dataStore = dataStore;
        this.name = name;
        this.kClass = kClass;
        this.vClass = vClass;
        this.underlying = underlying;
        this.maxMessageSize = maxMessageSize;
        kEnumClass = dataStore.enumeratedClass(kClass);
        vEnumClass = dataStore.enumeratedClass(vClass);

        keySet = Collections.unmodifiableSet(underlying.keySet());
        values = Collections.unmodifiableCollection(underlying.values());
        entrySet = Collections.unmodifiableSet(underlying.entrySet());

        dataStore.add(name, this);
    }

    @NotNull
    public Annotation[] getAnnotations() {
        return annotations;
    }

    public void setAnnotations(@NotNull Annotation[] annotations) {
        this.annotations = Arrays.copyOf(annotations, annotations.length);
    }

    @Nullable
    @SuppressWarnings("unchecked")
    @Override
    public <A extends Annotation> A getAnnotation(@NotNull Class<A> annotationClass) {
        for (Annotation annotation : annotations) {
            if (annotationClass.isInstance(annotation))
                return (A) annotation;
        }
        return null;
    }

    @Override
    public void addListener(MapListener<K, V> listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(MapListener<K, V> listener) {
        listeners.remove(listener);
    }

    @Override
    public void inSync() {
        for (MapListener<K, V> listener : listeners) {
            listener.inSync();
        }
    }

    // reload, and synchronise the map.
    @Override
    public void onExcerpt(@NotNull Excerpt excerpt) {
        int position = excerpt.position();
        WrapperEvent event = excerpt.readEnum(WrapperEvent.class);
        if (event == null) {
            excerpt.position(position);
            System.err.println("Unknown event type " + excerpt.readUTF());
            return;
        }
        if (!notifyOff) {
            for (int i = 0; i < listeners.size(); i++)
                listeners.get(i).eventStart(excerpt.index(), name);
        }
        try {
            switch (event) {
                case put: {
                    onExcerptPut(excerpt);
                    break;

                }
                case putAll: {
                    int count = excerpt.readInt();
                    for (int i = 0; i < count; i++)
                        onExcerptPut(excerpt);
                    break;
                }
                case remove: {
                    @SuppressWarnings("unchecked")
                    K key = readKey(excerpt);
                    V value = underlying.remove(key);
                    if (!notifyOff)
                        for (int i = 0; i < listeners.size(); i++)
                            listeners.get(i).remove(key, value);

                    break;
                }

                case clear: {
                    if (!notifyOff) {
                        @SuppressWarnings("unchecked")
                        Entry<K, V>[] entrySet = underlying.entrySet().toArray(new Entry[underlying.size()]);
                        for (int i = 0; i < listeners.size(); i++) {
                            MapListener<K, V> listener = listeners.get(i);
                            for (int j = 0; j < entrySet.length; j++) {
                                listener.remove(entrySet[j].getKey(), entrySet[j].getValue());
                            }
                        }
                    }
                    underlying.clear();
                    break;
                }
                case event: {
                    if (!notifyOff) {
                        Object object = excerpt.readObject();
                        for (int i = 0; i < listeners.size(); i++)
                            listeners.get(i).onEvent(object);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!notifyOff) {
            boolean lastEvent = !excerpt.hasNextIndex();

            for (int i = 0; i < listeners.size(); i++) {
                listeners.get(i).eventEnd(lastEvent);
            }
        }

    }

    private void onExcerptPut(@NotNull Excerpt excerpt) {
        K key = readKey(excerpt);
        V value = readValue(excerpt);
        V previous = underlying.put(key, value);
        if (!notifyOff)
            for (int i = 0; i < listeners.size(); i++) {
                MapListener<K, V> listener = listeners.get(i);
                if (previous == null)
                    listener.add(key, value);
                else
                    listener.update(key, previous, value);
            }
    }

    @SuppressWarnings("unchecked")
    private V readValue(@NotNull Excerpt excerpt) {
        if (vEnumClass)
            return excerpt.readEnum(vClass);
        return (V) excerpt.readObject();
    }

    @SuppressWarnings("unchecked")
    private K readKey(@NotNull Excerpt excerpt) {
        if (kEnumClass)
            return excerpt.readEnum(kClass);
        return (K) excerpt.readObject();
    }

    @Override
    public void notifyOff(boolean notifyOff) {
        this.notifyOff = notifyOff;
    }

    //// Map
    @Override
    public void clear() {
        checkWritable();
        writeClear();
    }

    private void writeClear() {
        Excerpt excerpt = getExcerpt(16, clear);
        long eventId = excerpt.index();
        excerpt.writeEnum(clear);
        excerpt.finish();
        if (!notifyOff && !listeners.isEmpty()) {
            @SuppressWarnings("unchecked")
            Entry<K, V>[] entrySet = underlying.entrySet().toArray(new Entry[underlying.size()]);
            for (int i = 0; i < listeners.size(); i++) {
                MapListener<K, V> listener = listeners.get(i);
                listener.eventStart(eventId, name);
                for (int j = 0; j < entrySet.length; j++) {
                    listener.remove(entrySet[j].getKey(), entrySet[j].getValue());
                }
                listener.eventEnd(true);
            }
        }
    }

    @NotNull
    private Excerpt getExcerpt(int maxSize, @NotNull WrapperEvent event) {
        Excerpt excerpt = dataStore.startExcerpt(maxSize + 2 + event.name().length(), name);
        excerpt.writeEnum(event);
        return excerpt;
    }

    void checkWritable() {
        dataStore.checkWritable();
    }

    @Override
    public boolean containsKey(Object key) {
        return underlying.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return underlying.containsValue(value);
    }

    @NotNull
    @Override
    public Set<Entry<K, V>> entrySet() {
        return entrySet;
    }

    @Override
    public boolean equals(Object o) {
        return underlying.equals(o);
    }

    @Override
    public V get(Object key) {
        return underlying.get(key);
    }

    @Override
    public int hashCode() {
        return underlying.hashCode();
    }

    @Override
    public boolean isEmpty() {
        return underlying.isEmpty();
    }

    @NotNull
    @Override
    public Set<K> keySet() {
        return keySet;
    }

    @Override
    public V put(K key, V value) {
        checkWritable();
        V previous = underlying.put(key, value);
        if (sameOrNotEqual(previous, value))
            writePut(key, previous, value);
        return previous;
    }

    private void writePut(K key, @Nullable V previous, V value) {
        Excerpt excerpt = getExcerpt(maxMessageSize, put);
        long eventId = excerpt.index();
        writeKey(excerpt, key);
        writeValue(excerpt, value);
        excerpt.finish();
        if (!notifyOff && !listeners.isEmpty()) {
            for (int i = 0; i < listeners.size(); i++) {
                MapListener<K, V> listener = listeners.get(i);
                listener.eventStart(eventId, name);
                if (previous == null)
                    listener.add(key, value);
                else
                    listener.update(key, previous, value);
                listener.eventEnd(true);
            }
        }
    }

    private void writeValue(@NotNull Excerpt excerpt, V value) {
        if (vEnumClass)
            excerpt.writeEnum(value);
        else
            excerpt.writeObject(value);
    }

    private void writeKey(@NotNull Excerpt excerpt, K key) {
        if (kEnumClass)
            excerpt.writeEnum(key);
        else
            excerpt.writeObject(key);
    }

    protected boolean sameOrNotEqual(@Nullable V previous, V value) {
        return previous == value || previous == null || !previous.equals(value);
    }

    @Override
    public void putAll(@NotNull Map<? extends K, ? extends V> m) {
        checkWritable();
        performAndWritePutAll(m);
    }

    private void performAndWritePutAll(@NotNull Map<? extends K, ? extends V> m) {
        Excerpt excerpt = getExcerpt(m.size() * maxMessageSize, putAll);
        long eventId = excerpt.index();
        int pos = excerpt.position();
        excerpt.writeInt(0); // place holder for the actual size.
        int count = 0;
        for (int i = 0; i < listeners.size(); i++) {
            MapListener<K, V> listener = listeners.get(i);
            listener.eventStart(eventId, name);
        }
        for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
            K key = entry.getKey();
            V value = entry.getValue();
            V previous = underlying.put(key, value);
            if (sameOrNotEqual(previous, value)) {
                writeKey(excerpt, key);
                writeValue(excerpt, value);
                for (int i = 0; i < listeners.size(); i++) {
                    MapListener<K, V> listener = listeners.get(i);
                    if (previous == null)
                        listener.add(key, value);
                    else
                        listener.update(key, previous, value);
                }
                count++;
            }
            for (int i = 0; i < listeners.size(); i++) {
                MapListener<K, V> listener = listeners.get(i);
                listener.eventEnd(true);
            }
        }
        excerpt.writeInt(pos, count);
        excerpt.finish();
    }

    @Override
    public V remove(Object key) {
        checkWritable();
        V value = underlying.remove(key);
        if (value != null)
            writeRemove(key, value);
        return value;
    }

    @SuppressWarnings("unchecked")
    private void writeRemove(Object key, V value) {
        Excerpt excerpt = getExcerpt(maxMessageSize, remove);
        long eventId = excerpt.index();
        writeKey(excerpt, (K) key);
        writeValue(excerpt, value);
        excerpt.finish();
        if (!notifyOff && !listeners.isEmpty()) {
            for (int i = 0; i < listeners.size(); i++) {
                MapListener<K, V> listener = listeners.get(i);
                listener.eventStart(eventId, name);
                listener.remove((K) key, value);
                listener.eventEnd(true);
            }
        }
    }

    @Override
    public int size() {
        return underlying.size();
    }

    @Override
    public String toString() {
        return underlying.toString();
    }

    @NotNull
    @Override
    public Collection<V> values() {
        return values;
    }

    @Override
    public void publishEvent(Object object) {
        Excerpt excerpt = getExcerpt(maxMessageSize + 128, event);
        long eventId = excerpt.index();
        excerpt.writeObject(event);
        excerpt.finish();

        if (!notifyOff && !listeners.isEmpty()) {
            for (int i = 0; i < listeners.size(); i++) {
                MapListener<K, V> listener = listeners.get(i);
                listener.eventStart(eventId, name);
                listener.onEvent(object);
                listener.eventEnd(true);
            }
        }
    }
}
TOP

Related Classes of com.higherfrequencytrading.chronicle.datamodel.MapWrapper

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.