/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.jgroups.protocols;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.jgroups.Address;
import org.jgroups.Event;
import org.jgroups.PhysicalAddress;
import org.jgroups.View;
import org.jgroups.annotations.Property;
import org.jgroups.conf.ClassConfigurator;
import org.jgroups.logging.LogFactory;
import org.jgroups.protocols.Discovery;
/**
* Discovery protocol that delegates to a {@link PingDao} implementation. The {@link PingDao} impl
* MUST call the static {@link #setPingDao(PingDao)} method when it is ready to handle calls. Until
* that time the DAO_PING protocol will behave as if there are no other visible members.
*
*/
public class DAO_PING extends Discovery {
static {
//Register the protocol with jGroups
ClassConfigurator.addProtocol((short) 600, DAO_PING.class);
}
private static volatile PingDao pingDao;
public static void setPingDao(PingDao pingDao) {
if (DAO_PING.pingDao != null) {
LogFactory.getLog(DAO_PING.class)
.warn(
"A PingDao was already set. "
+ DAO_PING.pingDao
+ " will be replaced with "
+ pingDao);
}
DAO_PING.pingDao = pingDao;
}
@Property(
description =
"Interval (in milliseconds) at which the own Address is written. 0 disables it."
)
protected long interval = 60000;
private Future<?> writer_future;
@Override
public boolean sendDiscoveryRequestsInParallel() {
return true;
}
@Override
public boolean isDynamic() {
return true;
}
public void start() throws Exception {
super.start();
if (interval > 0) {
writer_future =
timer.scheduleWithFixedDelay(
new WriterTask(), interval, interval, TimeUnit.MILLISECONDS);
}
}
public void stop() {
final Future<?> wf = writer_future;
if (wf != null) {
wf.cancel(false);
writer_future = null;
}
super.stop();
}
@Override
public void destroy() {
super.destroy();
pingDao = null;
}
@Override
public Collection<PhysicalAddress> fetchClusterMembers(String clusterName) {
//If no DAO has been set just return an empty list
if (pingDao == null) {
log.info("No PingDao set, returning empty set for current cluster members");
return Collections.emptyList();
}
//Get the current cluster members
final Map<Address, PhysicalAddress> existing_mbrs = pingDao.getAddresses(clusterName);
//Add our address to the store
getAndSavePhysicalAddress(clusterName);
//Return current members
return existing_mbrs.values();
}
public Object down(Event evt) {
final Object retval = super.down(evt);
if (evt.getType() == Event.VIEW_CHANGE) {
//Handle view changes to make sure the dao store is consistent
handleView((View) evt.getArg());
}
return retval;
}
protected void getAndSavePhysicalAddress(String clusterName) {
if (pingDao == null) {
log.info("No PingDao set, skiping save of physical address for cluster " + clusterName);
return;
}
PhysicalAddress physicalAddr =
(PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr));
pingDao.addAddress(clusterName, local_addr, physicalAddr);
}
protected void handleView(View view) {
if (pingDao == null) {
//If no dao is set yet ignore the view change.
log.info("No PingDao set, ignoring view change.");
return;
}
final Collection<Address> mbrs = view.getMembers();
final boolean is_coordinator = !mbrs.isEmpty() && mbrs.iterator().next().equals(local_addr);
if (is_coordinator) {
//Delete all member addresses other than those in the current view
pingDao.purgeOtherAddresses(group_addr, mbrs);
}
}
protected final class WriterTask implements Runnable {
public void run() {
getAndSavePhysicalAddress(group_addr);
}
}
}