/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * 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 com.hazelcast.client.spi.impl.listener; import com.hazelcast.client.connection.nio.ClientConnection; import com.hazelcast.client.impl.HazelcastClientInstanceImpl; import com.hazelcast.client.impl.protocol.ClientMessage; import com.hazelcast.client.spi.ClientListenerService; import com.hazelcast.client.spi.EventHandler; import com.hazelcast.client.spi.impl.ClientExecutionServiceImpl; import com.hazelcast.internal.metrics.MetricsProvider; import com.hazelcast.internal.metrics.MetricsRegistry; import com.hazelcast.internal.metrics.Probe; import com.hazelcast.logging.ILogger; import com.hazelcast.nio.Connection; import com.hazelcast.spi.serialization.SerializationService; import com.hazelcast.util.executor.SingleExecutorThreadFactory; import com.hazelcast.util.executor.StripedExecutor; import com.hazelcast.util.executor.StripedRunnable; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import static com.hazelcast.internal.metrics.ProbeLevel.MANDATORY; public abstract class ClientListenerServiceImpl implements ClientListenerService, MetricsProvider { protected final HazelcastClientInstanceImpl client; protected final SerializationService serializationService; protected final ScheduledExecutorService registrationExecutor; protected final ILogger logger; @Probe(name = "eventHandlerCount", level = MANDATORY) private final ConcurrentMap<Long, EventHandler> eventHandlerMap = new ConcurrentHashMap<Long, EventHandler>(); private final StripedExecutor eventExecutor; public ClientListenerServiceImpl(HazelcastClientInstanceImpl client, int eventThreadCount, int eventQueueCapacity) { this.client = client; serializationService = client.getSerializationService(); logger = client.getLoggingService().getLogger(ClientListenerService.class); String name = client.getName(); eventExecutor = new StripedExecutor(logger, name + ".event", eventThreadCount, eventQueueCapacity); ClassLoader classLoader = client.getClientConfig().getClassLoader(); ThreadFactory threadFactory = new SingleExecutorThreadFactory(classLoader, name + ".eventRegistration-"); registrationExecutor = Executors.newSingleThreadScheduledExecutor(threadFactory); } @Override public void provideMetrics(MetricsRegistry registry) { registry.scanAndRegister(this, "listeners"); } @Probe(level = MANDATORY) private int eventQueueSize() { return eventExecutor.getWorkQueueSize(); } @Probe(level = MANDATORY) private long eventsProcessed() { return eventExecutor.processedCount(); } public void addEventHandler(long callId, EventHandler handler) { eventHandlerMap.put(callId, handler); } protected void removeEventHandler(long callId) { eventHandlerMap.remove(callId); } protected EventHandler getEventHandler(long callId) { return eventHandlerMap.get(callId); } public void handleClientMessage(ClientMessage clientMessage, Connection connection) { try { eventExecutor.execute(new ClientEventProcessor(clientMessage, (ClientConnection) connection)); } catch (RejectedExecutionException e) { logger.warning("Event clientMessage could not be handled", e); } } public void shutdown() { eventExecutor.shutdown(); ClientExecutionServiceImpl.shutdownExecutor("registrationExecutor", registrationExecutor, logger); } public void start() { } private final class ClientEventProcessor implements StripedRunnable { final ClientMessage clientMessage; final ClientConnection connection; private ClientEventProcessor(ClientMessage clientMessage, ClientConnection connection) { this.clientMessage = clientMessage; this.connection = connection; } @Override public void run() { try { long correlationId = clientMessage.getCorrelationId(); final EventHandler eventHandler = eventHandlerMap.get(correlationId); if (eventHandler == null) { logger.warning("No eventHandler for callId: " + correlationId + ", event: " + clientMessage + ", connection: " + connection); return; } eventHandler.handle(clientMessage); } finally { connection.decrementPendingPacketCount(); } } @Override public int getKey() { return clientMessage.getPartitionId(); } } //called from ee. public StripedExecutor getEventExecutor() { return eventExecutor; } //For Testing public abstract Collection<ClientEventRegistration> getActiveRegistrations(String uuid); }