package com.yahoo.dtf.actions.protocol; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import com.yahoo.dtf.actions.Action; import com.yahoo.dtf.actions.http.HttpBase; import com.yahoo.dtf.actions.protocol.Lock; import com.yahoo.dtf.comm.Comm; import com.yahoo.dtf.comm.rpc.Node; import com.yahoo.dtf.DTFNode; import com.yahoo.dtf.exception.DTFException; import com.yahoo.dtf.state.ActionState; import com.yahoo.dtf.state.DTFState; /** * does the opposite of SetupAgent and releases this agent from being owned * by anyone, allowing it release any stale data or references. */ public class ReleaseAgent extends Action { public ReleaseAgent() { } public ReleaseAgent(Lock lock) { } public void execute() throws DTFException { getLogger().info("releasing this agent"); /* * Call all CleanUp hooks. */ for (int i = 0; i < _cleanupHooks.size(); i++) { _cleanupHooks.get(i).cleanup(); } /* * Catch uncleaned global context */ ActionState as = ActionState.getInstance(); DTFState mainState = as.getState(Node.BASE_CONFIG); Hashtable globalCtx = mainState.getGlobalContext(); Enumeration keys = globalCtx.keys(); StringBuffer contexts = new StringBuffer(); while (keys.hasMoreElements()) { String key = (String)keys.nextElement(); // only acceptable global ctx left behind. if (!key.equals(Node.ACTION_DTFX_THREADID)) contexts.append(key + ","); } if ( contexts.length() != 0 ) getLogger().warn("Unfreed global contexts [" + contexts + "]"); globalCtx.clear(); // now lets make sure there's only 2 state objects left, 1 from the main // thread and the other from this thread that is executing right now. Thread[] threads = new Thread[Thread.activeCount()]; int numThreads = Thread.enumerate(threads); HashMap<String,Thread> threadsLookup = new HashMap<String, Thread>(); for (int i = 0; i < numThreads; i++) { threadsLookup.put(threads[i].getName(), threads[i]); } Enumeration states = as.getStates(); contexts = new StringBuffer(); while (states.hasMoreElements()) { String key = (String) states.nextElement(); /* * Do not delete the state of this current thread, main or the agent * base config. */ if (!(key.equals("main") || key.equals(Thread.currentThread().getName()) || key.equals(Node.BASE_CONFIG))) { contexts.append(key + ","); as.delState(key); } } if ( contexts.length() != 0 ) getLogger().warn("Unfreed local contexts [" + contexts + "]"); /* * We release the connections because the older connections are not * being release because in the constructor of HttpOperation we * tell the API to not check for stale connections (this helps * performance but would then generate 1 single failure to connect * because of an old stale connection); */ HttpBase.releaseConnections(); /* * Throw away all of the currently exported references on the main state */ mainState.getReferences().clear(); /* * Throw away all of the currently exported functions on the main state */ mainState.getFunctions().clear(); // clean up rmi clients Comm.removeClient(DTFNode.getOwner().getId()); DTFNode.setOwner(null); getLogger().info("This agent is no longer in use by anyone."); } private static ArrayList<CleanUpHook> _cleanupHooks = new ArrayList<CleanUpHook>(); public static void addCleanUpHook(CleanUpHook cleanup) { _cleanupHooks.add(cleanup); } }