All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.umbraltech.rxchange.adapter.collections.MapChangeAdapter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2018 - present, RxChange contributors
 *
 * 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.umbraltech.rxchange.adapter.collections;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.umbraltech.rxchange.message.ChangeMessage;
import com.umbraltech.rxchange.message.MetaChangeMessage;
import com.umbraltech.rxchange.type.ChangeType;
import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * An adapter that implements the reactive change model for maps
 *
 * @param  the type used for the keys
 * @param  the type used for the data
 */
public class MapChangeAdapter {
    private final PublishSubject>> publishSubject = PublishSubject.create();
    private final Map dataMap = new HashMap<>();

    /**
     * Default constructor
     */
    public MapChangeAdapter() {
        // Stub
    }

    /**
     * Initializes the adapter with a map of entries, without emitting a change message
     *
     * @param initialDataMap the initial map of entries
     */
    public MapChangeAdapter(final Map initialDataMap) {
        dataMap.putAll(initialDataMap);
    }

    /**
     * Adds a key-value pair to the map and emits a change message to surrounding observers
     * 

* The metadata in the emitted change message will contain a snapshot * of the entry that was just added * * @param key the key used for accessing the data * @param data the value associated with the key * @return {@code true} if the entry was added to the map, {@code false} otherwise */ public boolean add(final K key, final D data) { // Check if entry already exists if (dataMap.containsKey(key)) { return false; } final Map oldMapSnapshot = ImmutableMap.copyOf(dataMap); dataMap.put(key, data); final Map newMapSnapshot = ImmutableMap.copyOf(dataMap); final Map.Entry changeSnapshot = Maps.immutableEntry(key, data); // Signal addition publishSubject.onNext(new MetaChangeMessage<>(oldMapSnapshot, newMapSnapshot, ChangeType.ADD, changeSnapshot)); return true; } /** * Adds a collection of key-value pairs to the map and emits a change message to surrounding observers *

* The metadata in the emitted change message will contain a snapshot * of the entries that were just added * * @param dataMap the map containing the entries to be added * @return {@code true} if all of the entries were added, {@code false} otherwise */ public boolean addAll(final Map dataMap) { // Check if entries already exist for (final K key : dataMap.keySet()) { if (this.dataMap.containsKey(key)) { return false; } } final Map oldMapSnapshot = ImmutableMap.copyOf(this.dataMap); this.dataMap.putAll(dataMap); final Map newMapSnapshot = ImmutableMap.copyOf(this.dataMap); final Map changeSnapshot = ImmutableMap.copyOf(dataMap); // Signal addition publishSubject.onNext(new MetaChangeMessage<>(oldMapSnapshot, newMapSnapshot, ChangeType.ADD, changeSnapshot)); return true; } /** * Removes an entry specified by the key and emits a change message to surrounding observers *

* The metadata in the emitted change message will contain a snapshot * of the entry that was just removed * * @param key the key associated with the entry to be removed * @return {@code true} if the entry was removed, {@code false} otherwise */ public boolean remove(final K key) { // Check if no entry to remove if (!dataMap.containsKey(key)) { return false; } final Map oldMapSnapshot = ImmutableMap.copyOf(dataMap); final D resultData = dataMap.remove(key); final Map newMapSnapshot = ImmutableMap.copyOf(dataMap); final Map.Entry changeSnapshot = Maps.immutableEntry(key, resultData); // Signal removal publishSubject.onNext(new MetaChangeMessage<>(oldMapSnapshot, newMapSnapshot, ChangeType.REMOVE, changeSnapshot)); return true; } /** * Removes a collection of entries from the map and emits a change message to surrounding observers *

* The metadata in the emitted change message will contain a snapshot * of the entries that were just removed * * @param keySet the set of keys for the entries to be removed * @return {@code true} if all of the entries were removed, {@code false} otherwise */ public boolean removeAll(final Set keySet) { // Check if no entries to remove for (final K key : keySet) { if (!this.dataMap.containsKey(key)) { return false; } } final Map oldMapSnapshot = ImmutableMap.copyOf(this.dataMap); this.dataMap.keySet().removeAll(keySet); final Map newMapSnapshot = ImmutableMap.copyOf(this.dataMap); final Map changeSnapshot = Maps.difference(oldMapSnapshot, newMapSnapshot).entriesOnlyOnLeft(); // Signal removal publishSubject.onNext(new MetaChangeMessage<>(oldMapSnapshot, newMapSnapshot, ChangeType.REMOVE, changeSnapshot)); return true; } /** * Updates the value of an entry in the map and emits a change message to surrounding observers *

* The metadata in the emitted change message will contain a snapshot * of the entry that was just updated * * @param key the key associated with the old data * @param data the new value stored with the key * @return {@code true} if the entry was updated, {@code false} otherwise */ public boolean update(final K key, final D data) { // Check if entry does not exist if (!dataMap.containsKey(key)) { return false; } final Map oldMapSnapshot = ImmutableMap.copyOf(dataMap); dataMap.put(key, data); final Map newMapSnapshot = ImmutableMap.copyOf(dataMap); final Map.Entry changeSnapshot = Maps.immutableEntry(key, data); // Signal update publishSubject.onNext(new MetaChangeMessage<>(oldMapSnapshot, newMapSnapshot, ChangeType.UPDATE, changeSnapshot)); return true; } /** * Updates multiple entries in the map and emits a change message to surrounding observers *

* The metadata in the emitted change message will contain a snapshot * of the entries that were just updated * * @param dataMap the map containing the entries to be updated * @return {@code true} if all of the entries were updated, {@code false} otherwise */ public boolean updateAll(final Map dataMap) { // Check if entries do not exist for (final K key : dataMap.keySet()) { if (!this.dataMap.containsKey(key)) { return false; } } final Map oldMapSnapshot = ImmutableMap.copyOf(this.dataMap); this.dataMap.putAll(dataMap); final Map newMapSnapshot = ImmutableMap.copyOf(this.dataMap); final Map changeSnapshot = ImmutableMap.copyOf(dataMap); // Signal update publishSubject.onNext(new MetaChangeMessage<>(oldMapSnapshot, newMapSnapshot, ChangeType.UPDATE, changeSnapshot)); return true; } /** * Returns the data of the entry specified by the key * * @param key the key used for the retrieval * @return the data associated with the key, null if not found */ public D get(final K key) { if (!dataMap.containsKey(key)) { return null; } return dataMap.get(key); } /** * Returns an immutable snapshot of the current map * * @return the map of elements */ public Map getAll() { return ImmutableMap.copyOf(dataMap); } /** * Returns a reference to the observable used for listening to change messages * * @return the observable reference */ public Observable>> getObservable() { return publishSubject; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy