org.glassfish.jersey.internal.util.collection.GuardianStringKeyMultivaluedMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxrs-ri Show documentation
Show all versions of jaxrs-ri Show documentation
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.
/*
* Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.jersey.internal.util.collection;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
/**
* The {@link MultivaluedMap} wrapper that is able to set guards observing changes of values represented by a key.
* @param The value type of the wrapped {@code MultivaluedMap}.
*
* @since 2.38
*/
public class GuardianStringKeyMultivaluedMap implements MultivaluedMap {
private final MultivaluedMap inner;
private final Map guards = new HashMap<>();
private static boolean isMutable(Object mutable) {
return !String.class.isInstance(mutable) && !MediaType.class.isInstance(mutable);
}
public GuardianStringKeyMultivaluedMap(MultivaluedMap inner) {
this.inner = inner;
}
@Override
public void putSingle(String key, V value) {
observe(key);
inner.putSingle(key, value);
}
@Override
public void add(String key, V value) {
observe(key);
inner.add(key, value);
}
@Override
public V getFirst(String key) {
V first = inner.getFirst(key);
if (isMutable(key)) {
observe(key);
}
return first;
}
@Override
public void addAll(String key, V... newValues) {
observe(key);
inner.addAll(key, newValues);
}
@Override
public void addAll(String key, List valueList) {
observe(key);
inner.addAll(key, valueList);
}
@Override
public void addFirst(String key, V value) {
observe(key);
inner.addFirst(key, value);
}
@Override
public boolean equalsIgnoreValueOrder(MultivaluedMap otherMap) {
return inner.equalsIgnoreValueOrder(otherMap);
}
@Override
public int size() {
return inner.size();
}
@Override
public boolean isEmpty() {
return inner.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return inner.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return inner.containsValue(value);
}
@Override
public List get(Object key) {
final List innerList = inner.get(key);
if (innerList != null) {
for (Map.Entry guard : guards.entrySet()) {
if (guard.getKey().equals(key)) {
return new GuardianList(innerList, guard);
}
}
}
return innerList;
}
@Override
public List put(String key, List value) {
observe(key);
return inner.put(key, value);
}
@Override
public List remove(Object key) {
if (key != null) {
observe(key.toString());
}
return inner.remove(key);
}
@Override
public void putAll(Map extends String, ? extends List> m) {
for (String key : m.keySet()) {
observe(key);
}
inner.putAll(m);
}
@Override
public void clear() {
observeAll();
inner.clear();
}
@Override
public Set keySet() {
return inner.keySet();
}
@Override
public Collection> values() {
observeAll();
return inner.values();
}
@Override
public Set>> entrySet() {
observeAll();
return inner.entrySet();
}
/**
* Observe changes of a value represented by the key.
* @param key the key values to observe
*/
public void setGuard(String key) {
guards.put(key, false);
}
/**
* Get all the guarded keys
* @return a {@link Set} of keys guarded.
*/
public Set getGuards() {
return guards.keySet();
}
/**
* Return true when the value represented by the key has changed. Resets any observation - the operation is not idempotent.
* @param key the Key observed.
* @return whether the value represented by the key has changed.
*/
public boolean isObservedAndReset(String key) {
Boolean observed = guards.get(key);
if (observed != null) {
guards.put(key, false);
}
return observed != null && observed;
}
private void observe(String key) {
for (Map.Entry guard : guards.entrySet()) {
if (guard.getKey().equals(key)) {
guard.setValue(true);
break;
}
}
}
private void observeAll() {
for (Map.Entry guard : guards.entrySet()) {
guard.setValue(true);
}
}
@Override
public String toString() {
return inner.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GuardianStringKeyMultivaluedMap> that = (GuardianStringKeyMultivaluedMap>) o;
return inner.equals(that.inner) && guards.equals(that.guards);
}
@Override
public int hashCode() {
return Objects.hash(inner, guards);
}
private static class MutableGuardian {
protected final Map.Entry guard;
private MutableGuardian(Entry guard) {
this.guard = guard;
}
protected V guardMutable(V mutable) {
if (isMutable(mutable)) {
guard.setValue(true);
}
return mutable;
}
}
private static class GuardianList extends MutableGuardian implements List {
private final List guarded;
public GuardianList(List guarded, Map.Entry guard) {
super(guard);
this.guarded = guarded;
}
@Override
public int size() {
return guarded.size();
}
@Override
public boolean isEmpty() {
return guarded.isEmpty();
}
@Override
public boolean contains(Object o) {
return guarded.contains(o);
}
@Override
public Iterator iterator() {
return new GuardianIterator<>(guarded.iterator(), guard);
}
@Override
public Object[] toArray() {
guard.setValue(true);
return guarded.toArray();
}
@Override
public T[] toArray(T[] a) {
guard.setValue(true);
return guarded.toArray(a);
}
@Override
public boolean add(V e) {
guard.setValue(true);
return guarded.add(e);
}
@Override
public boolean remove(Object o) {
guard.setValue(true);
return guarded.remove(o);
}
@Override
public boolean containsAll(Collection> c) {
return guarded.containsAll(c);
}
@Override
public boolean addAll(Collection extends V> c) {
guard.setValue(true);
return guarded.addAll(c);
}
@Override
public boolean addAll(int index, Collection extends V> c) {
guard.setValue(true);
return guarded.addAll(index, c);
}
@Override
public boolean removeAll(Collection> c) {
guard.setValue(true);
return guarded.removeAll(c);
}
@Override
public boolean retainAll(Collection> c) {
guard.setValue(true);
return guarded.retainAll(c);
}
@Override
public void clear() {
guard.setValue(true);
guarded.clear();
}
@Override
public V get(int index) {
return guardMutable(guarded.get(index));
}
@Override
public V set(int index, V element) {
guard.setValue(true);
return guarded.set(index, element);
}
@Override
public void add(int index, V element) {
guard.setValue(true);
guarded.add(index, element);
}
@Override
public V remove(int index) {
guard.setValue(true);
return guarded.remove(index);
}
@Override
public int indexOf(Object o) {
return guarded.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return guarded.lastIndexOf(o);
}
@Override
public ListIterator listIterator() {
return new GuardianListIterator<>(guarded.listIterator(), guard);
}
@Override
public ListIterator listIterator(int index) {
return new GuardianListIterator<>(guarded.listIterator(index), guard);
}
@Override
public List subList(int fromIndex, int toIndex) {
final List sublist = guarded.subList(fromIndex, toIndex);
return sublist != null ? new GuardianList<>(sublist, guard) : sublist;
}
@Override
public String toString() {
return guarded.toString();
}
@Override
public boolean equals(Object obj) {
if (GuardianList.class.isInstance(obj)) {
return guarded.equals(((GuardianList) obj).guarded);
}
return guarded.equals(obj);
}
@Override
public int hashCode() {
return guarded.hashCode();
}
}
private static class GuardianIterator extends MutableGuardian implements Iterator {
protected final Iterator guarded;
public GuardianIterator(Iterator guarded, Map.Entry guard) {
super(guard);
this.guarded = guarded;
}
@Override
public boolean hasNext() {
return guarded.hasNext();
}
@Override
public V next() {
return guardMutable(guarded.next());
}
@Override
public void remove() {
guard.setValue(true);
guarded.remove();
}
@Override
public void forEachRemaining(Consumer super V> action) {
guarded.forEachRemaining(action);
}
@Override
public String toString() {
return guarded.toString();
}
}
private static class GuardianListIterator extends GuardianIterator implements ListIterator {
public GuardianListIterator(Iterator guarded, Entry guard) {
super(guarded, guard);
}
@Override
public boolean hasPrevious() {
return ((ListIterator) guarded).hasPrevious();
}
@Override
public V previous() {
return guardMutable(((ListIterator) guarded).previous());
}
@Override
public int nextIndex() {
return ((ListIterator) guarded).nextIndex();
}
@Override
public int previousIndex() {
return ((ListIterator) guarded).previousIndex();
}
@Override
public void set(V v) {
((ListIterator) guarded).set(v);
guard.setValue(true);
}
@Override
public void add(V v) {
((ListIterator) guarded).add(v);
guard.setValue(true);
}
}
}