/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.wicket.protocol.ws.api.registry; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.concurrent.ConcurrentMap; import org.apache.wicket.Application; import org.apache.wicket.MetaDataKey; import org.apache.wicket.protocol.ws.api.IWebSocketConnection; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.lang.Generics; /** * A registry that keeps all currently opened web socket connections in * maps in Application's meta data. * * @since 6.0 */ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRegistry { private static final MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>> KEY = new MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>>() { }; @Override public IWebSocketConnection getConnection(Application application, String sessionId, IKey key) { Args.notNull(application, "application"); Args.notNull(sessionId, "sessionId"); Args.notNull(key, "key"); IWebSocketConnection connection = null; ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY); if (connectionsBySession != null) { ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId); if (connectionsByPage != null) { connection = connectionsByPage.get(key); } } return connection; } @Override public Collection<IWebSocketConnection> getConnections(Application application, String sessionId) { Args.notNull(application, "application"); Args.notNull(sessionId, "sessionId"); Collection<IWebSocketConnection> connections = Collections.emptyList(); ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY); if (connectionsBySession != null) { ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId); if (connectionsByPage != null) { connections = connectionsByPage.values(); } } return connections; } /** * Returns a collection of currently active websockets. The connections might close at any time. * * @param application * The application * @return a collection of currently active websockets */ public Collection<IWebSocketConnection> getConnections(Application application) { Args.notNull(application, "application"); Collection<IWebSocketConnection> connections = new ArrayList<>(); ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY); if (connectionsBySession != null) { for (ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage : connectionsBySession.values()) { connections.addAll(connectionsByPage.values()); } } return connections; } @Override public void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection) { Args.notNull(application, "application"); Args.notNull(sessionId, "sessionId"); Args.notNull(key, "key"); ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY); if (connectionsBySession == null) { synchronized (KEY) { connectionsBySession = application.getMetaData(KEY); if (connectionsBySession == null) { connectionsBySession = Generics.newConcurrentHashMap(); application.setMetaData(KEY, connectionsBySession); } } } ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId); if (connectionsByPage == null && connection != null) { connectionsByPage = connectionsBySession.get(sessionId); if (connectionsByPage == null) { connectionsByPage = Generics.newConcurrentHashMap(); ConcurrentMap<IKey, IWebSocketConnection> old = connectionsBySession.putIfAbsent(sessionId, connectionsByPage); if (old != null) { connectionsByPage = old; } } } if (connection != null) { connectionsByPage.put(key, connection); } else if (connectionsByPage != null) { connectionsByPage.remove(key); if (connectionsByPage.isEmpty()) { connectionsBySession.remove(sessionId); } } } @Override public void removeConnection(Application application, String sessionId, IKey key) { setConnection(application, sessionId, key, null); } }