package com.tesora.dve.worker.agent; /* * #%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.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import com.tesora.dve.comms.client.messages.ResponseMessage; import com.tesora.dve.exceptions.PEException; public abstract class Agent { static AtomicLong agentId = new AtomicLong(0); protected long exceptionFrame = 0; protected String name; private static PluginProvider<?> provider; AgentPlugin plugin; private Set<Thread> shutdownHooks = new HashSet<Thread>(); protected Agent() {}; public Agent(String name) throws PEException { this.name = name + agentId.incrementAndGet(); initialize(); } protected void initialize() throws PEException { try { plugin = provider.newInstance(this); } catch (Exception e) { throw new PEException("Unable to instantiate new AgentPlugin", e); } } public static void setPluginProvider(PluginProvider<? extends AgentPlugin> pluginProvider) throws PEException { try { provider = pluginProvider; } catch (Exception e) { throw new PEException("Cannot find newInstance() method in AgentPlugin", e); } } public static void startServices(Properties props) throws PEException { try { provider.startServices(props); } catch (Exception e) { throw new PEException("Unable to start Agent services", e); } } public static void stopServices() throws PEException { try { if(provider != null) provider.stopServices(); } catch (Exception e) { throw new PEException("Unable to stop Agent services", e); } } /** * A static method for sending a message without instantiating an Agent * @param e Envelope with the message to send and destination address * @throws PEException */ public static void dispatch(String toAddress, Object message) throws PEException { try { provider.dispatch(toAddress,message); } catch (Exception e) { throw new PEException("Unable to dispatch envelope", e); } } public void close() throws PEException { plugin.close(); // We copy the list in case the hook removes itself List<Thread> hooksToRun = new ArrayList<Thread>(shutdownHooks); for (Thread shutdownHook : hooksToRun) { shutdownHook.run(); } } public String getReplyAddress() throws PEException { return plugin.getReplyAddress(); } public String getAddress() throws PEException { return plugin.getAddress(); } public void returnResponse(Envelope requestEnvelope, ResponseMessage resp) throws PEException { plugin.returnResponse(requestEnvelope, resp); } public ResponseMessage sendAndReceive(Envelope e) throws PEException { return plugin.sendAndReceive(e); } public void send(Envelope e) throws PEException { plugin.send(e); } public abstract void onMessage(Envelope e) throws PEException; public void onTimeout() { } /** * Utility method to return a random value between 0 and <code>size</code>-1. * * @param size upper bound on value to be returned * @return random value */ public static int getRandom(int size) { return (int) (Math.random()*size); } /** * Gets the name of the Agent. This would be the queue name for Agents such * as the WorkerManager, but is only for convenience and may not follow this * convention. * * @return the Agent's name */ public String getName() { return name; } @Override public String toString() { return getClass().getSimpleName()+"("+name+")"; } /** * Bumps the Agent's exception frame. The exception frame is used to silently consume messages * on the Send/Receive/Reply queue after and exception (i.e., outstanding messages from other * workers after one worker returns an exception). */ public void nextExceptionFrame() { ++exceptionFrame; } public long getExceptionFrame() { return exceptionFrame; } public Envelope newEnvelope(Object o) { return plugin.newEnvelope(o); } public void addShutdownHook(Thread shutdownHook) { this.shutdownHooks.add(shutdownHook); } public void removeShutdownHook(Thread shutdownHook) { this.shutdownHooks.remove(shutdownHook); } }