You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CallbackManagerImpl.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (c) 2006-2015 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.parser.common;
  23. import com.dmdirc.parser.interfaces.Parser;
  24. import com.dmdirc.parser.interfaces.SpecificCallback;
  25. import com.dmdirc.parser.interfaces.callbacks.AuthNoticeListener;
  26. import com.dmdirc.parser.interfaces.callbacks.AwayStateListener;
  27. import com.dmdirc.parser.interfaces.callbacks.CallbackInterface;
  28. import com.dmdirc.parser.interfaces.callbacks.ChannelActionListener;
  29. import com.dmdirc.parser.interfaces.callbacks.ChannelCtcpListener;
  30. import com.dmdirc.parser.interfaces.callbacks.ChannelCtcpReplyListener;
  31. import com.dmdirc.parser.interfaces.callbacks.ChannelJoinListener;
  32. import com.dmdirc.parser.interfaces.callbacks.ChannelKickListener;
  33. import com.dmdirc.parser.interfaces.callbacks.ChannelListModeListener;
  34. import com.dmdirc.parser.interfaces.callbacks.ChannelMessageListener;
  35. import com.dmdirc.parser.interfaces.callbacks.ChannelModeChangeListener;
  36. import com.dmdirc.parser.interfaces.callbacks.ChannelModeMessageListener;
  37. import com.dmdirc.parser.interfaces.callbacks.ChannelModeNoticeListener;
  38. import com.dmdirc.parser.interfaces.callbacks.ChannelNamesListener;
  39. import com.dmdirc.parser.interfaces.callbacks.ChannelNickChangeListener;
  40. import com.dmdirc.parser.interfaces.callbacks.ChannelNonUserModeChangeListener;
  41. import com.dmdirc.parser.interfaces.callbacks.ChannelNoticeListener;
  42. import com.dmdirc.parser.interfaces.callbacks.ChannelOtherAwayStateListener;
  43. import com.dmdirc.parser.interfaces.callbacks.ChannelPartListener;
  44. import com.dmdirc.parser.interfaces.callbacks.ChannelQuitListener;
  45. import com.dmdirc.parser.interfaces.callbacks.ChannelSelfJoinListener;
  46. import com.dmdirc.parser.interfaces.callbacks.ChannelSingleModeChangeListener;
  47. import com.dmdirc.parser.interfaces.callbacks.ChannelTopicListener;
  48. import com.dmdirc.parser.interfaces.callbacks.ChannelUserModeChangeListener;
  49. import com.dmdirc.parser.interfaces.callbacks.CompositionStateChangeListener;
  50. import com.dmdirc.parser.interfaces.callbacks.ConnectErrorListener;
  51. import com.dmdirc.parser.interfaces.callbacks.DataInListener;
  52. import com.dmdirc.parser.interfaces.callbacks.DataOutListener;
  53. import com.dmdirc.parser.interfaces.callbacks.DebugInfoListener;
  54. import com.dmdirc.parser.interfaces.callbacks.ErrorInfoListener;
  55. import com.dmdirc.parser.interfaces.callbacks.GroupListEndListener;
  56. import com.dmdirc.parser.interfaces.callbacks.GroupListEntryListener;
  57. import com.dmdirc.parser.interfaces.callbacks.GroupListStartListener;
  58. import com.dmdirc.parser.interfaces.callbacks.InviteListener;
  59. import com.dmdirc.parser.interfaces.callbacks.MotdEndListener;
  60. import com.dmdirc.parser.interfaces.callbacks.MotdLineListener;
  61. import com.dmdirc.parser.interfaces.callbacks.MotdStartListener;
  62. import com.dmdirc.parser.interfaces.callbacks.NetworkDetectedListener;
  63. import com.dmdirc.parser.interfaces.callbacks.NickChangeListener;
  64. import com.dmdirc.parser.interfaces.callbacks.NickInUseListener;
  65. import com.dmdirc.parser.interfaces.callbacks.NumericListener;
  66. import com.dmdirc.parser.interfaces.callbacks.OtherAwayStateListener;
  67. import com.dmdirc.parser.interfaces.callbacks.PasswordRequiredListener;
  68. import com.dmdirc.parser.interfaces.callbacks.PingFailureListener;
  69. import com.dmdirc.parser.interfaces.callbacks.PingSentListener;
  70. import com.dmdirc.parser.interfaces.callbacks.PingSuccessListener;
  71. import com.dmdirc.parser.interfaces.callbacks.PrivateActionListener;
  72. import com.dmdirc.parser.interfaces.callbacks.PrivateCtcpListener;
  73. import com.dmdirc.parser.interfaces.callbacks.PrivateCtcpReplyListener;
  74. import com.dmdirc.parser.interfaces.callbacks.PrivateMessageListener;
  75. import com.dmdirc.parser.interfaces.callbacks.PrivateNoticeListener;
  76. import com.dmdirc.parser.interfaces.callbacks.QuitListener;
  77. import com.dmdirc.parser.interfaces.callbacks.ServerErrorListener;
  78. import com.dmdirc.parser.interfaces.callbacks.ServerNoticeListener;
  79. import com.dmdirc.parser.interfaces.callbacks.ServerReadyListener;
  80. import com.dmdirc.parser.interfaces.callbacks.SocketCloseListener;
  81. import com.dmdirc.parser.interfaces.callbacks.UnknownActionListener;
  82. import com.dmdirc.parser.interfaces.callbacks.UnknownCtcpListener;
  83. import com.dmdirc.parser.interfaces.callbacks.UnknownCtcpReplyListener;
  84. import com.dmdirc.parser.interfaces.callbacks.UnknownMessageListener;
  85. import com.dmdirc.parser.interfaces.callbacks.UnknownNoticeListener;
  86. import com.dmdirc.parser.interfaces.callbacks.UnknownServerNoticeListener;
  87. import com.dmdirc.parser.interfaces.callbacks.UserModeChangeListener;
  88. import com.dmdirc.parser.interfaces.callbacks.UserModeDiscoveryListener;
  89. import com.dmdirc.parser.interfaces.callbacks.WallDesyncListener;
  90. import com.dmdirc.parser.interfaces.callbacks.WallopListener;
  91. import com.dmdirc.parser.interfaces.callbacks.WalluserListener;
  92. import java.lang.reflect.InvocationHandler;
  93. import java.lang.reflect.Method;
  94. import java.lang.reflect.Proxy;
  95. import java.util.Collections;
  96. import java.util.HashMap;
  97. import java.util.Map;
  98. /**
  99. * Parser Callback Manager.
  100. * Manages adding/removing/calling callbacks.
  101. */
  102. public class CallbackManagerImpl implements CallbackManager {
  103. private static final Class<?>[] CLASSES = {
  104. AwayStateListener.class,
  105. OtherAwayStateListener.class,
  106. ChannelOtherAwayStateListener.class,
  107. ChannelActionListener.class,
  108. ChannelCtcpListener.class,
  109. ChannelCtcpReplyListener.class,
  110. ChannelListModeListener.class,
  111. ChannelNamesListener.class,
  112. ChannelJoinListener.class,
  113. ChannelKickListener.class,
  114. ChannelMessageListener.class,
  115. ChannelModeChangeListener.class,
  116. ChannelNickChangeListener.class,
  117. ChannelNonUserModeChangeListener.class,
  118. ChannelModeMessageListener.class,
  119. ChannelModeNoticeListener.class,
  120. ChannelNoticeListener.class,
  121. ChannelPartListener.class,
  122. ChannelQuitListener.class,
  123. ChannelSelfJoinListener.class,
  124. ChannelSingleModeChangeListener.class,
  125. ChannelTopicListener.class,
  126. ChannelUserModeChangeListener.class,
  127. CompositionStateChangeListener.class,
  128. ConnectErrorListener.class,
  129. DataInListener.class,
  130. DataOutListener.class,
  131. DebugInfoListener.class,
  132. ErrorInfoListener.class,
  133. GroupListStartListener.class,
  134. GroupListEntryListener.class,
  135. GroupListEndListener.class,
  136. NetworkDetectedListener.class,
  137. InviteListener.class,
  138. MotdEndListener.class,
  139. MotdLineListener.class,
  140. MotdStartListener.class,
  141. NickChangeListener.class,
  142. NickInUseListener.class,
  143. AuthNoticeListener.class,
  144. NumericListener.class,
  145. PasswordRequiredListener.class,
  146. PingFailureListener.class,
  147. PingSuccessListener.class,
  148. PingSentListener.class,
  149. PrivateActionListener.class,
  150. PrivateCtcpListener.class,
  151. PrivateCtcpReplyListener.class,
  152. PrivateMessageListener.class,
  153. PrivateNoticeListener.class,
  154. QuitListener.class,
  155. ServerErrorListener.class,
  156. ServerReadyListener.class,
  157. SocketCloseListener.class,
  158. UnknownActionListener.class,
  159. UnknownCtcpListener.class,
  160. UnknownCtcpReplyListener.class,
  161. UnknownMessageListener.class,
  162. UnknownNoticeListener.class,
  163. UserModeChangeListener.class,
  164. UserModeDiscoveryListener.class,
  165. WallDesyncListener.class,
  166. WallopListener.class,
  167. WalluserListener.class,
  168. ServerNoticeListener.class,
  169. UnknownServerNoticeListener.class,
  170. };
  171. /** Hashtable used to store the different types of callback known. */
  172. private final Map<Class<? extends CallbackInterface>, CallbackObject> callbackHash
  173. = new HashMap<>();
  174. /** A map of implementations to use for parser interfaces. */
  175. private final Map<Class<?>, Class<?>> implementationMap;
  176. /**
  177. * Constructor to create a CallbackManager.
  178. *
  179. * @param implementationMap A map of implementations to use
  180. */
  181. public CallbackManagerImpl(final Map<Class<?>, Class<?>> implementationMap) {
  182. this.implementationMap = Collections.unmodifiableMap(implementationMap);
  183. }
  184. @Override
  185. public void initialise(final Parser parser) {
  186. for (Class<?> type : CLASSES) {
  187. if (type.isAnnotationPresent(SpecificCallback.class)) {
  188. addCallbackType(getSpecificCallbackObject(parser, type));
  189. } else {
  190. addCallbackType(getCallbackObject(parser, type));
  191. }
  192. }
  193. }
  194. /**
  195. * Retrieves a relevant {@link CallbackObject} for the specified type.
  196. *
  197. * @param parser The parser that this manager belongs to
  198. * @param type The type of callback to create an object for
  199. * @return The relevant CallbackObject
  200. */
  201. protected CallbackObject getCallbackObject(final Parser parser, final Class<?> type) {
  202. return new CallbackObject(parser, this, type.asSubclass(CallbackInterface.class),
  203. implementationMap);
  204. }
  205. /**
  206. * Retrieves a relevant {@link CallbackObjectSpecific} for the specified type.
  207. *
  208. * @param parser The parser that this manager belongs to
  209. * @param type The type of callback to create an object for
  210. * @return The relevant CallbackObject
  211. */
  212. protected CallbackObjectSpecific getSpecificCallbackObject(
  213. final Parser parser, final Class<?> type) {
  214. return new CallbackObjectSpecific(parser, this, type.asSubclass(CallbackInterface.class),
  215. implementationMap);
  216. }
  217. /**
  218. * Add new callback type.
  219. *
  220. * @param callback CallbackObject subclass for the callback.
  221. */
  222. private void addCallbackType(final CallbackObject callback) {
  223. if (!callbackHash.containsKey(callback.getType())) {
  224. callbackHash.put(callback.getType(), callback);
  225. }
  226. }
  227. /**
  228. * Get reference to callback object.
  229. *
  230. * @param callback Name of type of callback object.
  231. * @return CallbackObject returns the callback object for this type
  232. */
  233. private CallbackObject getCallbackType(final Class<? extends CallbackInterface> callback) {
  234. if (!callbackHash.containsKey(callback)) {
  235. throw new CallbackNotFoundException("Callback not found: " + callback.getName());
  236. }
  237. return callbackHash.get(callback);
  238. }
  239. @Override
  240. public void delAllCallback(final CallbackInterface o) {
  241. callbackHash.values().stream()
  242. .filter(cb -> cb != null && cb.getType().isInstance(o))
  243. .forEach(cb -> cb.del(o));
  244. }
  245. @Override
  246. public void addAllCallback(final CallbackInterface o) {
  247. callbackHash.values().stream()
  248. .filter(cb -> cb != null && cb.getType().isInstance(o))
  249. .forEach(cb -> cb.add(o));
  250. }
  251. @Override
  252. public <S extends CallbackInterface> void addCallback(final Class<S> callback, final S o) throws CallbackNotFoundException {
  253. if (o == null) {
  254. throw new NullPointerException("CallbackInterface is null");
  255. }
  256. final CallbackObject cb = getCallbackType(callback);
  257. if (cb != null) {
  258. cb.add(o);
  259. }
  260. }
  261. @Override
  262. public <S extends CallbackInterface> void addCallback(final Class<S> callback, final S o,
  263. final String target) throws CallbackNotFoundException {
  264. if (o == null) {
  265. throw new NullPointerException("CallbackInterface is null");
  266. }
  267. ((CallbackObjectSpecific) getCallbackType(callback)).add(o, target);
  268. }
  269. @Override
  270. public void delCallback(final Class<? extends CallbackInterface> callback,
  271. final CallbackInterface o) {
  272. getCallbackType(callback).del(o);
  273. }
  274. @Override
  275. @SuppressWarnings({"unchecked", "rawtypes"})
  276. public <T extends CallbackInterface> T getCallback(final Class<T> callback) {
  277. return (T) Proxy.newProxyInstance(getClass().getClassLoader(),
  278. new Class[]{ callback }, new CallbackHandler(callback));
  279. }
  280. /**
  281. * A Proxy invocation handler for a specified parser callback.
  282. */
  283. private class CallbackHandler implements InvocationHandler {
  284. /** The callback that should be called. */
  285. private final Class<? extends CallbackInterface> callback;
  286. /**
  287. * Creates a new callback handler for the specified callback.
  288. *
  289. * @param callback The callback to handle
  290. */
  291. public CallbackHandler(final Class<? extends CallbackInterface> callback) {
  292. this.callback = callback;
  293. }
  294. @Override
  295. public Object invoke(final Object proxy, final Method method, final Object[] args) {
  296. getCallbackType(callback).call(args);
  297. return null;
  298. }
  299. }
  300. }