/opennms-ackd/src/main/java/org/opennms/netmgt/ackd/readers/DefaultAckReader.java

https://github.com/ajakubo1/opennms · Java · 319 lines · 164 code · 40 blank · 115 comment · 20 complexity · 1cf082c1b99ab7b634e15e8121824455 MD5 · raw file

  1. /*******************************************************************************
  2. * This file is part of OpenNMS(R).
  3. *
  4. * Copyright (C) 2010-2012 The OpenNMS Group, Inc.
  5. * OpenNMS(R) is Copyright (C) 1999-2012 The OpenNMS Group, Inc.
  6. *
  7. * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
  8. *
  9. * OpenNMS(R) is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published
  11. * by the Free Software Foundation, either version 3 of the License,
  12. * or (at your option) any later version.
  13. *
  14. * OpenNMS(R) is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with OpenNMS(R). If not, see:
  21. * http://www.gnu.org/licenses/
  22. *
  23. * For more information contact:
  24. * OpenNMS(R) Licensing <license@opennms.org>
  25. * http://www.opennms.org/
  26. * http://www.opennms.com/
  27. *******************************************************************************/
  28. package org.opennms.netmgt.ackd.readers;
  29. import java.util.concurrent.Future;
  30. import java.util.concurrent.ScheduledThreadPoolExecutor;
  31. import org.opennms.core.spring.BeanUtils;
  32. import org.opennms.netmgt.ackd.AckReader;
  33. import org.opennms.netmgt.dao.api.AckdConfigurationDao;
  34. import org.slf4j.Logger;
  35. import org.slf4j.LoggerFactory;
  36. import org.springframework.beans.factory.InitializingBean;
  37. import org.springframework.beans.factory.annotation.Autowired;
  38. import org.springframework.util.Assert;
  39. /**
  40. * Acknowledgment Reader implementation using Java Mail
  41. *
  42. * DONE: Identify acknowledgments for sent notifications
  43. * DONE: Identify acknowledgments for alarm IDs (how the send knows the ID, good question)
  44. * DONE: Persist acknowledgments
  45. * DONE: Identify escalation reply
  46. * DONE: Identify clear reply
  47. * DOND: Identify unacknowledged reply
  48. * DONE: Formalize Acknowledgment parameters (ack-type, id)
  49. * DONE: JavaMail configuration factory
  50. * DONE: Ackd configuration factory
  51. * TODO: Associate email replies with openNMS user
  52. * DONE: Finish scheduling component of JavaAckReader
  53. * DONE: Configurable Schedule
  54. * DONE: Identify Java Mail configuration element to use for reading replies
  55. * TODO: Migrate JavaMailNotificationStrategy to new JavaMail Configuration and JavaSendMailer
  56. * TODO: Migrate Availability Reports send via JavaMail to new JavaMail Configuration and JavaSendMailer
  57. * TODO: Move reading email messages from MTM to JavaReadMailer class
  58. * DONE: Need an event to cause re-loading of schedules based on changes to ackd-configuration
  59. * DONE: Do some proper logging
  60. * DONE: Handle "enabled" flag of the readers in ackd-configuration
  61. * DONE: Move executor to Ackd daemon
  62. *
  63. * @author <a href=mailto:david@opennms.org>David Hustace</a>
  64. * @version $Id: $
  65. */
  66. public class DefaultAckReader implements AckReader, InitializingBean {
  67. private static final Logger LOG = LoggerFactory.getLogger(DefaultAckReader.class);
  68. private volatile String m_name;
  69. private volatile Future<?> m_future;
  70. private AckProcessor m_ackProcessor;
  71. private ReaderSchedule m_schedule;
  72. private volatile AckReaderState m_state = AckReaderState.STOPPED;
  73. @Autowired
  74. private volatile AckdConfigurationDao m_ackdConfigDao;
  75. /**
  76. * <p>afterPropertiesSet</p>
  77. *
  78. * @throws java.lang.Exception if any.
  79. */
  80. @Override
  81. public void afterPropertiesSet() throws Exception {
  82. BeanUtils.assertAutowiring(this);
  83. boolean state = (m_ackProcessor != null);
  84. Assert.state(state, "Dependency injection failed; one or more fields are null.");
  85. }
  86. private synchronized void start(final ScheduledThreadPoolExecutor executor) {
  87. if (m_schedule == null) {
  88. m_schedule = ReaderSchedule.createSchedule();
  89. }
  90. this.start(executor, m_schedule, true);
  91. }
  92. /** {@inheritDoc} */
  93. @Override
  94. public synchronized void start(final ScheduledThreadPoolExecutor executor, final ReaderSchedule schedule, boolean reloadConfig) throws IllegalStateException {
  95. if (reloadConfig) {
  96. //FIXME:The reload of JavaMailConfiguration is made here because the DAO is there. Perhaps that should be changed.
  97. LOG.info("start: reloading ack processor configuration...");
  98. m_ackProcessor.reloadConfigs();
  99. LOG.info("start: ack processor configuration reloaded.");
  100. }
  101. if (AckReaderState.STOPPED.equals(getState())) {
  102. this.setState(AckReaderState.START_PENDING);
  103. this.setSchedule(executor, schedule, false);
  104. LOG.info("start: Starting reader...");
  105. this.scheduleReads(executor);
  106. this.setState(AckReaderState.STARTED);
  107. LOG.info("start: Reader started.");
  108. } else {
  109. IllegalStateException e = new IllegalStateException("Reader is not in a stopped state. Reader state is: "+getState());
  110. LOG.error("start error", e);
  111. throw e;
  112. }
  113. }
  114. /**
  115. * <p>pause</p>
  116. *
  117. * @throws java.lang.IllegalStateException if any.
  118. */
  119. @Override
  120. public synchronized void pause() throws IllegalStateException {
  121. if (AckReaderState.STARTED.equals(getState()) || AckReaderState.RESUMED.equals(getState())) {
  122. LOG.info("pause: lock acquired; pausing reader...");
  123. setState(AckReaderState.PAUSE_PENDING);
  124. if (m_future != null) {
  125. m_future.cancel(false);
  126. m_future = null;
  127. }
  128. setState(AckReaderState.PAUSED);
  129. LOG.info("pause: Reader paused.");
  130. } else {
  131. IllegalStateException e = new IllegalStateException("Reader is not in a running state (STARTED or RESUMED). Reader state is: "+getState());
  132. LOG.error("pause error", e);
  133. throw e;
  134. }
  135. }
  136. /** {@inheritDoc} */
  137. @Override
  138. public synchronized void resume(final ScheduledThreadPoolExecutor executor) throws IllegalStateException {
  139. if (AckReaderState.PAUSED.equals(getState())) {
  140. setState(AckReaderState.RESUME_PENDING);
  141. LOG.info("resume: lock acquired; resuming reader...");
  142. scheduleReads(executor);
  143. setState(AckReaderState.RESUMED);
  144. LOG.info("resume: reader resumed.");
  145. } else {
  146. IllegalStateException e = new IllegalStateException("Reader is not in a paused state, cannot resume. Reader state is: "+getState());
  147. LOG.error("resume error", e);
  148. throw e;
  149. }
  150. }
  151. /**
  152. * <p>stop</p>
  153. *
  154. * @throws java.lang.IllegalStateException if any.
  155. */
  156. @Override
  157. public synchronized void stop() throws IllegalStateException {
  158. if (!AckReaderState.STOPPED.equals(getState())) {
  159. setState(AckReaderState.STOP_PENDING);
  160. LOG.info("stop: lock acquired; stopping reader...");
  161. if (m_future != null) {
  162. m_future.cancel(false);
  163. m_future = null;
  164. }
  165. setState(AckReaderState.STOPPED);
  166. LOG.info("stop: Reader stopped.");
  167. } else {
  168. IllegalStateException e = new IllegalStateException("Reader is already stopped.");
  169. LOG.error("stop error", e);
  170. throw e;
  171. }
  172. }
  173. private synchronized void scheduleReads(final ScheduledThreadPoolExecutor executor) {
  174. LOG.debug("scheduleReads: acquired lock, creating schedule...");
  175. executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
  176. executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
  177. m_future = executor.scheduleWithFixedDelay(this.getAckProcessor(), getSchedule().getInitialDelay(),
  178. getSchedule().getInterval(), getSchedule().getUnit());
  179. LOG.debug("scheduleReads: exited lock, schedule updated.");
  180. LOG.debug("scheduleReads: schedule is: attempts remaining: {}; initial delay: {}; interval: {}; unit: {}",
  181. getSchedule().getAttemptsRemaining(),
  182. getSchedule().getInitialDelay(),
  183. getSchedule().getInterval(),
  184. getSchedule().getUnit());
  185. LOG.debug("scheduleReads: executor details: active count: {}; completed task count: {}; task count: {}; queue size: {}", executor.getActiveCount(), executor.getCompletedTaskCount(), executor.getTaskCount(), executor.getQueue().size());
  186. }
  187. /** {@inheritDoc} */
  188. @Override
  189. public String toString() {
  190. return getClass().getCanonicalName();
  191. }
  192. /** {@inheritDoc} */
  193. @Override
  194. public void setAckProcessor(AckProcessor ackProcessor) {
  195. m_ackProcessor = ackProcessor;
  196. }
  197. /**
  198. * <p>getAckProcessor</p>
  199. *
  200. * @return a {@link org.opennms.netmgt.ackd.readers.AckProcessor} object.
  201. */
  202. @Override
  203. public AckProcessor getAckProcessor() {
  204. return m_ackProcessor;
  205. }
  206. /**
  207. * <p>setAckdConfigDao</p>
  208. *
  209. * @param ackdConfigDao a {@link org.opennms.netmgt.dao.api.AckdConfigurationDao} object.
  210. */
  211. public void setAckdConfigDao(AckdConfigurationDao ackdConfigDao) {
  212. m_ackdConfigDao = ackdConfigDao;
  213. }
  214. /**
  215. * <p>getAckdConfigDao</p>
  216. *
  217. * @return a {@link org.opennms.netmgt.dao.api.AckdConfigurationDao} object.
  218. */
  219. public AckdConfigurationDao getAckdConfigDao() {
  220. return m_ackdConfigDao;
  221. }
  222. /**
  223. * Gets a new schedule and optionally reschedules <code>MailAckProcessor</code>
  224. * @param schedule
  225. * @param reschedule
  226. */
  227. private synchronized void setSchedule(final ScheduledThreadPoolExecutor executor, ReaderSchedule schedule, boolean reschedule) {
  228. m_schedule = schedule;
  229. if (reschedule) {
  230. stop();
  231. start(executor);
  232. }
  233. }
  234. private ReaderSchedule getSchedule() {
  235. if (m_schedule == null) {
  236. m_schedule = ReaderSchedule.createSchedule();
  237. }
  238. return m_schedule;
  239. }
  240. /**
  241. * Anything calling this method should already have the lock.
  242. *
  243. * @param state
  244. */
  245. private synchronized void setState(AckReaderState state) {
  246. m_state = state;
  247. }
  248. /**
  249. * <p>getState</p>
  250. *
  251. * @return a AckReaderState object.
  252. */
  253. @Override
  254. public AckReaderState getState() {
  255. return m_state;
  256. }
  257. /**
  258. * <p>getFuture</p>
  259. *
  260. * @return a {@link java.util.concurrent.Future} object.
  261. */
  262. public Future<?> getFuture() {
  263. return m_future;
  264. }
  265. /**
  266. * <p>getName</p>
  267. *
  268. * @return a {@link java.lang.String} object.
  269. */
  270. @Override
  271. public String getName() {
  272. return m_name;
  273. }
  274. /** {@inheritDoc} */
  275. @Override
  276. public synchronized void setName(String name) {
  277. m_name = name;
  278. }
  279. }