View Javadoc

1   package cz.cuni.amis.pogamut.base.agent.utils;
2   
3   
4   import cz.cuni.amis.pogamut.base.agent.IAgent;
5   import cz.cuni.amis.pogamut.base.agent.state.WaitForAgentStateChange;
6   import cz.cuni.amis.pogamut.base.agent.state.level0.IAgentState;
7   import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateDown;
8   import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateGoingUp;
9   import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateUp;
10  import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
11  import cz.cuni.amis.utils.ExceptionToString;
12  import cz.cuni.amis.utils.NullCheck;
13  import java.util.logging.Level;
14  
15  public class AgentKeepAlive {
16  	
17  	private Object keepAliveMutex = new Object();
18  	
19  	private LogCategory log;
20  	
21  	private KeepAlive keepAlive = null;
22  	
23  	private boolean firstStart = false;
24  	
25  	private IAgent agent;
26  	
27  	private boolean running = false;
28  	
29  	private long reconnectMillis;
30  
31  	public AgentKeepAlive(IAgent agent, long reconnectWaitMillis) {
32  		this.agent = agent;
33  		NullCheck.check(this.agent, "agent");
34  		this.log = agent.getLogger().getCategory(getClass().getSimpleName());
35  		NullCheck.check(this.log, "log initialization");
36  		this.reconnectMillis = reconnectWaitMillis;
37  	}
38  
39  	public void start() {
40  		synchronized(keepAliveMutex) {
41  			if (running) return;
42  			IAgentState state = agent.getState().getFlag();
43  			firstStart = true;
44  			keepAlive = new KeepAlive();
45  		}
46  	}
47  	
48  	public void stop() {
49  		synchronized(keepAliveMutex) {
50  			if (keepAlive != null) {
51  				keepAlive.stop();
52  				keepAlive = null;
53  			}
54  		}
55  	}
56  	
57  	public Long getNextRestart() {
58  		synchronized(keepAliveMutex) {
59  			if (!running) return null;
60  			return keepAlive.getNextRestart();
61  		}
62  	}
63  	
64  	public boolean isRunning() {
65  		return running;
66  	}
67  			
68  	private class KeepAlive implements Runnable {
69  		
70  		private Thread reconnectThread = null;
71  		
72  		private boolean shouldRun = true;
73  	
74  		private boolean shouldReconnect = true;
75  		
76  		private long sleepMillis = -1;
77  		
78  		public KeepAlive() {
79  			this.reconnectThread = new Thread(this, agent.getName() + " reconnector");
80  			this.reconnectThread.start();
81  		}
82  		
83  
84  		public void stop() {
85  			if (log.isLoggable(Level.WARNING)) log.warning("Stopping KeepAlive.");
86  			shouldReconnect = false;
87  			shouldRun = false;
88  			reconnectThread.interrupt();			
89  		}
90  		
91  		public Long getNextRestart() {
92  			synchronized(keepAliveMutex) {
93  				if (sleepMillis < 0) return null;
94  				return System.currentTimeMillis() - sleepMillis - reconnectMillis;
95  			}
96  		}
97  
98  		@Override
99  		public void run() {
100 			Boolean result = null;
101 			while (shouldRun && !Thread.currentThread().isInterrupted()) {
102 				if (shouldReconnect) {			
103 					try {
104 						if (!firstStart) {
105 							synchronized(keepAliveMutex) {
106 								sleepMillis = System.currentTimeMillis();
107 							}
108 							if (log.isLoggable(Level.FINER)) log.finer("Next reconnect attempt in " + reconnectMillis + " ms.");
109 							Thread.sleep(reconnectMillis);
110 						}
111 						if (!shouldReconnect) break;
112 						try {
113 							IAgentState state = agent.getState().getFlag();
114 							if (state instanceof IAgentStateUp || state instanceof IAgentStateGoingUp) {
115 								shouldReconnect = false;
116 								continue;
117 							}
118 							if (firstStart) {
119 								if (log.isLoggable(Level.INFO)) log.info("Starting agent.");
120 								firstStart = false;
121 							} else {
122 								if (log.isLoggable(Level.INFO)) log.info("Restarting agent.");
123 							}
124 							
125 							agent.start();
126 							if (log.isLoggable(Level.INFO)) log.info("Agent started.");
127 						} catch (Exception e1) {
128 							if (!shouldReconnect) break;
129 							if (log.isLoggable(Level.INFO)) log.info("Agent did not start, killing agent (cleaning up).");
130 							try {														
131 								agent.kill();
132 							} catch (Exception e2) {
133 							}
134 						}
135 					} catch (Exception e) {
136 						if (!shouldReconnect) break;
137 						if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process("Unhandled exception, stopping " + AgentKeepAlive.this.getClass().getSimpleName() + ".", e));
138 						break;
139 					}	
140 				}
141 				// if we reach here - the agent is running
142 				try {
143 					new WaitForAgentStateChange(agent.getState(), IAgentStateDown.class).await();
144 				} catch (Exception e) {					
145 				}
146 				shouldReconnect = agent.getState().getFlag() instanceof IAgentStateDown;				
147 			}
148 			reconnectThread = null;
149 			synchronized(keepAliveMutex) {
150 				if (keepAlive == this) {
151 					running = false;
152 					keepAlive = null;
153 				}
154 			}
155 			if (log.isLoggable(Level.WARNING)) log.warning("Stopped.");
156 		}	
157 	}
158 	
159 }