/* Copyright (c) 2011 Danish Maritime Authority. * * 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 net.maritimecloud.internal.mms.client.broadcast; import static java.util.Objects.requireNonNull; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; import net.maritimecloud.internal.util.Coverage; import net.maritimecloud.internal.util.logging.Logger; import net.maritimecloud.net.BroadcastConsumer; import net.maritimecloud.net.BroadcastMessage; import net.maritimecloud.net.BroadcastSubscription; import net.maritimecloud.net.MessageHeader; import net.maritimecloud.util.Binary; /** * A set of 1 or more subscribers of a particular type. * * @author Kasper Nielsen */ class SubscriptionSet { /** The logger. */ static final Logger LOG = Logger.get(SubscriptionSet.class); /** The broadcast manager. */ final ClientBroadcastManager broadcastManager; /** The type of broadcast messages. */ final String broadcastType; /** A list of all listeners for the particular type. */ final CopyOnWriteArrayList<DefaultSubscription> listeners = new CopyOnWriteArrayList<>(); volatile Set<BroadcastDeserializer> deserializers = new HashSet<>(); SubscriptionSet(ClientBroadcastManager broadcastManager, String broadcastType) { this.broadcastManager = requireNonNull(broadcastManager); this.broadcastType = requireNonNull(broadcastType); } BroadcastSubscription newSubscription(BroadcastDeserializer bd, BroadcastConsumer<? extends BroadcastMessage> listener, Coverage coverage) { DefaultSubscription bs = new DefaultSubscription(bd, listener, coverage); listeners.add(bs); return bs; } void remove(DefaultSubscription s) { broadcastManager.subscribeLock.readLock().lock(); try { listeners.remove(s); } finally { broadcastManager.subscribeLock.readLock().unlock(); } } class DefaultSubscription implements BroadcastSubscription { /** The number of broadcast messages received. */ private final AtomicLong count = new AtomicLong(); /** A unique id of this subscription. */ private final Binary id = Binary.random(32); /** The listener. */ private final BroadcastConsumer<? extends BroadcastMessage> listener; final Coverage coverage; final BroadcastDeserializer bd; DefaultSubscription(BroadcastDeserializer bd, BroadcastConsumer<? extends BroadcastMessage> listener, Coverage coverage) { this.bd = requireNonNull(bd); this.listener = requireNonNull(listener); this.coverage = coverage; } /** {@inheritDoc} */ @Override public void cancel() { remove(this); } @SuppressWarnings({ "unchecked", "rawtypes" }) void deliver(MessageHeader broadcastHeader, BroadcastMessage message) { // Vi har et problem, hvis vi ikke sender et evt, broadcast area med... // Naar man broadcaster til et area har man ingen position med, Vi bliver sgu noedt til at sende et area // med. if (broadcastHeader.getSenderPosition() == null || coverage.isCovered(broadcastHeader.getSenderPosition())) { try { ((BroadcastConsumer) listener).onMessage(broadcastHeader, message); count.incrementAndGet(); } catch (Exception e) { // Never throw anything, we are invoked from a dispatcher thread LOG.error("Exception while handling an incoming broadcast message of type " + message.getClass(), e); } } } /** {@inheritDoc} */ @Override public Binary getId() { return id; } /** {@inheritDoc} */ @Override public long getNumberOfReceivedMessages() { return count.get(); } /** {@inheritDoc} */ @Override public String getBroadcastType() { return broadcastType; } } }