/* * Copyright to the original author or authors. * * 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. */ package org.rioproject.monitor.service.peer; import net.jini.config.Configuration; import net.jini.core.lookup.ServiceID; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceTemplate; import net.jini.discovery.DiscoveryManagement; import net.jini.lease.LeaseRenewalManager; import net.jini.lookup.LookupCache; import net.jini.lookup.ServiceDiscoveryEvent; import net.jini.lookup.ServiceDiscoveryManager; import net.jini.security.BasicProxyPreparer; import net.jini.security.ProxyPreparer; import org.rioproject.deploy.DeployAdmin; import org.rioproject.deploy.ServiceBeanInstance; import org.rioproject.deploy.ServiceProvisionListener; import org.rioproject.event.EventDescriptor; import org.rioproject.event.RemoteServiceEvent; import org.rioproject.event.RemoteServiceEventListener; import org.rioproject.impl.client.ServiceDiscoveryAdapter; import org.rioproject.impl.event.BasicEventConsumer; import org.rioproject.impl.fdh.FaultDetectionHandler; import org.rioproject.impl.fdh.FaultDetectionListener; import org.rioproject.impl.fdh.PooledFaultDetectionHandler; import org.rioproject.impl.system.ComputeResource; import org.rioproject.monitor.ProvisionMonitor; import org.rioproject.monitor.ProvisionMonitorEvent; import org.rioproject.monitor.service.*; import org.rioproject.monitor.service.channel.ServiceChannel; import org.rioproject.monitor.service.channel.ServiceChannelEvent; import org.rioproject.monitor.service.tasks.PeerNotificationTask; import org.rioproject.opstring.OperationalString; import org.rioproject.opstring.OperationalStringException; import org.rioproject.opstring.OperationalStringManager; import org.rioproject.opstring.ServiceElement; import org.rioproject.resolver.RemoteRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.rmi.RemoteException; import java.util.*; /** * Class that manages the discovery of other ProvisionMonitor instances, handles the registration and * notification of ProvisionMonitorEvent occurrences, and determines backup ProvisionMonitor capabilities */ public class ProvisionMonitorPeer extends ServiceDiscoveryAdapter implements RemoteServiceEventListener, FaultDetectionListener<ServiceID>, Runnable { private static Logger peerLogger = LoggerFactory.getLogger(ProvisionMonitorPeer.class.getName()); private static final String CONFIG_COMPONENT = "org.rioproject.monitor"; /** The PeerInfo object for this ProvisionMonitor */ private ProvisionMonitor.PeerInfo myPeerInfo; /** * The BasicEventConsumer providing notification of * ProvisionMonitorEvents */ private BasicEventConsumer eventConsumer; /** Table of Peer ProvisionMonitor instances to OpStringManagers which * are backups for the peer */ private final Map<ProvisionMonitor, List<OpStringManager>> opStringTable = new HashMap<ProvisionMonitor, List<OpStringManager>>(); /** The ProvisionMonitor instances this ProvisionMonitor is a backup for */ private final List<ProvisionMonitor> backupList = new ArrayList<ProvisionMonitor>(); /** The ProvisionMonitor that is our backup */ private ProvisionMonitor backup; /** Ordered set of ProvisionMonitor instances */ private final Set<ProvisionMonitor.PeerInfo> peerSet = new TreeSet<ProvisionMonitor.PeerInfo>(); /** Flag which indicates my backup is local, on the same machine */ private boolean localBackup = false; /** * Table of service IDs to FaultDetectionHandler instances, one for each service */ //private final Hashtable<ServiceID, FaultDetectionHandler> fdhTable = new Hashtable<ServiceID, FaultDetectionHandler>(); private final FaultDetectionHandler<ServiceID> faultDetectionHandler = new PooledFaultDetectionHandler(); /** ServiceTemplate for ProvisionMonitor discovery */ private ServiceTemplate template; /** DiscoveryManagement instance */ private DiscoveryManagement dm; /** ServiceDiscoveryManager for ProvisionMonitor instances */ private ServiceDiscoveryManager sdm; /** The LookupCache for the ServiceDiscoveryManager */ private LookupCache lCache; private ProxyPreparer peerProxyPreparer; private Configuration config; private ComputeResource computeResource; private ProvisionMonitor serviceProxy; private ProvisionMonitorEventProcessor eventProcessor; private OpStringManagerController opStringMangerController; public void initialize() throws Exception { if(config==null) throw new IllegalStateException("no configuration"); if(serviceProxy==null) throw new IllegalStateException("no serviceProxy"); if(dm==null) throw new IllegalStateException("no DiscoveryManagement"); if(eventProcessor==null) throw new IllegalStateException("no eventProcessor"); if(opStringMangerController==null) throw new IllegalStateException("no opStringMangerController"); peerProxyPreparer = (ProxyPreparer)config.getEntry(CONFIG_COMPONENT, "peerProxyPreparer", ProxyPreparer.class, new BasicProxyPreparer()); /* Create the PeerInfo object */ java.util.Random rand = new java.util.Random(System.currentTimeMillis()); long randomNumber = rand.nextLong(); myPeerInfo = new ProvisionMonitor.PeerInfo(getServiceProxy(), randomNumber, computeResource.getAddress().getHostAddress()); eventConsumer = new BasicEventConsumer(new EventDescriptor(ProvisionMonitorEvent.class, ProvisionMonitorEvent.ID), this, config); template = new ServiceTemplate(null, new Class[] {ProvisionMonitor.class}, null); new Thread(this).start(); } public void setOpStringMangerController(final OpStringManagerController opStringMangerController) { this.opStringMangerController = opStringMangerController; } public void setEventProcessor(ProvisionMonitorEventProcessor eventProcessor) { this.eventProcessor = eventProcessor; } public void setDiscoveryManagement(final DiscoveryManagement dm) { this.dm = dm; } ProvisionMonitor getServiceProxy() { return serviceProxy; } public void setServiceProxy(final ProvisionMonitor serviceProxy) { this.serviceProxy = serviceProxy; } public void setConfig(final Configuration config) { this.config = config; } public void setComputeResource(final ComputeResource computeResource) { this.computeResource = computeResource; } /** * Terminate the ProvisionMonitorPeer, cleaning up listeners, etc... */ public void terminate() { faultDetectionHandler.terminate(); eventConsumer.deregister(this); eventConsumer.terminate(); if(sdm != null) sdm.terminate(); } /** * Be a backup for another ProvisionMonitor * * @param primary The ProvisionMonitor to be the backup for * @return True if added to the collection, false if not */ public boolean addAsBackupFor(final ProvisionMonitor primary) { boolean assigned; int listSize; synchronized(backupList) { assigned = backupList.add(primary); listSize = backupList.size(); } if(assigned) { ProvisionMonitor.PeerInfo peer = getPeerInfo(primary); ProvisionMonitor[] provisioners = getProvisionMonitorPeers(); /* if we dont know about the new primary, add it into the mix */ if(peer == null) { ProvisionMonitor[] adjustedProvisioners = new ProvisionMonitor[provisioners.length + 1]; if(provisioners.length > 0) System.arraycopy(provisioners, 0, adjustedProvisioners, 0, provisioners.length); adjustedProvisioners[provisioners.length] = primary; provisioners = adjustedProvisioners; } myPeerInfo.setBackupCount(listSize); new Thread(new PeerNotificationTask(provisioners, myPeerInfo)).start(); } return (assigned); } /** * Remove the ProvisionMonitor from the backup list * * @param primary The ProvisionMonitor to remove * @return True if removed from the collection, false if not */ public boolean removeAsBackupFor(final ProvisionMonitor primary) { boolean removed; int listSize; synchronized(backupList) { removed = backupList.remove(primary); listSize = backupList.size(); } if(removed) { myPeerInfo.setBackupCount(listSize); notifyPeers(myPeerInfo); } return (removed); } /** * Get the latest & greatest PeerInfo * * @return The PeerInfo */ public ProvisionMonitor.PeerInfo doGetPeerInfo() { synchronized(backupList) { int bCount = backupList.size(); myPeerInfo.setBackupCount(bCount); } return (myPeerInfo); } /** * Get all backups * * @return An array of PeerInfo objects, one for each backup */ public ProvisionMonitor.PeerInfo[] getBackupInfo() { List<ProvisionMonitor.PeerInfo> list = new ArrayList<ProvisionMonitor.PeerInfo>(); synchronized(peerSet) { for (ProvisionMonitor.PeerInfo aPeerSet : peerSet) { list.add(aPeerSet); } } return(list.toArray(new ProvisionMonitor.PeerInfo[list.size()])); } /** * Update the backup count for a ProvisionMonitor peer * * @param peer The PeerInfo */ public void peerUpdated(final ProvisionMonitor.PeerInfo peer) { if(peer == null) { peerLogger.debug("updatePeer(): Unknown ProvisionMonitor"); return; } synchronized(peerSet) { if(peerSet.remove(peer)) { peerSet.add(peer); } } peerLogger.debug("ProvisionMonitorPeer: ProvisionMonitor updated info : backup count={}, address={}, id={}, ", peer.getBackupCount(), peer.getAddress(), peer.getID().toString()); } /** * Add a ProvisionMonitor * * @param item The ServiceItem for the ProvisionMonitor * @return The PeerInfo object */ ProvisionMonitor.PeerInfo addProvisioner(final ServiceItem item) { ProvisionMonitor.PeerInfo peer = null; try { if(getServiceProxy().equals(item.service)) return (null); peer = ((ProvisionMonitor)item.service).getPeerInfo(); synchronized(peerSet) { peerSet.add(peer); } importOperationalStrings(((ProvisionMonitor)item.service)); eventConsumer.register(item); } catch(Exception e) { peerLogger.warn("Adding a ProvisionMonitor peer instance", e); } return (peer); } /** * Notification that a Provisioner has been discovered * * @param sdEvent The ServiceDiscoveryEvent */ public void serviceAdded(final ServiceDiscoveryEvent sdEvent) { ServiceItem item = sdEvent.getPostEventServiceItem(); /* prepare the newly discovered proxy */ try { item.service = peerProxyPreparer.prepareProxy(item.service); } catch (RemoteException e) { peerLogger.warn("Could not prepare peer proxy, not adding as peer", e); return; } /* Check if we already know about this guy. If so, just return */ ProvisionMonitor.PeerInfo peer = getPeerInfo((ProvisionMonitor)item.service); if(peer != null) return; /* Add the new provisioner to the set */ peer = addProvisioner(item); /* If peer is null, then we just discovered ourselves */ if(peer == null) return; /* * If we dont have a backup yet, use the newly discovered provisioner */ if(backup == null) { peerLogger.debug("No backup yet, try assignment"); if(doAssignment(peer)) peerLogger.debug("Now backup for ProvisionMonitor: address={}, id={}", peer.getAddress(), peer.getID().toString()); } else { /* * If our backup is a local backup (same machine), and the newly * added peer is not on the same machine, assign the new * provisioner as the backup */ //if(localBackup && // (!computeResource.getAddress().equals(peer.getAddress()))) { String resourceAddress = computeResource.getAddress().getHostAddress(); String resourceHostName = computeResource.getAddress().getHostName(); if(localBackup && !(resourceAddress.equals(peer.getAddress()) || resourceHostName.equals(peer.getAddress())) ) { ProvisionMonitor currentBackup = backup; if(doAssignment(peer)) { try { currentBackup.removeBackupFor(getServiceProxy()); } catch(Exception e) { peerLogger.warn("Adjusting backup instance away from local instance", e); } } } } faultDetectionHandler.monitor(item.service, item.serviceID); } /** * A ProvisionMonitor has failed */ public void serviceFailure(final Object service, final ServiceID serviceID) { /* Clean up the event consumer, dont explictly cancel the lease since * the remote peer may be unreachable, this could block on the * remote method invocation on the lease itself */ eventConsumer.deregister(serviceID, false); ProvisionMonitor primary = null; ProvisionMonitor provMon = (ProvisionMonitor)service; /* * Remove the ProvisionMonitor that left the network from the * peerSet */ ProvisionMonitor.PeerInfo info = getPeerInfo(provMon); if(info == null) { peerLogger.debug("serviceFailure: Unknown ProvisionMonitor"); return; } synchronized(peerSet) { if(peerSet.remove(info)) { peerLogger.debug("ProvisionMonitorPeer: Removed ProvisionMonitor at [{}]", info.getAddress()); } } /* * Check to see if the ProvisionMonitor that just left the network * is our back-up. If so, locate another ProvisionMonitor and set * that as the backup */ if(backup != null && backup.equals(provMon)) { peerLogger.debug("ProvisionMonitorPeer: Backup has left the network, locate another backup"); if(!assignBackup()) { backup = null; peerLogger.debug("ProvisionMonitorPeer: No backup located"); } } /* * Check to see if we're the back-up for the ProvisionMonitor that * just left the network. If we are the backup then remove the entry * for the backup list */ boolean removedBackup = false; int listSize = 0; synchronized(backupList) { int index = backupList.indexOf(provMon); if(index != -1) { removedBackup = true; primary = backupList.remove(index); listSize = backupList.size(); } } /* If we were a backup, notify all peers of our current backup count */ if(removedBackup) { myPeerInfo.setBackupCount(listSize); notifyPeers(myPeerInfo); } /* Get OpStringManagers which were backing up opstrings in the failed * ProvisionMonitor */ List<OpStringManager> opMgrList; synchronized(opStringTable) { opMgrList = opStringTable.remove(primary); } /* * If we have a list, then iterate through all OpStringManager * instances and set them active */ if(opMgrList != null) { peerLogger.trace("Number of OpStringManager instances that are back ups : {}", opMgrList.size()); for (OpStringManager opMgr : opMgrList) { opMgr.setActive(true); ProvisionMonitorEvent event = new ProvisionMonitorEvent(getServiceProxy(), ProvisionMonitorEvent.Action.OPSTRING_MGR_CHANGED, opMgr.doGetOperationalString()); eventProcessor.processEvent(event); peerLogger.debug("Set active for opstring : {}", opMgr.getName()); } } else { peerLogger.debug("No backup OpStringManagers for removed peer"); } } /** * Notify ProvisionMonitor peers of a change in PeerInfo * * @param info PeerInfo */ void notifyPeers(final ProvisionMonitor.PeerInfo info) { new Thread(new PeerNotificationTask(getProvisionMonitorPeers(), info)).start(); } /** * Assign a backup * * @return true is successful */ boolean assignBackup() { boolean assignedBackup = false; ProvisionMonitor.PeerInfo[] peers = getPeers(); if(peers.length > 0) { for (ProvisionMonitor.PeerInfo peer : peers) { String resourceAddress = computeResource.getAddress().getHostAddress(); String resourceHostName = computeResource.getAddress().getHostName(); if (resourceAddress.equals(peer.getAddress()) || resourceHostName.equals(peer.getAddress())) continue; if (doAssignment(peer)) { assignedBackup = true; localBackup = false; break; } } /* * If we dont have a backup yet, its because the peerList has * entries that are on the same machine as we are. If its the * latter case, use the local backup for now */ if(!assignedBackup) { if(doAssignment(peers[0])) { localBackup = true; assignedBackup = true; } } } return (assignedBackup); } /** * Assign the ProvisionMonitor described by the PeerInfo object as a * backup * * @param peer The PeerInfo for a ProvisionMonitor * * @return true if assignment succeeded */ boolean doAssignment(final ProvisionMonitor.PeerInfo peer) { boolean assigned = false; try { backup = peer.getService(); backup.assignBackupFor(getServiceProxy()); assigned = true; peerLogger.debug("ProvisionMonitor backup info: backup count={}, address={}, id={}", peer.getBackupCount(), peer.getAddress(), peer.getID().toString()); } catch(Exception e) { peerLogger.warn("Failed assigning ProvisionMonitor backup", e); } return (assigned); } /** * Get a snapshot of the PeerInfo collection * * @return An array of PeerInfo instances in sorted order. * A new array is allocated each time. If there are no PeerInfo objects, * a zero length array will be returned. */ ProvisionMonitor.PeerInfo[] getPeers() { ProvisionMonitor.PeerInfo[] peers; synchronized(peerSet) { peers = peerSet.toArray(new ProvisionMonitor.PeerInfo[peerSet.size()]); } return (peers); } /** * Get an array of ProvisionMonitor instances from the PeerInfo * collection * * @return An array of ProvisionMonitor instances * in sorted order. A new array is allocated each time. If there are no * PeerInfo objects, a zero length array will be returned. */ public ProvisionMonitor[] getProvisionMonitorPeers() { ProvisionMonitor.PeerInfo[] peers = getPeers(); ProvisionMonitor[] provisioners = new ProvisionMonitor[peers.length]; for(int i = 0; i < provisioners.length; i++) provisioners[i] = peers[i].getService(); return (provisioners); } /** * Get the PeerInfo object for a ProvisionMonitor * * @param monitor The ProvisionMonitor instance * @return The PeerInfo instance or null if not found */ ProvisionMonitor.PeerInfo getPeerInfo(final ProvisionMonitor monitor) { ProvisionMonitor.PeerInfo[] peers = getPeers(); ProvisionMonitor.PeerInfo peer = null; for (ProvisionMonitor.PeerInfo peer1 : peers) { if (peer1.getService().equals(monitor)) { peer = peer1; break; } } return (peer); } /** * @see org.rioproject.event.RemoteServiceEventListener#notify */ public void notify(final RemoteServiceEvent event) { try { Object eventSource = event.getSource(); if(!(eventSource instanceof ProvisionMonitor)) { peerLogger.debug("ProvisionMonitorPeer: unknown event source : {}", eventSource.getClass().getName()); return; } ProvisionMonitor remoteMonitor = (ProvisionMonitor)eventSource; String opStringName = null; OpStringManager opMgr; ProvisionMonitorEvent pme = (ProvisionMonitorEvent)event; OperationalString opString = pme.getOperationalString(); ServiceElement sElem = pme.getServiceElement(); ProvisionMonitorEvent.Action action = pme.getAction(); switch(action) { case SERVICE_ELEMENT_UPDATED: case SERVICE_BEAN_INCREMENTED: case SERVICE_BEAN_DECREMENTED: String sAction = action.toString(); if(sElem == null) { peerLogger.debug("ProvisionMonitorPeer: {} sElem is null", sAction); return; } opStringName = sElem.getOperationalStringName(); peerLogger.trace("ProvisionMonitorPeer: {}, opstring: {}", sAction, opStringName); opMgr = opStringMangerController.getOpStringManager(opStringName); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: {} opstring [{}] not found", sAction, opStringName); return; } try { opMgr.doUpdateServiceElement(sElem); } catch(Exception e) { peerLogger.warn("Updating OperationalStringManager's ServiceElement", e); } break; case SERVICE_ELEMENT_ADDED: if(sElem == null) { peerLogger.warn("ProvisionMonitorPeer: SERVICE_ELEMENT_ADDED sElem is null"); return; } opStringName = sElem.getOperationalStringName(); peerLogger.trace("ProvisionMonitorPeer: SERVICE_ELEMENT_ADDED, opstring: {}", opStringName); opMgr = opStringMangerController.getOpStringManager(opStringName); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_ELEMENT_ADDED opstring [{}] not found" ,opStringName); return; } try { opMgr.doAddServiceElement(sElem, null); } catch(Exception e) { peerLogger.warn("Adding ServiceElement to OperationalStringManager", e); } break; case SERVICE_ELEMENT_REMOVED: if(sElem == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_ELEMENT_REMOVED sElem is null"); return; } opStringName = sElem.getOperationalStringName(); peerLogger.trace("ProvisionMonitorPeer: SERVICE_ELEMENT_REMOVED, opstring: {}", opStringName); opMgr = opStringMangerController.getOpStringManager(opStringName); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_ELEMENT_REMOVED opstring [{}] not found", opStringName); return; } try { opMgr.doRemoveServiceElement(sElem, false); } catch(Exception e) { peerLogger.warn("Removing ServiceElement from OperationalStringManager", e); } break; case OPSTRING_DEPLOYED: if(opString == null) { peerLogger.warn("ProvisionMonitorPeer: OPSTRING_DEPLOYED opstring is null"); return; } DeployAdmin deployAdmin = (DeployAdmin)remoteMonitor.getAdmin(); opStringProcessor(opString, remoteMonitor, deployAdmin, pme.getRemoteRepositories()); peerLogger.trace("ProvisionMonitorPeer: OPSTRING_DEPLOYED, opstring: {}", opString.getName()); break; case OPSTRING_UNDEPLOYED: if(opString == null) { peerLogger.debug("ProvisionMonitorPeer: OPSTRING_UNDEPLOYED opstring is null"); return; } peerLogger.trace("ProvisionMonitorPeer: OPSTRING_UNDEPLOYED, opstring: {}", opString.getName()); opMgr = opStringMangerController.getOpStringManager(opString.getName()); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: OPSTRING_UNDEPLOYED for opstring [{}] not found", opString.getName()); return; } opMgr.setDeploymentStatus(OperationalString.UNDEPLOYED); opMgr.terminate(false); synchronized(opStringTable) { if(opStringTable.containsKey(remoteMonitor)) { List<OpStringManager> list = opStringTable.get(remoteMonitor); list.remove(opMgr); opStringTable.put(remoteMonitor, list); } } break; case OPSTRING_MGR_CHANGED: if(opString == null) { peerLogger.debug("ProvisionMonitorPeer: OPSTRING_MGR_CHANGED opstring is null"); return; } peerLogger.debug("ProvisionMonitorPeer: OPSTRING_MGR_CHANGED, opstring: {}", opString.getName()); opMgr = opStringMangerController.getOpStringManager(opString.getName()); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: OPSTRING_MGR_CHANGED opstring [{}] not found", opString.getName()); return; } synchronized(opStringTable) { List<OpStringManager> list; if(opStringTable.containsKey(remoteMonitor)) list = opStringTable.get(remoteMonitor); else list = new ArrayList<OpStringManager>(); if(!list.contains(opMgr)) { list.add(opMgr); opStringTable.put(remoteMonitor, list); peerLogger.debug("ProvisionMonitorPeer: Reset backup peer for [{}] to {}", opString.getName(), remoteMonitor.toString()); } else { peerLogger.debug("ProvisionMonitorPeer: Already a backup for [{}] to {}", opString.getName(), remoteMonitor.toString()); } } break; case OPSTRING_UPDATED: if(opString == null) { peerLogger.debug("ProvisionMonitorPeer: OPSTRING_UNDEPLOYED opstring is null"); return; } peerLogger.trace("ProvisionMonitorPeer: OPSTRING_UPDATED, opstring: {}", opString.getName()); opMgr = opStringMangerController.getOpStringManager(opString.getName()); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: OPSTRING_UPDATED for opstring [{}] not found", opString.getName()); return; } opMgr.doUpdateOperationalString(opString); break; case SERVICE_BEAN_INSTANCE_UPDATED: ServiceBeanInstance instance = pme.getServiceBeanInstance(); if(instance == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_BEAN_INSTANCE_UPDATED instance is null"); return; } opStringName = pme.getOperationalStringName(); peerLogger.trace("ProvisionMonitorPeer: SERVICE_BEAN_INSTANCE_UPDATED, opstring: {}", opStringName); opMgr = opStringMangerController.getOpStringManager(opStringName); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_BEAN_INSTANCE_UPDATED for opstring [{}] not found", opStringName); return; } try { opMgr.doUpdateServiceBeanInstance(instance); } catch(Exception e) { peerLogger.warn("Updating OperationalStringManager's ServiceBeanInstance", e); } break; case SERVICE_PROVISIONED: instance = pme.getServiceBeanInstance(); if(instance == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_PROVISIONED instance is null"); return; } opStringName = pme.getOperationalStringName(); peerLogger.trace("ProvisionMonitorPeer: SERVICE_PROVISIONED, opstring: {}", opStringName); opMgr = opStringMangerController.getOpStringManager(opStringName); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_PROVISIONED for opstring [{}] " + "OpStringManager not found", opStringName); return; } ServiceElementManager mgr = opMgr.getServiceElementManager(sElem); if(mgr==null) { peerLogger.debug("ProvisionMonitorPeer: SERVICE_PROVISIONED for " + "opstring [{}] ServiceElementManager not found", opStringName); return; } boolean isStarted = mgr.isStarted(); while(!isStarted) { try { Thread.sleep(1000); isStarted = mgr.isStarted(); } catch(InterruptedException ignore) { /* Ignore */ } } mgr.importServiceBeanInstance(instance); ServiceChannel channel = ServiceChannel.getInstance(); channel.broadcast(new ServiceChannelEvent(this, sElem, ServiceChannelEvent.Type.PROVISIONED)); break; case REDEPLOY_REQUEST: opMgr = opStringMangerController.getOpStringManager(pme.getOperationalStringName()); if(opMgr == null) { peerLogger.debug("ProvisionMonitorPeer: REDEPLOY_REQUEST opstring [{}] not found", opStringName); return; } Object[] parms = pme.getRedeploymentParms(); Date redeployDate = (Date)parms[0]; boolean clean = (Boolean) parms[1]; boolean sticky = (Boolean) parms[2]; ServiceProvisionListener listener = (ServiceProvisionListener)parms[3]; long delay = redeployDate.getTime() - System.currentTimeMillis(); if(delay <= 0) { peerLogger.debug("ProvisionMonitorPeer: REDEPLOY_REQUEST for opstring " + "[{}] startTime has already passed, scheduled " + "redeployment cancelled", opStringName); } else { opMgr.doScheduleRedeploymentTask(delay, pme.getServiceElement(), pme.getServiceBeanInstance(), clean, sticky, listener); } break; } } catch(Throwable t) { peerLogger.warn("ProvisionMonitorEvent notification", t); } } /** * Perform initial discovery in a thread */ public void run() { try { if(config == null) sdm = new ServiceDiscoveryManager(dm, new LeaseRenewalManager()); else sdm = new ServiceDiscoveryManager(dm, new LeaseRenewalManager(config), config); lCache = sdm.createLookupCache(template, null, this); faultDetectionHandler.setLookupCache(lCache); faultDetectionHandler.register(this); if(!assignBackup()) peerLogger.debug("ProvisionMonitorPeer: No backup"); } catch(Exception e) { peerLogger.warn("ProvisionMonitor discovery", e); } } /** * Import all OperationalString instances from a newly discovered * ProvisionMonitor that the ProvisionMonitor is managing * * @param peer The peer ProvisionMonitor service */ void importOperationalStrings(final ProvisionMonitor peer) { try { DeployAdmin peerDeployAdmin = (DeployAdmin)peer.getAdmin(); OperationalStringManager[] mgrs = peerDeployAdmin.getOperationalStringManagers(); if(mgrs == null || mgrs.length == 0) { return; } for (OperationalStringManager mgr : mgrs) { if (mgr.isManaging()) { opStringProcessor(mgr.getOperationalString(), peer, peerDeployAdmin, mgr.getRemoteRepositories()); } } } catch(Exception e) { peerLogger.warn("Importing OperationalStrings", e); } } /** * Recursive method to add an OperationalString * * @param opString The OperationalString to add * @param peer A peer ProvisionMonitor service * @param peerDeployAdmin The peer ProvisionMonitor DeployAdmin * @param repositories A collection of {@code RemoteRepository} instances to use for the resolution of artifacts */ void opStringProcessor(final OperationalString opString, final ProvisionMonitor peer, final DeployAdmin peerDeployAdmin, final RemoteRepository[] repositories) { try { addPeerOpString(opString, peer, peerDeployAdmin, repositories); OperationalString[] nested = opString.getNestedOperationalStrings(); for (OperationalString aNested : nested) opStringProcessor(aNested, peer, peerDeployAdmin, repositories); } catch(Exception e) { peerLogger.warn("Adding OperationalString [{}]", opString.getName(), e); } } /** * Adds an OperationalString * * @param opString OperationalString to add * @param peer A peer ProvisionMonitor service * @param peerDeployAdmin The peer ProvisionMonitor DeployAdmin * @param repositories A collection of {@code RemoteRepository} instances to use for the resolution of artifacts */ synchronized void addPeerOpString(final OperationalString opString, final ProvisionMonitor peer, final DeployAdmin peerDeployAdmin, final RemoteRepository[] repositories) { Map<String, Throwable> map = new HashMap<String, Throwable>(); try { boolean resolveConflict = false; if(!opStringMangerController.opStringExists(opString.getName())) { peerLogger.debug("Adding OpString [{}] from Peer {}", opString.getName(), peer.toString()); opStringMangerController.getDeploymentVerifier().verifyDeploymentRequest(new DeployRequest(opString, repositories)); OpStringManager opMgr = opStringMangerController.addOperationalString(opString, map, null, peerDeployAdmin, null); if(opMgr==null) { resolveConflict = true; } else { List<OpStringManager> list; synchronized(opStringTable) { if(opStringTable.containsKey(peer)) list = opStringTable.get(peer); else list = new ArrayList<OpStringManager>(); list.add(opMgr); opStringTable.put(peer, list); } } } else { resolveConflict = true; } if(resolveConflict) { peerLogger.debug("Resolve conflict for OperationalString [{}]", opString.getName()); OpStringManager localMgr = opStringMangerController.getOpStringManager(opString.getName()); if(localMgr.isActive()) { resolveConflict(opString, peer, peerDeployAdmin); } } } catch(Throwable t) { peerLogger.warn("Adding Peer OperationalStrings", t); } } /** * Resolve a conflicting Primary relationship * * @param opString The OperationalString caught in the middle * @param peer The ProvisionMonitor that is also managing * @param peerDeployAdmin The peer's DeployAdmin */ void resolveConflict(final OperationalString opString, final ProvisionMonitor peer, final DeployAdmin peerDeployAdmin) { boolean addAsBackup = false; OpStringManager localMgr = null; OperationalStringManager peerMgr; try { ProvisionMonitor.PeerInfo peerInfo = getPeerInfo(peer); peerLogger.debug("ProvisionMonitor at [{}] also has [{}] deployed", peerInfo.getAddress(), opString.getName()); localMgr = opStringMangerController.getOpStringManager(opString.getName()); peerMgr = peerDeployAdmin.getOperationalStringManager(opString.getName()); if(!peerMgr.isManaging()) { peerLogger.debug("ProvisionMonitor at [{}] is not managing [{}], no conflict observed", peerInfo.getAddress(), opString.getName()); } else { /* See who deployed the OperationalString first */ Date[] peerDates = peerMgr.getDeploymentDates(); Date[] localDates = localMgr.getDeploymentDates(); /* If its scheduled, the use PeerInfo */ if(peerDates.length==0 && localDates.length==0) { /* Use PeerInfo comparable, lower is preferred */ peerLogger.debug("No Peer or Local dates"); int result = myPeerInfo.compareTo(peerInfo); if(result<0) { peerLogger.debug("Set ProvisionMonitor at [{}] as backup for [{}]", peerInfo.getAddress(), opString.getName()); peerMgr.setManaging(false); } else { peerLogger.debug("Set Local as backup for [{}]", opString.getName()); localMgr.setManaging(false); addAsBackup = true; } } else { /* If our instance has deployed and the peer has not, * set the peer to be a backup */ if(peerDates.length==0 && localDates.length>0) { peerLogger.debug("No Peer deployment dates, set ProvisionMonitor at [{}] as backup for [{}]", peerInfo.getAddress(), opString.getName()); peerMgr.setManaging(false); } /* Conversely, if the peer has deployed and we have not, * set the local instance to be backup */ else if(peerDates.length>0 && localDates.length==0) { peerLogger.debug("No Local deployment dates, set Local as backup for [{}]", opString.getName()); localMgr.setManaging(false); addAsBackup = true; } else { /* Both have deployed, get the latest date from both * and compare */ Date lastPeerDate = peerDates[peerDates.length-1]; Date lastLocalDate = localDates[localDates.length-1]; /* Highly unlikely that the 2 Deployment times will * be exact, if they are, use the random number in * PeerInfo */ if(lastPeerDate.equals(lastLocalDate)) { /* Use PeerInfo comparable, lower is prefered */ peerLogger.debug("Last deployment dates are equal"); int result = myPeerInfo.compareTo(peerInfo); if(result<0) { peerLogger.debug("Local is preferred, set ProvisionMonitor at [{}] as backup for [{}]", peerInfo.getAddress(), opString.getName()); peerMgr.setManaging(false); } else { peerLogger.debug("Peer is preferred, set Local as backup for [{}]", opString.getName()); localMgr.setManaging(false); } } else { if(lastPeerDate.before(lastLocalDate)) { peerLogger.debug("Peer deployed before Local, set Local as backup for [{}]", opString.getName()); localMgr.setManaging(false); addAsBackup = true; } else { peerLogger.debug("Local deployed before Peer, set ProvisionMonitor at [{}] as backup for [{}]", peerInfo.getAddress(), opString.getName()); peerMgr.setManaging(false); } } } } } } catch(OperationalStringException e) { /* This should not happen, log the occurrence just the same */ peerLogger.warn("OperationalStringException trying to resolve OperationalStringManager supremacy", e); } catch(RemoteException e) { peerLogger.warn("RemoteException trying to resolve OperationalStringManager supremacy", e); } finally { if(addAsBackup) { /* Set the OperationalString to the OpStringManager */ localMgr.doUpdateOperationalString(opString); /* Add OpStringManager to list of managers providing backup */ List<OpStringManager> list; synchronized(opStringTable) { if(opStringTable.containsKey(peer)) list = opStringTable.get(peer); else list = new ArrayList<OpStringManager>(); list.add(localMgr); opStringTable.put(peer, list); } } } } } // End class ProvisionMonitorPeer