org.omnaest.utils.table.impl.TableIndexArbitraryImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.omnaest.utils.table.impl.TableIndexArbitraryImpl.java

Source

/*******************************************************************************
 * Copyright 2012 Danny Kunz
 * 
 * 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 org.omnaest.utils.table.impl;

import java.io.Serializable;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentSkipListMap;

import org.apache.commons.lang3.ObjectUtils;
import org.omnaest.utils.structure.collection.CollectionUtils;
import org.omnaest.utils.structure.collection.set.SetUtils;
import org.omnaest.utils.structure.element.KeyExtractor;
import org.omnaest.utils.structure.element.converter.ElementBidirectionalConverterSerializable;
import org.omnaest.utils.structure.element.converter.ElementBidirectionalConverterSetToUnmodifiableSet;
import org.omnaest.utils.structure.element.factory.concrete.LinkedHashSetFactory;
import org.omnaest.utils.structure.map.MapUtils;
import org.omnaest.utils.table.Row;
import org.omnaest.utils.table.RowDataReader;
import org.omnaest.utils.table.Table;
import org.omnaest.utils.table.TableEventHandler;
import org.omnaest.utils.table.TableIndex;
import org.omnaest.utils.table.impl.rowdata.ElementsToRowDataReaderAdapter;
import org.omnaest.utils.table.impl.rowdata.RowToRowDataAccessorAdapter;

/**
 * @see TableIndex
 * @author Omnaest
 * @param <E>
 */
class TableIndexArbitraryImpl<K, E> implements SortedMap<K, Set<Row<E>>>, TableEventHandler<E>, Serializable {
    /* ************************************************** Constants *************************************************** */
    private static final long serialVersionUID = -8584025610784755115L;
    /* ************************************** Variables / State (internal/hiding) ************************************* */
    private final SortedMap<K, Set<Row<E>>> keyToRowSetMap;
    private final KeyExtractor<K, RowDataReader<E>> keyExtractor;
    private final Table<E> table;

    /* *************************************************** Methods **************************************************** */

    /**
     * @see TableIndexArbitraryImpl
     * @param column
     */
    TableIndexArbitraryImpl(Table<E> table, KeyExtractor<K, RowDataReader<E>> keyExtractor,
            Comparator<K> comparator) {
        super();
        this.table = table;
        this.keyExtractor = keyExtractor;

        this.keyToRowSetMap = MapUtils.initializedSortedMap(new ConcurrentSkipListMap<K, Set<Row<E>>>(),
                new LinkedHashSetFactory<Row<E>>());

        this.rebuildIndexFully();

    }

    private void rebuildIndexFully() {
        this.keyToRowSetMap.clear();
        for (Row<E> row : this.table.rows()) {
            final K key = extractKey(row);
            this.keyToRowSetMap.get(key).add(row);
        }
    }

