All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.cache.util.UniversalMembershipListenerAdapter Maven / Gradle / Ivy

The newest version!
/*
 * 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.cache.util;

import com.gemstone.gemfire.admin.AdminDistributedSystem;
import com.gemstone.gemfire.admin.SystemMembershipEvent;
import com.gemstone.gemfire.admin.SystemMembershipListener;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.internal.Assert;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;

import java.util.*;

/**
 * 

The UniversalMembershipListenerAdapter is a wrapper * for {@link com.gemstone.gemfire.admin.SystemMembershipListener} and * {@link BridgeMembershipListener}, providing a facade that makes both * appear to customer code as a single SystemMembershipListener * from the Admin API. This includes adapting * BridgeMembershipListener events to appear as events for the * SystemMembershipListener.

* *

UniversalMembershipListenerAdapter implements * SystemMembershipListener, exposing the callbacks in that * interface as methods to be overridden by the customer.

* *

An internal implementation of BridgeMembershipListener is * registered when this class is instantiated. This implementation creates a * {@link com.gemstone.gemfire.admin.SystemMembershipEvent} and calls the * corresponding SystemMembershipListener public methods on * UniversalMembershipListenerAdapter. To the customer code, the * BridgeMembershipEvents are wrapped to appear as * SystemMembershipEvents. In this way, both types of membership * events appear as SystemMembershipEvents, allowing customer * code written using the Admin API to continue working by changing the * listener implementation to simply extend this class.

* *

Any BridgeServer using the UniversalMembershipListenerAdapter * will receive notifications of system membership changes and bridge * membership changes through a single listener.

* *

Any bridge client using the UniversalMembershipListenerAdapter * would receive notifications of bridge server connection changes. If that * bridge client also creates a connection to the GemFire {@link * com.gemstone.gemfire.distributed.DistributedSystem}, then it will also * receive notifications of system membership changes.

* *

Subclasses of UniversalMembershipListenerAdapter may be * registered as a SystemMembershipListener using {@link * com.gemstone.gemfire.admin.AdminDistributedSystem#addMembershipListener}. * It is best, however, to register the listener using {@link * #registerMembershipListener} since this allows the adapter to prevent * duplicate events for members that are both a system member and a bridge * member.

* *

Simply constructing the UniversalMembershipListenerAdapter * results in the underlying BridgeMembershipListener also being * registered.

* *

The following code illustrates how a BridgeServer application would use * UniversalMembershipListenerAdapter. The code in this example * assumes that the class MyMembershipListenerImpl extends * UniversalMembershipListenerAdapter: *


 * public class MyMembershipListenerImpl extends UniversalMembershipListenerAdapter {
 *   public void memberCrashed(SystemMembershipEvent event) {
 *     // customer code
 *   }
 *   public void memberLeft(SystemMembershipEvent event) {
 *     // customer code
 *   }
 *   public void memberJoined(SystemMembershipEvent event) {
 *     // customer code
 *   }
 * }
 *
 * DistributedSystemConfig config = 
 *   AdminDistributedSystemFactory.defineDistributedSystem(myDS, null);
 * AdminDistributedSystem adminDS = 
 *   AdminDistributedSystemFactory.getDistributedSystem(config);
 * adminDS.connect();
 * MyMembershipListenerImpl myListener = new MyMembershipListenerImpl();
 * myListener.registerMembershipListener(adminDS);
 * 
* The callbacks on MyMembershipListenerImpl would then be * invoked for all SystemMembershipEvents and * BridgeMembershipEvents. The latter will appear to be * SystemMembershipEvents.

* *

Similarly, the following code illustrates how a bridge client application * would use UniversalMembershipListenerAdapter, where * MyMembershipListenerImpl is a subclass. Simply by constructing this subclass * of UniversalMembershipListenerAdapter it is registering itself * as a BridgeMembershipListener: *


 * new MyMembershipListenerImpl();
 * 
* A bridge client that also connects to the DistributedSystem * could register with theAdminDistributedSystem as shown * above.

* *

It is recommended that subclasses register with the * AdminDistributedSystem using {@link * #registerMembershipListener}, as this will prevent duplicate events for * members that are both bridge members and system members. If duplicate * events are acceptable, you may register subclasses using {@link * com.gemstone.gemfire.admin.AdminDistributedSystem#addMembershipListener * AdminDistributedSystem#addMembershipListener}.

* * @author Kirk Lund * @since 4.2.1 */ public abstract class UniversalMembershipListenerAdapter implements SystemMembershipListener { /** * Default number of historical events to track in order to avoid duplicate * events for members that are both bridge members and system members; * value is 100. */ public static final int DEFAULT_HISTORY_SIZE = 100; // private final Object[] eventHistory; // private final boolean[] eventJoined; // private boolean registered = false; protected final int historySize; protected final LinkedList eventHistory; // list of String memberIds protected final Map eventJoined; // key: memberId, value: Boolean // TODO: perhaps ctor should require AdminDistributedSystem as arg? /** Constructs an instance of UniversalMembershipListenerAdapter. */ public UniversalMembershipListenerAdapter() { this(DEFAULT_HISTORY_SIZE); } /** * Constructs an instance of UniversalMembershipListenerAdapter. * @param historySize number of historical events to track in order to avoid * duplicate events for members that are both bridge members and system * members; must a number between 10 and Integer.MAX_INT * @throws IllegalArgumentException if historySizde is less than 10 */ public UniversalMembershipListenerAdapter(int historySize) { if (historySize < 10) { throw new IllegalArgumentException(LocalizedStrings.UniversalMembershipListenerAdapter_ARGUMENT_HISTORYSIZE_MUST_BE_BETWEEN_10_AND_INTEGERMAX_INT_0.toLocalizedString(Integer.valueOf(historySize))); } this.historySize = historySize; this.eventHistory = new LinkedList(); this.eventJoined = new HashMap(); BridgeMembership.registerBridgeMembershipListener(this.bridgeMembershipListener); } /** * Registers this adapter with the AdminDistributedSystem. * Registering in this way allows the adapter to ensure that callbacks will * not be invoked twice for members that have a bridge connection and a * system connection. If you register with {@link * com.gemstone.gemfire.admin.AdminDistributedSystem#addMembershipListener} * then duplicate events may occur for members that are both bridge members * and system. */ public void registerMembershipListener(AdminDistributedSystem admin) { synchronized (this.eventHistory) { // this.registered = true; admin.addMembershipListener(this.systemMembershipListener); } } /** * Unregisters this adapter with the AdminDistributedSystem. * If registration is performed with {@link #registerMembershipListener} * then this method must be used to successfuly unregister the adapter. */ public void unregisterMembershipListener(AdminDistributedSystem admin) { synchronized (this.eventHistory) { // this.registered = false; admin.removeMembershipListener(this.systemMembershipListener); } unregisterBridgeMembershipListener(); } /** * Registers this adapter as a BridgeMembershipListener. * Registration is automatic when constructing this adapter, so this call * is no necessary unless it was previously unregistered by calling * {@link #unregisterBridgeMembershipListener}. */ public void registerBridgeMembershipListener() { BridgeMembership.registerBridgeMembershipListener(this.bridgeMembershipListener); } /** * Unregisters this adapter as a BridgeMembershipListener. * @see #registerBridgeMembershipListener */ public void unregisterBridgeMembershipListener() { BridgeMembership.unregisterBridgeMembershipListener(this.bridgeMembershipListener); } /** * Invoked when a member has joined the distributed system. Also invoked when * a client has connected to this process or when this process has connected * to a BridgeServer. */ public void memberJoined(SystemMembershipEvent event) {} /** * Invoked when a member has gracefully left the distributed system. Also * invoked when a client has gracefully disconnected from this process. * or when this process has gracefully disconnected from a * BridgeServer. */ public void memberLeft(SystemMembershipEvent event) {} /** * Invoked when a member has unexpectedly left the distributed system. Also * invoked when a client has unexpectedly disconnected from this process * or when this process has unexpectedly disconnected from a * BridgeServer. */ public void memberCrashed(SystemMembershipEvent event) {} /** Adapts BridgeMembershipEvent to look like a SystemMembershipEvent */ public static class AdaptedMembershipEvent implements SystemMembershipEvent { private final BridgeMembershipEvent event; protected AdaptedMembershipEvent(BridgeMembershipEvent event) { this.event = event; } /** * Returns true if the member is a bridge client to a BridgeServer hosted * by this process. Returns false if the member is a BridgeServer that this * process is connected to. */ public boolean isClient() { return event.isClient(); } public String getMemberId() { return event.getMemberId(); } public DistributedMember getDistributedMember() { return event.getMember(); } @Override public boolean equals(Object other) { if (other == this) return true; if (other == null) return false; if (!(other instanceof AdaptedMembershipEvent)) return false; final AdaptedMembershipEvent that = (AdaptedMembershipEvent) other; if (this.event != that.event && !(this.event != null && this.event.equals(that.event))) return false; return true; } @Override public int hashCode() { return this.event.hashCode(); } @Override public String toString() { final StringBuffer sb = new StringBuffer("[AdaptedMembershipEvent: "); sb.append(this.event); sb.append("]"); return sb.toString(); } } private final BridgeMembershipListener bridgeMembershipListener = new BridgeMembershipListener() { public void memberJoined(BridgeMembershipEvent event) { systemMembershipListener.memberJoined(new AdaptedMembershipEvent(event)); } public void memberLeft(BridgeMembershipEvent event) { systemMembershipListener.memberLeft(new AdaptedMembershipEvent(event)); } public void memberCrashed(BridgeMembershipEvent event) { systemMembershipListener.memberCrashed(new AdaptedMembershipEvent(event)); } }; protected final SystemMembershipListener systemMembershipListener = new SystemMembershipListener() { public void memberJoined(SystemMembershipEvent event) { if (!isDuplicate(event, true)) { UniversalMembershipListenerAdapter.this.memberJoined(event); } } public void memberLeft(SystemMembershipEvent event) { if (!isDuplicate(event, false)) { UniversalMembershipListenerAdapter.this.memberLeft(event); } } public void memberCrashed(SystemMembershipEvent event) { if (!isDuplicate(event, false)) { UniversalMembershipListenerAdapter.this.memberCrashed(event); } } protected boolean isDuplicate(SystemMembershipEvent event, boolean joined) { synchronized (eventHistory) { boolean duplicate = false; String memberId = event.getMemberId(); // find memberId in eventHistory... int indexOf = eventHistory.indexOf(memberId); if (indexOf > -1) { // found an event for this member if ((eventJoined.get(memberId)).booleanValue() == joined) { // we already recorded a matching event for this member duplicate = true; } else { // remove the event from history and map... will be re-inserted Assert.assertTrue(eventHistory.remove(memberId), "Failed to replace entry in eventHistory for " + memberId); Assert.assertTrue(eventJoined.remove(memberId) != null, "Failed to replace entry in eventJoined for " + memberId); } } if (!duplicate) { // add the event to the history and map if (eventHistory.size() == historySize) { // filled the eventHistory, so need to remove first entry eventHistory.removeFirst(); } eventHistory.addLast(memberId); // linked list eventJoined.put(memberId, Boolean.valueOf(joined)); // boolean map Assert.assertTrue(eventHistory.size() <= historySize, "Attempted to grow eventHistory beyond maximum of " + historySize); } return duplicate; } // sync } }; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy