Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2010-2015 Pivotal Software, 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.internal.cache.tier.sockets;
import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.SocketAddress;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.gemstone.gemfire.CancelException;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.Instantiator;
import com.gemstone.gemfire.InternalGemFireError;
import com.gemstone.gemfire.StatisticsFactory;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheEvent;
import com.gemstone.gemfire.cache.CacheException;
import com.gemstone.gemfire.cache.InterestRegistrationEvent;
import com.gemstone.gemfire.cache.InterestRegistrationListener;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionDestroyedException;
import com.gemstone.gemfire.cache.RegionExistsException;
import com.gemstone.gemfire.cache.UnsupportedVersionException;
import com.gemstone.gemfire.cache.client.internal.PoolImpl;
import com.gemstone.gemfire.cache.client.internal.PoolImpl.PoolTask;
import com.gemstone.gemfire.cache.query.CqException;
import com.gemstone.gemfire.cache.query.CqQuery;
import com.gemstone.gemfire.cache.query.Query;
import com.gemstone.gemfire.cache.query.internal.CqQueryImpl;
import com.gemstone.gemfire.cache.query.internal.CqService;
import com.gemstone.gemfire.cache.query.internal.DefaultQuery;
import com.gemstone.gemfire.cache.server.CacheServer;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.internal.DM;
import com.gemstone.gemfire.distributed.internal.DistributionConfig;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.distributed.internal.HighPriorityDistributionMessage;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.MessageWithReply;
import com.gemstone.gemfire.distributed.internal.ReplyMessage;
import com.gemstone.gemfire.distributed.internal.ReplyProcessor21;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.ClassLoadUtil;
import com.gemstone.gemfire.internal.DummyStatisticsFactory;
import com.gemstone.gemfire.internal.InternalDataSerializer;
import com.gemstone.gemfire.internal.InternalInstantiator;
import com.gemstone.gemfire.internal.SystemTimer;
import com.gemstone.gemfire.internal.cache.BridgeObserver;
import com.gemstone.gemfire.internal.cache.BridgeObserverHolder;
import com.gemstone.gemfire.internal.cache.BridgeRegionEventImpl;
import com.gemstone.gemfire.internal.cache.BridgeServerImpl;
import com.gemstone.gemfire.internal.cache.CacheClientStatus;
import com.gemstone.gemfire.internal.cache.CacheDistributionAdvisor;
import com.gemstone.gemfire.internal.cache.CachedDeserializable;
import com.gemstone.gemfire.internal.cache.Conflatable;
import com.gemstone.gemfire.internal.cache.DistributedRegion;
import com.gemstone.gemfire.internal.cache.EntryEventImpl;
import com.gemstone.gemfire.internal.cache.EnumListenerEvent;
import com.gemstone.gemfire.internal.cache.EventID;
import com.gemstone.gemfire.internal.cache.FilterProfile;
import com.gemstone.gemfire.internal.cache.EntryEventImpl.SerializedCacheValueImpl;
import com.gemstone.gemfire.internal.cache.FilterRoutingInfo.FilterInfo;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.InternalCacheEvent;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.internal.cache.RegionEventImpl;
import com.gemstone.gemfire.internal.cache.ha.HAContainerMap;
import com.gemstone.gemfire.internal.cache.ha.HAContainerRegion;
import com.gemstone.gemfire.internal.cache.ha.HAContainerWrapper;
import com.gemstone.gemfire.internal.cache.ha.HARegionQueue;
import com.gemstone.gemfire.internal.cache.ha.ThreadIdentifier;
import com.gemstone.gemfire.internal.cache.tier.Acceptor;
import com.gemstone.gemfire.internal.cache.tier.InterestType;
import com.gemstone.gemfire.internal.cache.tier.MessageType;
import com.gemstone.gemfire.internal.cache.versions.VersionTag;
import com.gemstone.gemfire.internal.concurrent.CFactory;
import com.gemstone.gemfire.internal.concurrent.CM;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.shared.UnsupportedGFXDVersionException;
import com.gemstone.gemfire.internal.shared.Version;
import com.gemstone.gemfire.security.AccessControl;
import com.gemstone.gemfire.security.AuthenticationFailedException;
import com.gemstone.gemfire.security.AuthenticationRequiredException;
/**
* Class CacheClientNotifier works on the server and manages
* client socket connections to clients requesting notification of updates and
* notifies them when updates occur.
*
* @author Barry Oglesby
*
* @since 3.2
*/
@SuppressWarnings({"synthetic-access", "deprecation"})
public class CacheClientNotifier
{
private static volatile CacheClientNotifier ccnSingleton;
/**
* Factory method to construct a CacheClientNotifier
* CacheClientNotifier instance.
*
* @param cache
* The GemFire Cache
* @param acceptorStats
* @param maximumMessageCount
* @param messageTimeToLive
* @param transactionTimeToLive - ttl for txstates for disconnected clients
* @param listener
* @param overflowAttributesList
* @return A CacheClientNotifier instance
*/
public static synchronized CacheClientNotifier getInstance(Cache cache,
CacheServerStats acceptorStats,
int maximumMessageCount, int messageTimeToLive,
int transactionTimeToLive,
ConnectionListener listener, List overflowAttributesList, boolean isGatewayReceiver)
{
if (ccnSingleton == null) {
ccnSingleton = new CacheClientNotifier(cache, acceptorStats, maximumMessageCount,
messageTimeToLive, transactionTimeToLive,
listener, overflowAttributesList, isGatewayReceiver);
}
// else {
// ccnSingleton.acceptorStats = acceptorStats;
// ccnSingleton.maximumMessageCount = maximumMessageCount;
// ccnSingleton.messageTimeToLive = messageTimeToLive;
// ccnSingleton._connectionListener = listener;
// ccnSingleton.setCache((GemFireCache)cache);
// }
return ccnSingleton;
}
public static CacheClientNotifier getInstance(){
return ccnSingleton;
}
/** the amount of time in seconds to keep a disconnected client's txstates around */
private final int transactionTimeToLive;
/**
* Writes a given message to the output stream
*
* @param dos
* the DataOutputStream to use for writing the
* message
* @param type
* a byte representing the message type
* @param p_msg
* the message to be written; can be null
* @param clientVersion
*
*/
private void writeMessage(DataOutputStream dos, byte type, String p_msg, Version clientVersion )
throws IOException {
String msg = p_msg;
// write the message type
dos.writeByte(type);
// dummy epType
dos.writeByte(0x00);
// dummy qSize
dos.writeInt(0);
if (msg == null) {
msg = "";
}
dos.writeUTF(msg);
if (clientVersion != null
&& clientVersion.compareTo(Version.GFE_61) >= 0) {
// get all the instantiators.
Instantiator[] instantiators = InternalInstantiator.getInstantiators();
HashMap instantiatorMap = new HashMap();
if (instantiators != null && instantiators.length > 0) {
for (Instantiator instantiator : instantiators) {
ArrayList instantiatorAttributes = new ArrayList();
instantiatorAttributes.add(instantiator.getClass().toString()
.substring(6));
instantiatorAttributes.add(instantiator.getInstantiatedClass()
.toString().substring(6));
instantiatorMap.put(instantiator.getId(), instantiatorAttributes);
}
}
DataSerializer.writeHashMap(instantiatorMap, dos);
// get all the dataserializers.
DataSerializer[] dataSerializers = InternalDataSerializer
.getSerializers();
HashMap> dsToSupportedClasses = new HashMap>();
HashMap dataSerializersMap = new HashMap();
if (dataSerializers != null && dataSerializers.length > 0) {
for (DataSerializer dataSerializer : dataSerializers) {
dataSerializersMap.put(dataSerializer.getId(), dataSerializer
.getClass().toString().substring(6));
if (clientVersion.compareTo(Version.GFE_6516) >= 0) {
ArrayList supportedClassNames = new ArrayList();
for (Class clazz : dataSerializer.getSupportedClasses()) {
supportedClassNames.add(clazz.getName());
}
dsToSupportedClasses.put(dataSerializer.getId(), supportedClassNames);
}
}
}
DataSerializer.writeHashMap(dataSerializersMap, dos);
if (clientVersion.compareTo(Version.GFE_6516) >= 0) {
DataSerializer.writeHashMap(dsToSupportedClasses, dos);
}
}
dos.flush();
}
/**
* Writes an exception message to the socket
*
* @param dos
* the DataOutputStream to use for writing the
* message
* @param type
* a byte representing the exception type
* @param ex
* the exception to be written; should not be null
* @param clientVersion
*
*/
private void writeException(DataOutputStream dos, byte type, Exception ex, Version clientVersion)
throws IOException {
writeMessage(dos, type, ex.toString(), clientVersion);
}
// /**
// * Factory method to return the singleton CacheClientNotifier
// * instance.
// * @return the singleton CacheClientNotifier instance
// */
// public static CacheClientNotifier getInstance()
// {
// return _instance;
// }
// /**
// * Shuts down the singleton CacheClientNotifier instance.
// */
// public static void shutdownInstance()
// {
// if (_instance == null) return;
// _instance.shutdown();
// _instance = null;
// }
/**
* Registers a new client updater that wants to receive updates with this
* server.
*
* @param socket
* The socket over which the server communicates with the client.
*/
public void registerClient(Socket socket, boolean isPrimary, long acceptorId,
boolean notifyBySubscription)
throws IOException
{
// Since no remote ports were specified in the message, wait for them.
long startTime = this._statistics.startTime();
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
// Read the client version
short clientVersionOrdinal = Version.readOrdinal(dis);
Version clientVersion = null;
try {
clientVersion = Version.fromOrdinal(clientVersionOrdinal, true);
if (this._logger.fineEnabled()) {
this._logger.fine(this + ": Registering client with version: "
+ clientVersion);
}
}
catch (UnsupportedGFXDVersionException e) {
SocketAddress sa = socket.getRemoteSocketAddress();
UnsupportedVersionException uve;
if (sa != null) {
String sInfo = " Client: " + sa.toString() + ".";
uve = new UnsupportedVersionException(e.getMessage() + sInfo);
}
else {
uve = new UnsupportedVersionException(e.getMessage());
}
_logger
.warning(
LocalizedStrings.CacheClientNotifier_CACHECLIENTNOTIFIER_CAUGHT_EXCEPTION_ATTEMPTING_TO_CLIENT,
uve);
writeException(dos, Acceptor.UNSUCCESSFUL_SERVER_TO_CLIENT, uve, clientVersion);
return;
}
// Read and ignore the reply code. This is used on the client to server
// handshake.
dis.readByte(); // replyCode
if (Version.GFE_57.compareTo(clientVersion) <= 0) {
registerGFEClient(dis, dos, socket, isPrimary, startTime, clientVersion,
acceptorId, notifyBySubscription);
} else {
Exception e = new UnsupportedVersionException(clientVersionOrdinal);
throw new IOException(e.toString());
}
}
protected void registerGFEClient(DataInputStream dis, DataOutputStream dos,
Socket socket, boolean isPrimary, long startTime, Version clientVersion,
long acceptorId, boolean notifyBySubscription) throws IOException {
// Read the ports and throw them away. We no longer need them
int numberOfPorts = dis.readInt();
for (int i = 0; i < numberOfPorts; i++) {
dis.readInt();
}
// Read the handshake identifier and convert it to a string member id
ClientProxyMembershipID proxyID = null;
CacheClientProxy proxy;
AccessControl authzCallback = null;
byte clientConflation = HandShake.CONFLATION_DEFAULT;
try {
proxyID = ClientProxyMembershipID.readCanonicalized(dis);
if (getBlacklistedClient().contains(proxyID)) {
writeException(dos, HandShake.REPLY_INVALID, new Exception(
"This client is blacklisted by server"), clientVersion);
return;
}
proxy = getClientProxy(proxyID);
DistributedMember member = proxyID.getDistributedMember();
DistributedSystem system = this.getCache().getDistributedSystem();
Properties sysProps = system.getProperties();
String authenticator = sysProps
.getProperty(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME);
//TODO;hitesh for conflation
if (clientVersion.compareTo(Version.GFE_603) >= 0) {
byte[] overrides = HandShake.extractOverrides(new byte[] { (byte) dis.read() });
clientConflation = overrides[0];
} else {
clientConflation = (byte) dis.read();
}
switch (clientConflation) {
case HandShake.CONFLATION_DEFAULT:
case HandShake.CONFLATION_OFF:
case HandShake.CONFLATION_ON:
break;
default:
writeException(dos, HandShake.REPLY_INVALID,
new IllegalArgumentException("Invalid conflation byte"), clientVersion);
return;
}
//TODO:hitesh
Properties credentials = HandShake.readCredentials(dis, dos,
authenticator, system);
if (credentials != null) {
if (_securityLogger.fineEnabled()) {
_securityLogger
.fine("CacheClientNotifier: verifying credentials for proxyID: "
+ proxyID);
}
Principal principal = HandShake.verifyCredentials(authenticator,
credentials, system.getSecurityProperties(), this._logger.convertToLogWriter(),
this._securityLogger.convertToLogWriter(), member);
if (_securityLogger.fineEnabled()) {
_securityLogger
.fine("CacheClientNotifier: successfully verified credentials for proxyID: "
+ proxyID + " having principal: " + principal.getName());
}
String postAuthzFactoryName = sysProps
.getProperty(DistributionConfig.SECURITY_CLIENT_ACCESSOR_PP_NAME);
if (postAuthzFactoryName != null && postAuthzFactoryName.length() > 0) {
if (principal == null) {
if (_securityLogger.warningEnabled()) {
_securityLogger.warning(
LocalizedStrings.CacheClientNotifier_CACHECLIENTNOTIFIER_POST_PROCESS_AUTHORIZATION_CALLBACK_ENABLED_BUT_AUTHENTICATION_CALLBACK_0_RETURNED_WITH_NULL_CREDENTIALS_FOR_PROXYID_1,
new Object[] {DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME, proxyID});
}
}
Method authzMethod = ClassLoadUtil
.methodFromName(postAuthzFactoryName);
authzCallback = (AccessControl)authzMethod.invoke(null,
(Object[])null);
authzCallback.init(principal, member, this.getCache());
}
}
}
catch (ClassNotFoundException e) {
throw new IOException(LocalizedStrings.CacheClientNotifier_CLIENTPROXYMEMBERSHIPID_OBJECT_COULD_NOT_BE_CREATED_EXCEPTION_OCCURRED_WAS_0.toLocalizedString(e));
}
catch (AuthenticationRequiredException ex) {
if (_securityLogger.warningEnabled()) {
_securityLogger.warning(LocalizedStrings.CacheClientNotifier_AN_EXCEPTION_WAS_THROWN_FOR_CLIENT_0_1,
new Object[] {proxyID, ex});
}
writeException(dos, HandShake.REPLY_EXCEPTION_AUTHENTICATION_REQUIRED, ex, clientVersion);
return;
}
catch (AuthenticationFailedException ex) {
if (_securityLogger.warningEnabled()) {
_securityLogger.warning(
LocalizedStrings.CacheClientNotifier_AN_EXCEPTION_WAS_THROWN_FOR_CLIENT_0_1,
new Object[] {proxyID, ex});
}
writeException(dos, HandShake.REPLY_EXCEPTION_AUTHENTICATION_FAILED, ex, clientVersion);
return;
}
catch (Exception ex) {
if (_logger.warningEnabled()) {
_logger.warning(
LocalizedStrings.CacheClientNotifier_AN_EXCEPTION_WAS_THROWN_FOR_CLIENT_0_1,
new Object[] {proxyID, ""}, ex);
}
writeException(dos, Acceptor.UNSUCCESSFUL_SERVER_TO_CLIENT, ex, clientVersion);
return;
}
try {
proxy = registerClient(socket, proxyID, proxy, isPrimary, clientConflation,
clientVersion, acceptorId, notifyBySubscription);
}
catch (CacheException e) {
if(this._logger.warningEnabled()) {
this._logger.warning(LocalizedStrings.CacheClientNotifier_0_REGISTERCLIENT_EXCEPTION_ENCOUNTERED_IN_REGISTRATION_1, new Object[] {this, e}, e);
}
IOException io = new IOException(LocalizedStrings.CacheClientNotifier_EXCEPTION_OCCURRED_WHILE_TRYING_TO_REGISTER_INTEREST_DUE_TO_0.toLocalizedString(e.getMessage()));
io.initCause(e);
throw io;
}
if (authzCallback != null && proxy != null) {
proxy.setPostAuthzCallback(authzCallback);
}
this._statistics.endClientRegistration(startTime);
}
/**
* Registers a new client that wants to receive updates with this server.
*
* @param socket
* The socket over which the server communicates with the
* client.
* @param proxyId
* The distributed member id of the client being registered
* @param proxy
* The CacheClientProxy of the given
* proxyId
*
* @return CacheClientProxy for the registered client
*/
private CacheClientProxy registerClient(Socket socket,
ClientProxyMembershipID proxyId, CacheClientProxy proxy,
boolean isPrimary, byte clientConflation, Version clientVersion,
long acceptorId, boolean notifyBySubscription) throws IOException, CacheException {
CacheClientProxy l_proxy = proxy;
// Initialize the socket
socket.setTcpNoDelay(true);
socket.setSendBufferSize(CacheClientNotifier.socketBufferSize);
socket.setReceiveBufferSize(CacheClientNotifier.socketBufferSize);
if (_logger.fineEnabled()) {
_logger
.fine("CacheClientNotifier: Initialized server-to-client socket with send buffer size: "
+ socket.getSendBufferSize()
+ " bytes and receive buffer size: "
+ socket.getReceiveBufferSize() + " bytes");
}
// Determine whether the client is durable or not.
byte responseByte = Acceptor.SUCCESSFUL_SERVER_TO_CLIENT;
String unsuccessfulMsg = null;
boolean successful = true;
boolean clientIsDurable = proxyId.isDurable();
if (_logger.fineEnabled()) {
_logger.fine("CacheClientNotifier: Attempting to register "
+ (clientIsDurable ? "durable client: " + proxyId.getDurableId()
: "non-durable client"));
}
if (clientIsDurable) {
if (l_proxy == null) {
// No proxy exists for this durable client. It must be created.
if (_logger.fineEnabled()) {
_logger.fine("CacheClientNotifier: No proxy exists for durable client with id "
+ proxyId.getDurableId() + ". It must be created.");
}
l_proxy = new CacheClientProxy(this, socket, proxyId,
isPrimary, clientConflation, clientVersion, acceptorId, notifyBySubscription);
successful = this.initializeProxy(l_proxy);
} else {
// A proxy exists for this durable client. It must be reinitialized.
if (l_proxy.isPaused()) {
if (CacheClientProxy.testHook != null) {
CacheClientProxy.testHook.doTestHook("CLIENT_PRE_RECONNECT");
}
if (l_proxy.lockDrain()) {
try {
if (_logger.fineEnabled()) {
_logger.fine("CacheClientNotifier: A proxy exists for durable client with id "
+ proxyId.getDurableId() + ". This proxy will be reinitialized: " + l_proxy);
}
this._statistics.incDurableReconnectionCount();
l_proxy.getProxyID().updateDurableTimeout(proxyId.getDurableTimeout());
l_proxy.reinitialize(socket, proxyId, this.getCache(), isPrimary,
clientConflation, clientVersion);
l_proxy.setMarkerEnqueued(true);
if (CacheClientProxy.testHook != null) {
CacheClientProxy.testHook.doTestHook("CLIENT_RECONNECTED");
}
}
finally {
l_proxy.unlockDrain();
}
}
else {
unsuccessfulMsg = LocalizedStrings.CacheClientNotifier_COULD_NOT_CONNECT_DUE_TO_CQ_BEING_DRAINED.toLocalizedString();
_logger.warning(LocalizedStrings.ONE_ARG, unsuccessfulMsg);
responseByte = HandShake.REPLY_REFUSED;
if (CacheClientProxy.testHook != null) {
CacheClientProxy.testHook.doTestHook("CLIENT_REJECTED_DUE_TO_CQ_BEING_DRAINED");
}
}
} else {
// The existing proxy is already running (which means that another
// client is already using this durable id.
unsuccessfulMsg = LocalizedStrings.CacheClientNotifier_CACHECLIENTNOTIFIER_THE_REQUESTED_DURABLE_CLIENT_HAS_THE_SAME_IDENTIFIER__0__AS_AN_EXISTING_DURABLE_CLIENT__1__DUPLICATE_DURABLE_CLIENTS_ARE_NOT_ALLOWED.toLocalizedString(new Object[] {proxyId.getDurableId(), proxy});
_logger.warning( LocalizedStrings.ONE_ARG, unsuccessfulMsg );
// Set the unsuccessful response byte.
responseByte = HandShake.REPLY_EXCEPTION_DUPLICATE_DURABLE_CLIENT;
}
}
} else {
CacheClientProxy staleClientProxy = this.getClientProxy(proxyId);
if (staleClientProxy != null) {
// A proxy exists for this non-durable client. It must be closed.
if (_logger.fineEnabled()) {
_logger
.fine("CacheClientNotifier: A proxy exists for this non-durable client. It must be closed.");
}
if (staleClientProxy.startRemoval()) {
staleClientProxy.waitRemoval();
}
else {
staleClientProxy.close(false, false); // do not check for queue, just close it
removeClientProxy(staleClientProxy); // remove old proxy from proxy set
}
} // non-null stale proxy
// Create the new proxy for this non-durable client
l_proxy = new CacheClientProxy(this, socket, proxyId,
isPrimary, clientConflation, clientVersion, acceptorId, notifyBySubscription);
successful = this.initializeProxy(l_proxy);
}
if (!successful){
l_proxy = null;
responseByte = HandShake.REPLY_REFUSED;
unsuccessfulMsg = LocalizedStrings.CacheClientNotifier_CACHECLIENTNOTIFIER_A_PREVIOUS_CONNECTION_ATTEMPT_FROM_THIS_CLIENT_IS_STILL_BEING_PROCESSED__0.toLocalizedString(new Object[] {proxyId});
}
// Tell the client that the proxy has been registered using the response
// byte. This byte will be read on the client by the CacheClientUpdater to
// determine whether the registration was successful. The times when
// registration is unsuccessful currently are if a duplicate durable client
// is attempted to be registered or authentication fails.
try {
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
socket.getOutputStream()));
// write the message type, message length and the error message (if any)
writeMessage(dos, responseByte, unsuccessfulMsg, clientVersion);
}
catch (IOException ioe) {// remove the added proxy if we get IOException.
if (l_proxy != null) {
boolean keepProxy = l_proxy.close(false, false); // do not check for queue, just close it
if (!keepProxy) {
removeClientProxy(l_proxy);
}
}
throw ioe;
}
if (_logger.fineEnabled() && unsuccessfulMsg != null) {
_logger.fine(unsuccessfulMsg);
}
// If the client is not durable, start its message processor
// Starting it here (instead of in the CacheClientProxy constructor)
// will ensure that the response byte is sent to the client before
// the marker message. If the client is durable, the message processor
// is not started until the clientReady message is received.
if (!clientIsDurable && l_proxy != null &&
responseByte == Acceptor.SUCCESSFUL_SERVER_TO_CLIENT) {
// The startOrResumeMessageDispatcher tests if the proxy is a primary.
// If this is a secondary proxy, the dispatcher is not started.
// The false parameter signifies that a marker message has not already been
// processed. This will generate and send one.
l_proxy.startOrResumeMessageDispatcher(false);
}
if (responseByte == Acceptor.SUCCESSFUL_SERVER_TO_CLIENT) {
if (_logger.fineEnabled()) {
_logger.fine("CacheClientNotifier: Successfully registered " + l_proxy);
}
} else {
if (_logger.warningEnabled()) {
_logger.warning(LocalizedStrings.CacheClientNotifier_CACHECLIENTNOTIFIER_UNSUCCESSFULLY_REGISTERED_CLIENT_WITH_IDENTIFIER__0, proxyId);
}
}
return l_proxy;
}
private boolean initializeProxy(CacheClientProxy l_proxy) throws IOException, CacheException {
boolean status = false;
if (!this.isProxyInInitializationMode(l_proxy)){
if (this._logger.fineEnabled()) {
this._logger.fine("Initializing proxy, proxy :" + l_proxy);
}
try {
// Add client proxy to initialization list. This has to be done before
// the queue is created so that events can be buffered here for delivery
// to the queue once it's initialized (bug #41681 and others)
addClientInitProxy(l_proxy);
l_proxy.initializeMessageDispatcher();
// Initialization success. Add to client proxy list.
addClientProxy(l_proxy);
return true;
} catch (RegionExistsException ree) {
if (this._logger.fineEnabled()) {
String name = (ree.getRegion() != null)?(ree.getRegion().getFullPath()):
"null region";
this._logger.fine("Found RegionExistsException while initializing proxy." +
" Region name :" + name);
}
// This will return false;
} finally {
removeClientInitProxy(l_proxy);
}
}
return status;
}
/**
* Makes Primary to this CacheClientProxy and start the dispatcher of the
* CacheClientProxy
*
* @param proxyId
* @param isClientReady Whether the marker has already been processed. This
* value helps determine whether to start the dispatcher.
*/
public void makePrimary(ClientProxyMembershipID proxyId, boolean isClientReady)
{
CacheClientProxy proxy = getClientProxy(proxyId);
if (proxy != null) {
proxy.setPrimary(true);
/* If the client represented by this proxy has:
* - already processed the marker message (meaning the client is failing
* over to this server as its primary)
* - is not durable (meaning the marker message is being processed
* automatically
*
* Then, start or resume the dispatcher. Otherwise, let the clientReady
* message start the dispatcher.
* See CacheClientProxy.startOrResumeMessageDispatcher
if (!proxy._messageDispatcher.isAlive()) {
proxy._messageDispatcher._messageQueue.setPrimary(true);
proxy._messageDispatcher.start();
}
*/
if (isClientReady || !proxy.isDurable()) {
if (_logger.fineEnabled()) {
_logger.fine("CacheClientNotifier: Notifying proxy to start dispatcher for: " + proxy);
}
proxy.startOrResumeMessageDispatcher(false);
}
} else {
throw new InternalGemFireError("No cache client proxy on this node for proxyId " + proxyId);
}
}
/**
* Adds or updates entry in the dispatched message map when client sends an ack.
*
* @param proxyId
* @param eid
* @return success
*/
public boolean processDispatchedMessage(ClientProxyMembershipID proxyId, EventID eid)
{
boolean success = false;
CacheClientProxy proxy = getClientProxy(proxyId);
if (proxy != null) {
HARegionQueue harq = proxy.getHARegionQueue();
harq.addDispatchedMessage(new ThreadIdentifier(eid.getMembershipID(),
eid.getThreadID()),
eid.getSequenceID());
success = true;
}
return success;
}
/**
* Sets keepalive on the proxy of the given membershipID
*
* @param membershipID
* Uniquely identifies the client pool
* @since 5.7
*/
public void setKeepAlive(ClientProxyMembershipID membershipID, boolean keepAlive)
{
if (_logger.fineEnabled())
_logger.fine("CacheClientNotifier: setKeepAlive client: " + membershipID);
CacheClientProxy proxy = getClientProxy(membershipID);
if (proxy != null) {
// Close the port if the proxy represents the client and contains the
// port)
// // If so, remove the port from the client's remote ports
// proxy.removePort(clientPort);
// Set the keepalive flag
proxy.setKeepAlive(keepAlive);
}
}
/**
* Unregisters an existing client from this server.
*
* @param memberId
* Uniquely identifies the client
*
*
*/
public void unregisterClient(ClientProxyMembershipID memberId, boolean normalShutdown)
{
if (_logger.fineEnabled()) {
_logger
.fine("CacheClientNotifier: Unregistering all clients with member id: "
+ memberId);
}
CacheClientProxy proxy = getClientProxy(memberId);
if (proxy != null) {
if (_logger.finerEnabled())
_logger.finer("CacheClientNotifier: Potential client: " + proxy);
// If the proxy's member id is the same as the input member id, add
// it to the set of dead proxies.
if (!proxy.startRemoval()) {
if (_logger.finerEnabled())
_logger.finer("CacheClientNotifier: Potential client: " + proxy
+ " matches " + memberId);
closeDeadProxies(Collections.singletonList(proxy), normalShutdown);
}
}
}
/**
* The client represented by the proxyId is ready to receive updates.
*
* @param proxyId
*/
public void readyForEvents(ClientProxyMembershipID proxyId)
{
CacheClientProxy proxy = getClientProxy(proxyId);
if (proxy == null) {
//@todo log a message
} else {
// False signifies that a marker message has not already been processed.
// Generate and send one.
proxy.startOrResumeMessageDispatcher(false);
}
}
private ClientUpdateMessageImpl constructClientMessage(InternalCacheEvent event){
ClientUpdateMessageImpl clientMessage = null;
EnumListenerEvent operation = event.getEventType();
try {
clientMessage = initializeMessage(operation, event);
} catch (Exception e) {
if (_logger.severeEnabled()) {
_logger.severe(
LocalizedStrings.CacheClientNotifier_CANNOT_NOTIFY_CLIENTS_TO_PERFORM_OPERATION_0_ON_EVENT_1,
new Object[] { operation, event}, e);
}
}
return clientMessage;
}
/**
* notify interested clients of the given cache event. The
* event should have routing information in it that determines
* which clients will receive the event.
*/
public static void notifyClients(InternalCacheEvent event) {
CacheClientNotifier instance = ccnSingleton;
if (instance != null) {
instance.singletonNotifyClients(event, null);
}
}
/**
* notify interested clients of the given cache event using the
* given update message. The
* event should have routing information in it that determines
* which clients will receive the event.
*/
public static void notifyClients(InternalCacheEvent event, ClientUpdateMessage cmsg) {
CacheClientNotifier instance = ccnSingleton;
if (instance != null) {
instance.singletonNotifyClients(event, cmsg);
}
}
private void singletonNotifyClients(InternalCacheEvent event, ClientUpdateMessage cmsg){
FilterInfo filterInfo = event.getLocalFilterInfo();
// if (_logger.fineEnabled()) {
// _logger.fine("Client dispatcher processing event " + event);
// }
FilterProfile regionProfile = ((LocalRegion)event.getRegion()).getFilterProfile();
if (filterInfo != null) {
// if the routing was made using an old profile we need to recompute it
if (_logger.finerEnabled()) {
_logger.finer("Event isOriginRemote=" + event.isOriginRemote());
}
}
if ((filterInfo == null ||
(filterInfo.getCQs() == null &&
filterInfo.getInterestedClients() == null &&
filterInfo.getInterestedClientsInv() == null))) {
return;
}
long startTime = this._statistics.startTime();
ClientUpdateMessageImpl clientMessage;
if (cmsg == null) {
clientMessage = constructClientMessage(event);
} else {
clientMessage = (ClientUpdateMessageImpl)cmsg;
}
if (clientMessage == null){
return;
}
// Holds the clientIds to which filter message needs to be sent.
Set filterClients = new HashSet();
// Add CQ info.
if (filterInfo.getCQs() != null) {
for (Map.Entry e: filterInfo.getCQs().entrySet()) {
Long cqID = e.getKey();
String cqName = regionProfile.getRealCqID(cqID);
if (cqName == null){
continue;
}
CqQueryImpl cq = (CqQueryImpl)regionProfile.getCq(cqName);
if (cq != null){
ClientProxyMembershipID id = cq.getClientProxyId();
filterClients.add(id);
if (this._logger.fineEnabled()) {
this._logger.fine("Adding cq routing info to message for id: " + id + " and cq: " + cqName);
}
clientMessage.addClientCq(id, cq.getName(), e.getValue());
}
}
}
// Add interestList info.
if (filterInfo.getInterestedClientsInv() != null) {
Set