diff --git a/build.metadata b/build.metadata new file mode 100644 index 0000000000..03503b19fc --- /dev/null +++ b/build.metadata @@ -0,0 +1,15 @@ +# Created by buildmetadata-maven-plugin 1.7.0 ( SHA: 6f444cae ) +build.artifactId=undertow-websockets-jsr +build.groupId=io.undertow +build.java.compiler=HotSpot 64-Bit Tiered Compilers +build.java.runtime.name=OpenJDK Runtime Environment +build.java.runtime.version=1.8.0_422-b05 +build.java.vendor=Red Hat, Inc. +build.java.vm=OpenJDK 64-Bit Server VM +build.maven.execution.cmdline=-Djavax.net.ssl.trustStore\=/home/aogburn/bin/builder/maven.truststore -Djavax.net.ssl.trustStorePassword\=rhmaven -s /home/aogburn/bin/builder/eap-build-settings.xml clean install -DskipTests +build.maven.version=3.9.6 +build.scmRevision.date=17.09.2024 +build.scmRevision.id=aaa36f6ad214aecd7d0d611cad582aa058f3a3e8 +build.scmRevision.url=scm\:git\://github.com/undertow-io/undertow.git/undertow-websockets-jsr +build.version=2.2.33.SP2-redhat-00001 +build.version.full=2.2.33.SP2-redhat-00001raaa36f6ad214aecd7d0d611cad582aa058f3a3e8 diff --git a/core/src/main/java/io/undertow/util/WeakCopyOnWriteMap.java b/core/src/main/java/io/undertow/util/WeakCopyOnWriteMap.java new file mode 100644 index 0000000000..c3c9f53dae --- /dev/null +++ b/core/src/main/java/io/undertow/util/WeakCopyOnWriteMap.java @@ -0,0 +1,170 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * 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 io.undertow.util; + +import java.util.Collection; +import java.util.Collections; +import java.util.WeakHashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +/** + * A basic copy on write map. It simply delegates to an underlying map, that is swapped out + * every time the map is updated. + * + * Note: this is not a secure map. It should not be used in situations where the map is populated + * from user input. + * + * @author Stuart Douglas + */ +public class WeakCopyOnWriteMap implements ConcurrentMap { + + private volatile Map delegate = Collections.emptyMap(); + + public WeakCopyOnWriteMap() { + } + + public WeakCopyOnWriteMap(Map existing) { + this.delegate = new WeakHashMap<>(existing); + } + + @Override + public synchronized V putIfAbsent(K key, V value) { + final Map delegate = this.delegate; + V existing = delegate.get(key); + if(existing != null) { + return existing; + } + putInternal(key, value); + return null; + } + + @Override + public synchronized boolean remove(Object key, Object value) { + final Map delegate = this.delegate; + V existing = delegate.get(key); + if(existing.equals(value)) { + removeInternal(key); + return true; + } + return false; + } + + @Override + public synchronized boolean replace(K key, V oldValue, V newValue) { + final Map delegate = this.delegate; + V existing = delegate.get(key); + if(existing.equals(oldValue)) { + putInternal(key, newValue); + return true; + } + return false; + } + + @Override + public synchronized V replace(K key, V value) { + final Map delegate = this.delegate; + V existing = delegate.get(key); + if(existing != null) { + putInternal(key, value); + return existing; + } + return null; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return delegate.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate.containsValue(value); + } + + @Override + public V get(Object key) { + return delegate.get(key); + } + + @Override + public synchronized V put(K key, V value) { + return putInternal(key, value); + } + + @Override + public synchronized V remove(Object key) { + return removeInternal(key); + } + + @Override + public synchronized void putAll(Map m) { + final Map delegate = new WeakHashMap<>(this.delegate); + for(Entry e : m.entrySet()) { + delegate.put(e.getKey(), e.getValue()); + } + this.delegate = delegate; + } + + @Override + public synchronized void clear() { + delegate = Collections.emptyMap(); + } + + @Override + public Set keySet() { + return delegate.keySet(); + } + + @Override + public Collection values() { + return delegate.values(); + } + + @Override + public Set> entrySet() { + return delegate.entrySet(); + } + + //must be called under lock + private V putInternal(final K key, final V value) { + final Map delegate = new WeakHashMap<>(this.delegate); + V existing = delegate.put(key, value); + this.delegate = delegate; + return existing; + } + + public V removeInternal(final Object key) { + final Map delegate = new WeakHashMap<>(this.delegate); + V existing = delegate.remove(key); + this.delegate = delegate; + return existing; + } +} diff --git a/websockets-jsr/src/main/java/io/undertow/websockets/jsr/ServerWebSocketContainer.java b/websockets-jsr/src/main/java/io/undertow/websockets/jsr/ServerWebSocketContainer.java index 7bc1e4d273..03412db047 100644 --- a/websockets-jsr/src/main/java/io/undertow/websockets/jsr/ServerWebSocketContainer.java +++ b/websockets-jsr/src/main/java/io/undertow/websockets/jsr/ServerWebSocketContainer.java @@ -28,7 +28,7 @@ import io.undertow.servlet.util.ConstructorInstanceFactory; import io.undertow.servlet.util.ImmediateInstanceHandle; import io.undertow.servlet.websockets.ServletWebSocketHttpExchange; -import io.undertow.util.CopyOnWriteMap; +import io.undertow.util.WeakCopyOnWriteMap; import io.undertow.util.PathTemplate; import io.undertow.util.StatusCodes; import io.undertow.websockets.WebSocketExtension; @@ -104,7 +104,7 @@ public class ServerWebSocketContainer implements ServerContainer, Closeable { private final ClassIntrospecter classIntrospecter; - private final Map, ConfiguredClientEndpoint> clientEndpoints = new CopyOnWriteMap<>(); + private final Map, ConfiguredClientEndpoint> clientEndpoints = new WeakCopyOnWriteMap<>(); private final List configuredServerEndpoints = new ArrayList<>(); private final Set> annotatedEndpointClasses = new HashSet<>();