package com.tesora.dve.groupmanager; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.net.InetSocketAddress; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.tesora.dve.lockmanager.LockManager; import com.tesora.dve.locking.impl.CoordinationServices; import com.tesora.dve.membership.GroupMembershipListener; import com.tesora.dve.membership.GroupTopic; import com.tesora.dve.membership.MembershipView; import com.tesora.dve.singleton.Singletons; import org.apache.log4j.Logger; import com.tesora.dve.membership.GroupMembershipListener.MembershipEventType; import com.tesora.dve.locking.ClusterLock; import com.tesora.dve.locking.impl.ClusterLockManager; public class LocalhostCoordinationServices implements CoordinationServices { static Logger logger = Logger.getLogger(LocalhostCoordinationServices.class); static class Factory implements CoordinationServices.Factory { @Override public CoordinationServices newInstance() { return new LocalhostCoordinationServices(); } } public static final String TYPE = "localhost"; private Set<InetSocketAddress> members = Collections.newSetFromMap(new ConcurrentHashMap<InetSocketAddress, Boolean>()); private AtomicInteger memberId = new AtomicInteger(); private Set<GroupMembershipListener> membershipListeners = Collections.newSetFromMap(new ConcurrentHashMap<GroupMembershipListener, Boolean>()); private ConcurrentHashMap<String, LocalTopic<?>> topicMap = new ConcurrentHashMap<String, LocalTopic<?>>(); ClusterLockManager lockManager; InetSocketAddress thisMember; private ConcurrentMap<Integer, String> connectionMap = new ConcurrentHashMap<Integer, String>(); private AtomicInteger globalConnectionId = new AtomicInteger(); private ConcurrentMap<String, String> externalServicesMap = new ConcurrentHashMap<String, String>(); private final HashMap<String, String> globalVariables = new HashMap<String,String>(); public LocalhostCoordinationServices() { // thisMember = new InetSocketAddress(getClass().getSimpleName(),memberId.incrementAndGet()); thisMember = InetSocketAddress.createUnresolved(getClass().getSimpleName(),memberId.incrementAndGet()); if (logger.isInfoEnabled()) logger.info("Configuring group services " + getClass().getSimpleName() + "(" + thisMember + ")"); members.add(thisMember); lockManager = new ClusterLockManager(this); for (GroupMembershipListener l : membershipListeners) l.onMembershipEvent(MembershipEventType.MEMBER_ADDED, getMemberAddress()); // load the global vars somehow here } @Override public Lock getLock(Object obj) { return new ReentrantLock(); } public ClusterLockManager getLockManager(){ return lockManager; } @Override public ClusterLock getClusterLock(String name) { return lockManager.getClusterLock(name); } @SuppressWarnings("unchecked") @Override public <M> GroupTopic<M> getTopic(String name) { if (false == topicMap.containsKey(name)) topicMap.putIfAbsent(name, new LocalTopic<M>()); return (GroupTopic<M>) topicMap.get(name); } @Override public void addMembershipListener(GroupMembershipListener listener) { membershipListeners.add(listener); } @Override public void removeMembershipListener(GroupMembershipListener listener) { membershipListeners.remove(listener); } @Override public void shutdown() { globalVariables.clear(); members.remove(getMemberAddress()); for (GroupMembershipListener l : membershipListeners) l.onMembershipEvent(MembershipEventType.MEMBER_REMOVED, getMemberAddress()); //TODO: how should we handle this for distributed locks? -sgossard //rwLockMap.clear(); topicMap.clear(); } @Override public InetSocketAddress getMemberAddress() { return thisMember; } @Override public Collection<InetSocketAddress> getMembers() { return members; } public void reset() { members.clear(); membershipListeners.clear(); topicMap.clear(); } @Override public void registerWithGroup(Properties props) { Singletons.replace(LockManager.class, lockManager); } @Override public void unRegisterWithGroup() { } @Override public MembershipView getMembershipView(){ return SimpleMembershipView.buildView(this.getMemberAddress(), this.getMembers(), this.getMembers()); } @Override public void configureProperties(Properties props) { // if (!props.containsKey(GroupManager.HIBERNATE_CACHE_REGION_FACTORY_CLASS)) { // props.setProperty("hibernate.cache.use_second_level_cache", "true"); // props.setProperty(GroupManager.HIBERNATE_CACHE_REGION_FACTORY_CLASS, // EHCacheCacheConfigurator.TYPE1); // } } public ConcurrentMap<Integer, String> getConnectionMap() { return connectionMap; } @Override public int registerConnection(String string) { int connectionId = globalConnectionId.incrementAndGet(); connectionMap.put(connectionId, string); return connectionId; } @Override public void unRegisterConnection(int currentConnId) { getConnectionMap().remove(currentConnId); } @Override public boolean localMemberIsOldestMember() { return true; } public ConcurrentMap<String, String> getExternalServicesMap() { return externalServicesMap; } @Override public String registerExternalService(String name) { return getExternalServicesMap().putIfAbsent(name, getMemberAddress().getHostName()); } @Override public String getExternalServiceRegisteredAddress(String name) { return getExternalServicesMap().get(name); } @Override public void deregisterExternalService(String name) { getExternalServicesMap().remove(name); } static AtomicLong globalIdGenerator = new AtomicLong(); @Override public long getGloballyUniqueId(String domain) { return globalIdGenerator.incrementAndGet(); } @Override public synchronized String getGlobalVariable(String name) { return globalVariables.get(name); } @Override public synchronized void setGlobalVariable(String name, String value) { globalVariables.put(name, value); } }