    private K extractKey(Row<E> row) {
        final RowDataReader<E> rowDataReader = new RowToRowDataAccessorAdapter<E>(row);
        final K key = this.keyExtractor.extractKey(rowDataReader);
        return key;
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Comparator<? super K> comparator() {
        return this.keyToRowSetMap.comparator();
    }

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

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

    @Override
    public Set<java.util.Map.Entry<K, Set<Row<E>>>> entrySet() {
        return Collections.unmodifiableSet(SetUtils.adapter(this.keyToRowSetMap.entrySet(),
                new ElementBidirectionalConverterSerializable<Entry<K, Set<Row<E>>>, Entry<K, Set<Row<E>>>>() {

                    private static final long serialVersionUID = 1170906776959603812L;

                    @Override
                    public java.util.Map.Entry<K, Set<Row<E>>> convert(final Map.Entry<K, Set<Row<E>>> entry) {
                        // 
                        return new Entry<K, Set<Row<E>>>() {
                            @Override
                            public K getKey() {
                                return entry.getKey();
                            }

                            @Override
                            public Set<Row<E>> getValue() {
                                return Collections.unmodifiableSet(entry.getValue());
                            }

                            @Override
                            public Set<Row<E>> setValue(Set<Row<E>> value) {
                                throw new UnsupportedOperationException();
                            }

                            @Override
                            public String toString() {
                                return String.valueOf(this.getKey()) + "=" + String.valueOf(this.getValue());
                            }

                        };
                    }

                    @Override
                    public java.util.Map.Entry<K, Set<Row<E>>> convertBackwards(
                            java.util.Map.Entry<K, Set<Row<E>>> element) {
                        throw new UnsupportedOperationException();
                    }
                }));
    }

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

    @Override
    public K firstKey() {
        return this.keyToRowSetMap.firstKey();
    }

    @Override
    public Set<Row<E>> get(Object key) {
        return this.containsKey(key) ? Collections.unmodifiableSet(this.keyToRowSetMap.get(key)) : null;
    }

    @Override
    public void handleAddedColumn(int columnIndex, E... elements) {
        this.rebuildIndexFully();
    }

    @Override
    public void handleAddedRow(int rowIndex, E... elements) {
        this.rebuildIndexFully();
    }

    @Override
    public void handleClearTable() {
        this.keyToRowSetMap.clear();
    }

    @Override
    public void handleRemovedColumn(int columnIndex, E[] previousElements, String columnTitle) {
        this.rebuildIndexFully();
    }

    @Override
    public void handleRemovedRow(int rowIndex, E[] previousElements, String rowTitle) {
        final K key = extractKey(previousElements);
        boolean containsKey = this.keyToRowSetMap.containsKey(key);
        if (containsKey) {
            final Set<Row<E>> rowSet = this.keyToRowSetMap.get(key);
            for (Row<E> row : rowSet) {
                if (row.isDeleted() || row.index() == rowIndex) {
                    rowSet.remove(row);
                    break;
                }
            }
            if (rowSet.isEmpty()) {
                this.keyToRowSetMap.remove(key);
            }
        }
    }

    private K extractKey(E[] previousElements) {
        final RowDataReader<E> rowDataReader = new ElementsToRowDataReaderAdapter<E>(previousElements, this.table);
        final K key = this.keyExtractor.extractKey(rowDataReader);
        return key;
    }

    @Override
    public void handleUpdatedCell(int rowIndex, int columnIndex, E element, E previousElement) {
        final Row<E> row = this.table.row(rowIndex);
        final E[] elements = row.getElements();
        final E[] elementsPrevious = Arrays.copyOf(elements, elements.length);
        elementsPrevious[columnIndex] = previousElement;

        final K keyPrevious = this.extractKey(elementsPrevious);
        final K keyNew = this.extractKey(elements);

        this.updateForChangedRow(rowIndex, row, keyPrevious, keyNew);
    }

    @Override
    public void handleUpdatedRow(int rowIndex, E[] elements, E[] previousElements, BitSet modifiedIndices) {
        final Row<E> row = this.table.row(rowIndex);
        final K keyPrevious = this.extractKey(previousElements);
        final K keyNew = this.extractKey(elements);

        this.updateForChangedRow(rowIndex, row, keyPrevious, keyNew);
    }

    private void updateForChangedRow(int rowIndex, final Row<E> row, final K keyPrevious, final K keyNew) {
        if (!ObjectUtils.equals(keyNew, keyPrevious)) {
            //remove old
            if (keyPrevious != null) {
                final Set<Row<E>> rowSet = this.keyToRowSetMap.get(keyPrevious);
                final Set<Row<E>> rowRemovableSet = new HashSet<Row<E>>();
                for (Row<E> iRow : rowSet) {
                    if (iRow.index() == rowIndex) {
                        rowRemovableSet.add(iRow);
                    }
                }
                rowSet.removeAll(rowRemovableSet);
                if (rowSet.isEmpty()) {
                    this.keyToRowSetMap.remove(keyPrevious);
                }
            }

            //add new
            if (keyNew != null) {
                Set<Row<E>> rowSet = this.keyToRowSetMap.get(keyNew);
                rowSet.add(row);
            }

        }
    }

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

    @Override
    public SortedMap<K, Set<Row<E>>> headMap(K toKey) {
        return Collections.unmodifiableSortedMap(MapUtils.adapter(this.keyToRowSetMap.headMap(toKey),
                new ElementBidirectionalConverterSetToUnmodifiableSet<Row<E>>()));
    }

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

    @Override
    public Set<K> keySet() {
        return Collections.unmodifiableSet(this.keyToRowSetMap.keySet());
    }

    @Override
    public K lastKey() {
        return this.keyToRowSetMap.lastKey();
    }

    @Override
    public Set<Row<E>> put(K key, Set<Row<E>> value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void putAll(Map<? extends K, ? extends Set<Row<E>>> m) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set<Row<E>> remove(Object key) {
        throw new UnsupportedOperationException();
    }

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

    @Override
    public SortedMap<K, Set<Row<E>>> subMap(K fromKey, K toKey) {
        return Collections.unmodifiableSortedMap(MapUtils.adapter(this.keyToRowSetMap.subMap(fromKey, toKey),
                new ElementBidirectionalConverterSetToUnmodifiableSet<Row<E>>()));
    }

    @Override
    public SortedMap<K, Set<Row<E>>> tailMap(K fromKey) {
        return Collections.unmodifiableSortedMap(MapUtils.adapter(this.keyToRowSetMap.tailMap(fromKey),
                new ElementBidirectionalConverterSetToUnmodifiableSet<Row<E>>()));
    }

    @Override
    public Collection<Set<Row<E>>> values() {
        return Collections.unmodifiableCollection(CollectionUtils.adapter(this.keyToRowSetMap.values(),
                new ElementBidirectionalConverterSetToUnmodifiableSet<Row<E>>()));
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(MapUtils.toString(this));
        return builder.toString();
    }

    @Override
    public void handleModifiedColumnTitle(int columnIndex, String columnTitle, String columnTitlePrevious) {
    }

    @Override
    public void handleModifiedRowTitle(int rowIndex, String rowTitle, String rowTitlePrevious) {
    }

    @Override
    public void handleModifiedColumnTitles(String[] columnTitles, String[] columnTitlesPrevious) {
    }

    @Override
    public void handleModifiedRowTitles(String[] rowTitles, String[] rowTitlesPrevious) {
    }

    @Override
    public void handleModifiedTableName(String tableName, String tableNamePrevious) {
    }

}