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

org.glassfish.jersey.internal.guava.StandardTable Maven / Gradle / Ivy

Go to download

A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle (jaxrs-ri.jar). Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from the command line.

There is a newer version: 3.1.9
Show newest version
/*
 * Copyright (C) 2008 The Guava Authors
 *
 * 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.glassfish.jersey.internal.guava;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import static org.glassfish.jersey.internal.guava.Preconditions.checkNotNull;
import static org.glassfish.jersey.internal.guava.Predicates.alwaysTrue;
import static org.glassfish.jersey.internal.guava.Predicates.equalTo;
import static org.glassfish.jersey.internal.guava.Predicates.in;
import static org.glassfish.jersey.internal.guava.Predicates.not;

/**
 * {@link Table} implementation backed by a map that associates row keys with
 * column key / value secondary maps. This class provides rapid access to
 * records by the row key alone or by both keys, but not by just the column key.
 * 

*

The views returned by {@link #column}, {@link #columnKeySet()}, and {@link * #columnMap()} have iterators that don't support {@code remove()}. Otherwise, * all optional operations are supported. Null row keys, columns keys, and * values are not supported. *

*

Lookups by row key are often faster than lookups by column key, because * the data is stored in a {@code Map>}. A method call like {@code * column(columnKey).get(rowKey)} still runs quickly, since the row key is * provided. However, {@code column(columnKey).size()} takes longer, since an * iteration across all row keys occurs. *

*

Note that this implementation is not synchronized. If multiple threads * access this table concurrently and one of the threads modifies the table, it * must be synchronized externally. * * @author Jared Levy */ class StandardTable extends AbstractTable implements Serializable { private static final long serialVersionUID = 0; private final Map> backingMap; private final Supplier> factory; // Accessors private transient Set columnKeySet; private transient Map> rowMap; private transient ColumnMap columnMap; StandardTable(Map> backingMap, Supplier> factory) { this.backingMap = backingMap; this.factory = factory; } @Override public boolean contains( Object rowKey, Object columnKey) { return rowKey != null && columnKey != null && super.contains(rowKey, columnKey); } @Override public boolean containsColumn(Object columnKey) { if (columnKey == null) { return false; } for (Map map : backingMap.values()) { if (Maps.safeContainsKey(map, columnKey)) { return true; } } return false; } // Mutators @Override public boolean containsRow(Object rowKey) { return rowKey != null && Maps.safeContainsKey(backingMap, rowKey); } @Override public boolean containsValue(Object value) { return value != null && super.containsValue(value); } @Override public V get(Object rowKey, Object columnKey) { return (rowKey == null || columnKey == null) ? null : super.get(rowKey, columnKey); } @Override public int size() { int size = 0; for (Map map : backingMap.values()) { size += map.size(); } return size; } @Override public void clear() { backingMap.clear(); } private Map getOrCreate(R rowKey) { Map map = backingMap.get(rowKey); if (map == null) { map = factory.get(); backingMap.put(rowKey, map); } return map; } @Override public V put(R rowKey, C columnKey, V value) { checkNotNull(rowKey); checkNotNull(columnKey); checkNotNull(value); return getOrCreate(rowKey).put(columnKey, value); } // Views @Override public V remove( Object rowKey, Object columnKey) { if ((rowKey == null) || (columnKey == null)) { return null; } Map map = Maps.safeGet(backingMap, rowKey); if (map == null) { return null; } V value = map.remove(columnKey); if (map.isEmpty()) { backingMap.remove(rowKey); } return value; } private Map removeColumn(Object column) { Map output = new LinkedHashMap(); Iterator>> iterator = backingMap.entrySet().iterator(); while (iterator.hasNext()) { Entry> entry = iterator.next(); V value = entry.getValue().remove(column); if (value != null) { output.put(entry.getKey(), value); if (entry.getValue().isEmpty()) { iterator.remove(); } } } return output; } private boolean containsMapping( Object rowKey, Object columnKey, Object value) { return value != null && value.equals(get(rowKey, columnKey)); } /** * Remove a row key / column key / value mapping, if present. */ private boolean removeMapping(Object rowKey, Object columnKey, Object value) { if (containsMapping(rowKey, columnKey, value)) { remove(rowKey, columnKey); return true; } return false; } /** * {@inheritDoc} *

*

The set's iterator traverses the mappings for the first row, the * mappings for the second row, and so on. *

*

Each cell is an immutable snapshot of a row key / column key / value * mapping, taken at the time the cell is returned by a method call to the * set or its iterator. */ @Override public Set> cellSet() { return super.cellSet(); } @Override Iterator> cellIterator() { return new CellIterator(); } @Override public Map row(R rowKey) { return new Row(rowKey); } /** * {@inheritDoc} *

*

The returned map's views have iterators that don't support * {@code remove()}. */ @Override public Map column(C columnKey) { return new Column(columnKey); } @Override public Set rowKeySet() { return rowMap().keySet(); } /** * {@inheritDoc} *

*

The returned set has an iterator that does not support {@code remove()}. *

*

The set's iterator traverses the columns of the first row, the * columns of the second row, etc., skipping any columns that have * appeared previously. */ @Override public Set columnKeySet() { Set result = columnKeySet; return (result == null) ? columnKeySet = new ColumnKeySet() : result; } /** * Creates an iterator that returns each column value with duplicates * omitted. */ private Iterator createColumnKeyIterator() { return new ColumnKeyIterator(); } @Override public Map> rowMap() { Map> result = rowMap; return (result == null) ? rowMap = createRowMap() : result; } private Map> createRowMap() { return new RowMap(); } @Override public Map> columnMap() { ColumnMap result = columnMap; return (result == null) ? columnMap = new ColumnMap() : result; } /** * Abstract set whose {@code isEmpty()} returns whether the table is empty and * whose {@code clear()} clears all table mappings. */ private abstract class TableSet extends Sets.ImprovedAbstractSet { @Override public boolean isEmpty() { return backingMap.isEmpty(); } @Override public void clear() { backingMap.clear(); } } private class CellIterator implements Iterator> { final Iterator>> rowIterator = backingMap.entrySet().iterator(); Entry> rowEntry; Iterator> columnIterator = Iterators.emptyModifiableIterator(); @Override public boolean hasNext() { return rowIterator.hasNext() || columnIterator.hasNext(); } @Override public Cell next() { if (!columnIterator.hasNext()) { rowEntry = rowIterator.next(); columnIterator = rowEntry.getValue().entrySet().iterator(); } Entry columnEntry = columnIterator.next(); return Tables.immutableCell( rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue()); } @Override public void remove() { columnIterator.remove(); if (rowEntry.getValue().isEmpty()) { rowIterator.remove(); } } } class Row extends Maps.ImprovedAbstractMap { final R rowKey; Map backingRowMap; Row(R rowKey) { this.rowKey = checkNotNull(rowKey); } Map backingRowMap() { return (backingRowMap == null || (backingRowMap.isEmpty() && backingMap.containsKey(rowKey))) ? backingRowMap = computeBackingRowMap() : backingRowMap; } Map computeBackingRowMap() { return backingMap.get(rowKey); } // Call this every time we perform a removal. void maintainEmptyInvariant() { if (backingRowMap() != null && backingRowMap.isEmpty()) { backingMap.remove(rowKey); backingRowMap = null; } } @Override public boolean containsKey(Object key) { Map backingRowMap = backingRowMap(); return (key != null && backingRowMap != null) && Maps.safeContainsKey(backingRowMap, key); } @Override public V get(Object key) { Map backingRowMap = backingRowMap(); return (key != null && backingRowMap != null) ? Maps.safeGet(backingRowMap, key) : null; } @Override public V put(C key, V value) { checkNotNull(key); checkNotNull(value); if (backingRowMap != null && !backingRowMap.isEmpty()) { return backingRowMap.put(key, value); } return StandardTable.this.put(rowKey, key, value); } @Override public V remove(Object key) { Map backingRowMap = backingRowMap(); if (backingRowMap == null) { return null; } V result = Maps.safeRemove(backingRowMap, key); maintainEmptyInvariant(); return result; } @Override public void clear() { Map backingRowMap = backingRowMap(); if (backingRowMap != null) { backingRowMap.clear(); } maintainEmptyInvariant(); } @Override protected Set> createEntrySet() { return new RowEntrySet(); } private final class RowEntrySet extends Maps.EntrySet { @Override Map map() { return Row.this; } @Override public int size() { Map map = backingRowMap(); return (map == null) ? 0 : map.size(); } @Override public Iterator> iterator() { final Map map = backingRowMap(); if (map == null) { return Iterators.emptyModifiableIterator(); } final Iterator> iterator = map.entrySet().iterator(); return new Iterator>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public Entry next() { final Entry entry = iterator.next(); return new ForwardingMapEntry() { @Override protected Entry delegate() { return entry; } @Override public V setValue(V value) { return super.setValue(checkNotNull(value)); } @Override public boolean equals(Object object) { // TODO(user): identify why this affects GWT tests return standardEquals(object); } }; } @Override public void remove() { iterator.remove(); maintainEmptyInvariant(); } }; } } } private class Column extends Maps.ImprovedAbstractMap { final C columnKey; Column(C columnKey) { this.columnKey = checkNotNull(columnKey); } @Override public V put(R key, V value) { return StandardTable.this.put(key, columnKey, value); } @Override public V get(Object key) { return StandardTable.this.get(key, columnKey); } @Override public boolean containsKey(Object key) { return StandardTable.this.contains(key, columnKey); } @Override public V remove(Object key) { return StandardTable.this.remove(key, columnKey); } /** * Removes all {@code Column} mappings whose row key and value satisfy the * given predicate. */ boolean removeFromColumnIf(Predicate> predicate) { boolean changed = false; Iterator>> iterator = backingMap.entrySet().iterator(); while (iterator.hasNext()) { Entry> entry = iterator.next(); Map map = entry.getValue(); V value = map.get(columnKey); if (value != null && predicate.test(Maps.immutableEntry(entry.getKey(), value))) { map.remove(columnKey); changed = true; if (map.isEmpty()) { iterator.remove(); } } } return changed; } @Override Set> createEntrySet() { return new EntrySet(); } @Override Set createKeySet() { return new KeySet(); } @Override Collection createValues() { return new Values(); } private class EntrySet extends Sets.ImprovedAbstractSet> { @Override public Iterator> iterator() { return new EntrySetIterator(); } @Override public int size() { int size = 0; for (Map map : backingMap.values()) { if (map.containsKey(columnKey)) { size++; } } return size; } @Override public boolean isEmpty() { return !containsColumn(columnKey); } @Override public void clear() { removeFromColumnIf(alwaysTrue()); } @Override public boolean contains(Object o) { if (o instanceof Entry) { Entry entry = (Entry) o; return containsMapping(entry.getKey(), columnKey, entry.getValue()); } return false; } @Override public boolean remove(Object obj) { if (obj instanceof Entry) { Entry entry = (Entry) obj; return removeMapping(entry.getKey(), columnKey, entry.getValue()); } return false; } @Override public boolean retainAll(Collection c) { return removeFromColumnIf(not(in(c))); } } private class EntrySetIterator extends AbstractIterator> { final Iterator>> iterator = backingMap.entrySet().iterator(); @Override protected Entry computeNext() { while (iterator.hasNext()) { final Entry> entry = iterator.next(); if (entry.getValue().containsKey(columnKey)) { return new AbstractMapEntry() { @Override public R getKey() { return entry.getKey(); } @Override public V getValue() { return entry.getValue().get(columnKey); } @Override public V setValue(V value) { return entry.getValue().put(columnKey, checkNotNull(value)); } }; } } return endOfData(); } } private class KeySet extends Maps.KeySet { KeySet() { super(StandardTable.Column.this); } @Override public boolean contains(Object obj) { return StandardTable.this.contains(obj, columnKey); } @Override public boolean remove(Object obj) { return StandardTable.this.remove(obj, columnKey) != null; } @Override public boolean retainAll(final Collection c) { return removeFromColumnIf(Maps.keyPredicateOnEntries(not(in(c)))); } } private class Values extends Maps.Values { Values() { super(StandardTable.Column.this); } @Override public boolean remove(Object obj) { return obj != null && removeFromColumnIf(Maps.valuePredicateOnEntries(equalTo(obj))); } @Override public boolean removeAll(final Collection c) { return removeFromColumnIf(Maps.valuePredicateOnEntries(in(c))); } @Override public boolean retainAll(final Collection c) { return removeFromColumnIf(Maps.valuePredicateOnEntries(not(in(c)))); } } } private class ColumnKeySet extends TableSet { @Override public Iterator iterator() { return createColumnKeyIterator(); } @Override public int size() { return Iterators.size(iterator()); } @Override public boolean remove(Object obj) { if (obj == null) { return false; } boolean changed = false; Iterator> iterator = backingMap.values().iterator(); while (iterator.hasNext()) { Map map = iterator.next(); if (map.keySet().remove(obj)) { changed = true; if (map.isEmpty()) { iterator.remove(); } } } return changed; } @Override public boolean removeAll(Collection c) { checkNotNull(c); boolean changed = false; Iterator> iterator = backingMap.values().iterator(); while (iterator.hasNext()) { Map map = iterator.next(); // map.keySet().removeAll(c) can throw a NPE when map is a TreeMap with // natural ordering and c contains a null. if (Iterators.removeAll(map.keySet().iterator(), c)) { changed = true; if (map.isEmpty()) { iterator.remove(); } } } return changed; } @Override public boolean retainAll(Collection c) { checkNotNull(c); boolean changed = false; Iterator> iterator = backingMap.values().iterator(); while (iterator.hasNext()) { Map map = iterator.next(); if (map.keySet().retainAll(c)) { changed = true; if (map.isEmpty()) { iterator.remove(); } } } return changed; } @Override public boolean contains(Object obj) { return containsColumn(obj); } } private class ColumnKeyIterator extends AbstractIterator { // Use the same map type to support TreeMaps with comparators that aren't // consistent with equals(). final Map seen = factory.get(); final Iterator> mapIterator = backingMap.values().iterator(); Iterator> entryIterator = Iterators.emptyIterator(); @Override protected C computeNext() { while (true) { if (entryIterator.hasNext()) { Entry entry = entryIterator.next(); if (!seen.containsKey(entry.getKey())) { seen.put(entry.getKey(), entry.getValue()); return entry.getKey(); } } else if (mapIterator.hasNext()) { entryIterator = mapIterator.next().entrySet().iterator(); } else { return endOfData(); } } } } class RowMap extends Maps.ImprovedAbstractMap> { @Override public boolean containsKey(Object key) { return containsRow(key); } // performing cast only when key is in backing map and has the correct type @SuppressWarnings("unchecked") @Override public Map get(Object key) { return containsRow(key) ? row((R) key) : null; } @Override public Map remove(Object key) { return (key == null) ? null : backingMap.remove(key); } @Override protected Set>> createEntrySet() { return new EntrySet(); } class EntrySet extends TableSet>> { @Override public Iterator>> iterator() { return Maps.asMapEntryIterator(backingMap.keySet(), new Function>() { @Override public Map apply(R rowKey) { return row(rowKey); } }); } @Override public int size() { return backingMap.size(); } @Override public boolean contains(Object obj) { if (obj instanceof Entry) { Entry entry = (Entry) obj; return entry.getKey() != null && entry.getValue() instanceof Map && Collections2.safeContains(backingMap.entrySet(), entry); } return false; } @Override public boolean remove(Object obj) { if (obj instanceof Entry) { Entry entry = (Entry) obj; return entry.getKey() != null && entry.getValue() instanceof Map && backingMap.entrySet().remove(entry); } return false; } } } private class ColumnMap extends Maps.ImprovedAbstractMap> { // The cast to C occurs only when the key is in the map, implying that it // has the correct type. @SuppressWarnings("unchecked") @Override public Map get(Object key) { return containsColumn(key) ? column((C) key) : null; } @Override public boolean containsKey(Object key) { return containsColumn(key); } @Override public Map remove(Object key) { return containsColumn(key) ? removeColumn(key) : null; } @Override public Set>> createEntrySet() { return new ColumnMapEntrySet(); } @Override public Set keySet() { return columnKeySet(); } @Override Collection> createValues() { return new ColumnMapValues(); } class ColumnMapEntrySet extends TableSet>> { @Override public Iterator>> iterator() { return Maps.asMapEntryIterator(columnKeySet(), new Function>() { @Override public Map apply(C columnKey) { return column(columnKey); } }); } @Override public int size() { return columnKeySet().size(); } @Override public boolean contains(Object obj) { if (obj instanceof Entry) { Entry entry = (Entry) obj; if (containsColumn(entry.getKey())) { // The cast to C occurs only when the key is in the map, implying // that it has the correct type. @SuppressWarnings("unchecked") C columnKey = (C) entry.getKey(); return get(columnKey).equals(entry.getValue()); } } return false; } @Override public boolean remove(Object obj) { if (contains(obj)) { Entry entry = (Entry) obj; removeColumn(entry.getKey()); return true; } return false; } @Override public boolean removeAll(Collection c) { /* * We can't inherit the normal implementation (which calls * Sets.removeAllImpl(Set, *Collection*) because, under some * circumstances, it attempts to call columnKeySet().iterator().remove, * which is unsupported. */ checkNotNull(c); return Sets.removeAllImpl(this, c.iterator()); } @Override public boolean retainAll(Collection c) { checkNotNull(c); boolean changed = false; for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) { if (!c.contains(Maps.immutableEntry(columnKey, column(columnKey)))) { removeColumn(columnKey); changed = true; } } return changed; } } private class ColumnMapValues extends Maps.Values> { ColumnMapValues() { super(StandardTable.ColumnMap.this); } @Override public boolean remove(Object obj) { for (Entry> entry : StandardTable.ColumnMap.this.entrySet()) { if (entry.getValue().equals(obj)) { removeColumn(entry.getKey()); return true; } } return false; } @Override public boolean removeAll(Collection c) { checkNotNull(c); boolean changed = false; for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) { if (c.contains(column(columnKey))) { removeColumn(columnKey); changed = true; } } return changed; } @Override public boolean retainAll(Collection c) { checkNotNull(c); boolean changed = false; for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) { if (!c.contains(column(columnKey))) { removeColumn(columnKey); changed = true; } } return changed; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy