/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.host.controller;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.jboss.as.domain.controller.HostConnectionInfo;
import org.jboss.as.host.controller.mgmt.SlaveHostPinger;
/**
* @author Emanuel Muckenhuber
*/
public class DomainSlaveHostRegistrations {
// Keep entries for 1 week by default
private static final long TTL = TimeUnit.DAYS.toMillis(7);
private final Map<String, DomainHostConnection> registrations = new ConcurrentHashMap<>();
protected void registerHost(final String hostName, SlaveHostPinger pinger, String address) {
synchronized (this) {
DomainHostConnection registration = registrations.get(hostName);
final List<HostConnectionInfo.Event> events;
if (registration == null) {
events = new ArrayList<>();
} else {
events = registration.events;
}
events.add(HostConnectionInfo.Events.create(HostConnectionInfo.EventType.REGISTERED, address));
registration = new DomainHostConnection(hostName, pinger, address, events);
registrations.put(hostName, registration);
}
}
protected boolean unregisterHost(final String hostName, HostConnectionInfo.Event event) {
synchronized (this) {
DomainHostConnection registration = registrations.get(hostName);
final List<HostConnectionInfo.Event> events;
if (registration == null) {
return false;
} else {
events = registration.events;
}
events.add(event);
registration = new DomainHostConnection(hostName, events);
registrations.put(hostName, registration);
}
return true;
}
protected boolean contains(final String host) {
return registrations.containsKey(host);
}
protected Set<String> getHosts() {
return registrations.keySet();
}
protected DomainHostConnection getRegistration(final String hostName) {
return registrations.get(hostName);
}
protected void addEvent(String hostName, HostConnectionInfo.Event event) {
synchronized (this) {
DomainHostConnection registration = registrations.get(hostName);
if (registration == null) {
registration = new DomainHostConnection(hostName);
registrations.put(hostName, registration);
}
final List<HostConnectionInfo.Event> events = new ArrayList<>(registration.events);
events.add(event);
registration.events = events;
}
}
public void pruneExpired() {
evictEntries(EXPIRED);
}
public void pruneDisconnected() {
evictEntries(DISCONNECTED);
}
protected void evictEntries(EvictionPolicy policy) {
synchronized (this) {
final Iterator<DomainHostConnection> i = registrations.values().iterator();
while (i.hasNext()) {
final DomainHostConnection registration = i.next();
if (policy.evictEntry(registration)) {
i.remove();
}
}
}
}
abstract static class EvictionPolicy {
abstract boolean evictEntry(DomainHostConnection entry);
}
private static final EvictionPolicy EXPIRED = new EvictionPolicy() {
@Override
boolean evictEntry(DomainHostConnection entry) {
final long expired = System.currentTimeMillis() - TTL;
final List<HostConnectionInfo.Event> events = entry.events;
final List<HostConnectionInfo.Event> newEvents = new ArrayList<>();
for (final HostConnectionInfo.Event event : events) {
if (event.getTimestamp() >= expired) {
newEvents.add(event);
}
}
entry.events = newEvents;
if (! newEvents.isEmpty()) {
return false;
} else {
return ! entry.isConnected();
}
}
};
private static final EvictionPolicy DISCONNECTED = new EvictionPolicy() {
@Override
boolean evictEntry(DomainHostConnection entry) {
return ! entry.isConnected();
}
};
static class DomainHostConnection implements HostConnectionInfo, Comparable<HostConnectionInfo> {
private final String hostName;
private final String address;
private final SlaveHostPinger pinger;
private volatile boolean connected;
private volatile List<Event> events;
DomainHostConnection(String hostName) {
this(hostName, new ArrayList<Event>());
}
DomainHostConnection(String hostName, List<Event> events) {
this.hostName = hostName;
this.connected = false;
this.address = null;
this.pinger = null;
this.events = events;
}
DomainHostConnection(String hostName, SlaveHostPinger pinger, String address, List<Event> events) {
this.hostName = hostName;
this.pinger = pinger;
this.events = events;
this.address = address;
this.connected = true;
}
@Override
public String getHostName() {
return hostName;
}
@Override
public boolean isConnected() {
return connected;
}
@Override
public List<Event> getEvents() {
return events;
}
protected String getAddress() {
return address;
}
protected Long getRemoteConnectionId() {
if (pinger != null) {
return pinger.getRemoteConnectionID();
} else {
return null;
}
}
protected SlaveHostPinger getPinger() {
return pinger;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DomainHostConnection that = (DomainHostConnection) o;
if (!hostName.equals(that.hostName)) return false;
return true;
}
@Override
public int hashCode() {
return hostName.hashCode();
}
@Override
public int compareTo(HostConnectionInfo o) {
return hostName.compareTo(o.getHostName());
}
}
}