Browse Source

Make callback manager an eventbus.

pull/70/head
Greg Holmes 9 years ago
parent
commit
e3154f075c

+ 1
- 27
common/src/com/dmdirc/parser/common/BaseParser.java View File

@@ -24,7 +24,6 @@ package com.dmdirc.parser.common;
24 24
 
25 25
 import com.dmdirc.parser.interfaces.ChannelInfo;
26 26
 import com.dmdirc.parser.interfaces.ClientInfo;
27
-import com.dmdirc.parser.interfaces.callbacks.CallbackInterface;
28 27
 
29 28
 import java.net.InetSocketAddress;
30 29
 import java.net.Proxy;
@@ -32,9 +31,7 @@ import java.net.ProxySelector;
32 31
 import java.net.SocketAddress;
33 32
 import java.net.URI;
34 33
 import java.net.URISyntaxException;
35
-import java.util.HashMap;
36 34
 import java.util.List;
37
-import java.util.Map;
38 35
 
39 36
 /**
40 37
  * Implements common base functionality for parsers.
@@ -79,16 +76,7 @@ public abstract class BaseParser extends ThreadedParser {
79 76
     public BaseParser(final URI uri) {
80 77
         this.uri = uri;
81 78
 
82
-        final Map<Class<?>, Class<?>> implementations = new HashMap<>();
83
-
84
-        for (Class<?> child : getClass().getAnnotation(ChildImplementations.class).value()) {
85
-            for (Class<?> iface : child.getInterfaces()) {
86
-                implementations.put(iface, child);
87
-            }
88
-        }
89
-
90
-        callbackManager = new CallbackManager(implementations);
91
-        callbackManager.initialise(this);
79
+        callbackManager = new CallbackManager(this);
92 80
     }
93 81
 
94 82
     @Override
@@ -161,20 +149,6 @@ public abstract class BaseParser extends ThreadedParser {
161 149
         return callbackManager;
162 150
     }
163 151
 
164
-    /**
165
-     * Gets a proxy object which can be used to despatch callbacks of the
166
-     * specified type. Callers may pass <code>null</code> for the first two
167
-     * arguments of any callback, and these will automatically be replaced
168
-     * by the relevant Parser instance and the current date.
169
-     *
170
-     * @param <T> The type of the callback to retrieve
171
-     * @param callback The callback to retrieve
172
-     * @return A proxy object which can be used to call the specified callback
173
-     */
174
-    protected <T extends CallbackInterface> T getCallback(final Class<T> callback) {
175
-        return callbackManager.getCallback(callback);
176
-    }
177
-
178 152
     @Override
179 153
     public void joinChannel(final String channel) {
180 154
         joinChannels(new ChannelJoinRequest(channel));

+ 57
- 333
common/src/com/dmdirc/parser/common/CallbackManager.java View File

@@ -22,354 +22,78 @@
22 22
 
23 23
 package com.dmdirc.parser.common;
24 24
 
25
+import com.dmdirc.parser.events.ParserErrorEvent;
26
+import com.dmdirc.parser.events.ParserEvent;
25 27
 import com.dmdirc.parser.interfaces.Parser;
26
-import com.dmdirc.parser.interfaces.SpecificCallback;
27
-import com.dmdirc.parser.interfaces.callbacks.AuthNoticeListener;
28
-import com.dmdirc.parser.interfaces.callbacks.AwayStateListener;
29
-import com.dmdirc.parser.interfaces.callbacks.CallbackInterface;
30
-import com.dmdirc.parser.interfaces.callbacks.ChannelActionListener;
31
-import com.dmdirc.parser.interfaces.callbacks.ChannelCtcpListener;
32
-import com.dmdirc.parser.interfaces.callbacks.ChannelCtcpReplyListener;
33
-import com.dmdirc.parser.interfaces.callbacks.ChannelJoinListener;
34
-import com.dmdirc.parser.interfaces.callbacks.ChannelKickListener;
35
-import com.dmdirc.parser.interfaces.callbacks.ChannelListModeListener;
36
-import com.dmdirc.parser.interfaces.callbacks.ChannelMessageListener;
37
-import com.dmdirc.parser.interfaces.callbacks.ChannelModeChangeListener;
38
-import com.dmdirc.parser.interfaces.callbacks.ChannelModeMessageListener;
39
-import com.dmdirc.parser.interfaces.callbacks.ChannelModeNoticeListener;
40
-import com.dmdirc.parser.interfaces.callbacks.ChannelNamesListener;
41
-import com.dmdirc.parser.interfaces.callbacks.ChannelNickChangeListener;
42
-import com.dmdirc.parser.interfaces.callbacks.ChannelNonUserModeChangeListener;
43
-import com.dmdirc.parser.interfaces.callbacks.ChannelNoticeListener;
44
-import com.dmdirc.parser.interfaces.callbacks.ChannelOtherAwayStateListener;
45
-import com.dmdirc.parser.interfaces.callbacks.ChannelPartListener;
46
-import com.dmdirc.parser.interfaces.callbacks.ChannelQuitListener;
47
-import com.dmdirc.parser.interfaces.callbacks.ChannelSelfJoinListener;
48
-import com.dmdirc.parser.interfaces.callbacks.ChannelSingleModeChangeListener;
49
-import com.dmdirc.parser.interfaces.callbacks.ChannelTopicListener;
50
-import com.dmdirc.parser.interfaces.callbacks.ChannelUserModeChangeListener;
51
-import com.dmdirc.parser.interfaces.callbacks.CompositionStateChangeListener;
52
-import com.dmdirc.parser.interfaces.callbacks.ConnectErrorListener;
53
-import com.dmdirc.parser.interfaces.callbacks.DataInListener;
54
-import com.dmdirc.parser.interfaces.callbacks.DataOutListener;
55
-import com.dmdirc.parser.interfaces.callbacks.DebugInfoListener;
56
-import com.dmdirc.parser.interfaces.callbacks.ErrorInfoListener;
57
-import com.dmdirc.parser.interfaces.callbacks.GroupListEndListener;
58
-import com.dmdirc.parser.interfaces.callbacks.GroupListEntryListener;
59
-import com.dmdirc.parser.interfaces.callbacks.GroupListStartListener;
60
-import com.dmdirc.parser.interfaces.callbacks.InviteListener;
61
-import com.dmdirc.parser.interfaces.callbacks.MotdEndListener;
62
-import com.dmdirc.parser.interfaces.callbacks.MotdLineListener;
63
-import com.dmdirc.parser.interfaces.callbacks.MotdStartListener;
64
-import com.dmdirc.parser.interfaces.callbacks.NetworkDetectedListener;
65
-import com.dmdirc.parser.interfaces.callbacks.NickChangeListener;
66
-import com.dmdirc.parser.interfaces.callbacks.NickInUseListener;
67
-import com.dmdirc.parser.interfaces.callbacks.NumericListener;
68
-import com.dmdirc.parser.interfaces.callbacks.OtherAwayStateListener;
69
-import com.dmdirc.parser.interfaces.callbacks.PasswordRequiredListener;
70
-import com.dmdirc.parser.interfaces.callbacks.PingFailureListener;
71
-import com.dmdirc.parser.interfaces.callbacks.PingSentListener;
72
-import com.dmdirc.parser.interfaces.callbacks.PingSuccessListener;
73
-import com.dmdirc.parser.interfaces.callbacks.PrivateActionListener;
74
-import com.dmdirc.parser.interfaces.callbacks.PrivateCtcpListener;
75
-import com.dmdirc.parser.interfaces.callbacks.PrivateCtcpReplyListener;
76
-import com.dmdirc.parser.interfaces.callbacks.PrivateMessageListener;
77
-import com.dmdirc.parser.interfaces.callbacks.PrivateNoticeListener;
78
-import com.dmdirc.parser.interfaces.callbacks.QuitListener;
79
-import com.dmdirc.parser.interfaces.callbacks.ServerErrorListener;
80
-import com.dmdirc.parser.interfaces.callbacks.ServerNoticeListener;
81
-import com.dmdirc.parser.interfaces.callbacks.ServerReadyListener;
82
-import com.dmdirc.parser.interfaces.callbacks.SocketCloseListener;
83
-import com.dmdirc.parser.interfaces.callbacks.UnknownActionListener;
84
-import com.dmdirc.parser.interfaces.callbacks.UnknownCtcpListener;
85
-import com.dmdirc.parser.interfaces.callbacks.UnknownCtcpReplyListener;
86
-import com.dmdirc.parser.interfaces.callbacks.UnknownMessageListener;
87
-import com.dmdirc.parser.interfaces.callbacks.UnknownNoticeListener;
88
-import com.dmdirc.parser.interfaces.callbacks.UnknownServerNoticeListener;
89
-import com.dmdirc.parser.interfaces.callbacks.UserModeChangeListener;
90
-import com.dmdirc.parser.interfaces.callbacks.UserModeDiscoveryListener;
91
-import com.dmdirc.parser.interfaces.callbacks.WallDesyncListener;
92
-import com.dmdirc.parser.interfaces.callbacks.WallopListener;
93
-import com.dmdirc.parser.interfaces.callbacks.WalluserListener;
94 28
 
95
-import java.lang.reflect.InvocationHandler;
96
-import java.lang.reflect.Method;
97
-import java.lang.reflect.Proxy;
98
-import java.util.Collections;
99
-import java.util.HashMap;
100
-import java.util.Map;
29
+import com.google.common.base.Throwables;
30
+
31
+import java.util.Date;
32
+
33
+import net.engio.mbassy.bus.MBassador;
34
+import net.engio.mbassy.bus.config.BusConfiguration;
35
+import net.engio.mbassy.bus.config.Feature;
101 36
 
102 37
 /**
103 38
  * Parser Callback Manager.
104 39
  * Manages adding/removing/calling callbacks.
105 40
  */
106
-public class CallbackManager {
107
-
108
-    private static final Class<?>[] CLASSES = {
109
-        AwayStateListener.class,
110
-        OtherAwayStateListener.class,
111
-        ChannelOtherAwayStateListener.class,
112
-        ChannelActionListener.class,
113
-        ChannelCtcpListener.class,
114
-        ChannelCtcpReplyListener.class,
115
-        ChannelListModeListener.class,
116
-        ChannelNamesListener.class,
117
-        ChannelJoinListener.class,
118
-        ChannelKickListener.class,
119
-        ChannelMessageListener.class,
120
-        ChannelModeChangeListener.class,
121
-        ChannelNickChangeListener.class,
122
-        ChannelNonUserModeChangeListener.class,
123
-        ChannelModeMessageListener.class,
124
-        ChannelModeNoticeListener.class,
125
-        ChannelNoticeListener.class,
126
-        ChannelPartListener.class,
127
-        ChannelQuitListener.class,
128
-        ChannelSelfJoinListener.class,
129
-        ChannelSingleModeChangeListener.class,
130
-        ChannelTopicListener.class,
131
-        ChannelUserModeChangeListener.class,
132
-        CompositionStateChangeListener.class,
133
-        ConnectErrorListener.class,
134
-        DataInListener.class,
135
-        DataOutListener.class,
136
-        DebugInfoListener.class,
137
-        ErrorInfoListener.class,
138
-        GroupListStartListener.class,
139
-        GroupListEntryListener.class,
140
-        GroupListEndListener.class,
141
-        NetworkDetectedListener.class,
142
-        InviteListener.class,
143
-        MotdEndListener.class,
144
-        MotdLineListener.class,
145
-        MotdStartListener.class,
146
-        NickChangeListener.class,
147
-        NickInUseListener.class,
148
-        AuthNoticeListener.class,
149
-        NumericListener.class,
150
-        PasswordRequiredListener.class,
151
-        PingFailureListener.class,
152
-        PingSuccessListener.class,
153
-        PingSentListener.class,
154
-        PrivateActionListener.class,
155
-        PrivateCtcpListener.class,
156
-        PrivateCtcpReplyListener.class,
157
-        PrivateMessageListener.class,
158
-        PrivateNoticeListener.class,
159
-        QuitListener.class,
160
-        ServerErrorListener.class,
161
-        ServerReadyListener.class,
162
-        SocketCloseListener.class,
163
-        UnknownActionListener.class,
164
-        UnknownCtcpListener.class,
165
-        UnknownCtcpReplyListener.class,
166
-        UnknownMessageListener.class,
167
-        UnknownNoticeListener.class,
168
-        UserModeChangeListener.class,
169
-        UserModeDiscoveryListener.class,
170
-        WallDesyncListener.class,
171
-        WallopListener.class,
172
-        WalluserListener.class,
173
-        ServerNoticeListener.class,
174
-        UnknownServerNoticeListener.class,
175
-    };
176
-
177
-    /** Hashtable used to store the different types of callback known. */
178
-    private final Map<Class<? extends CallbackInterface>, CallbackObject> callbackHash
179
-            = new HashMap<>();
180
-
181
-    /** A map of implementations to use for parser interfaces. */
182
-    private final Map<Class<?>, Class<?>> implementationMap;
183
-
184
-    /**
185
-     * Constructor to create a CallbackManager.
186
-     *
187
-     * @param implementationMap A map of implementations to use
188
-     */
189
-    public CallbackManager(final Map<Class<?>, Class<?>> implementationMap) {
190
-        this.implementationMap = Collections.unmodifiableMap(implementationMap);
191
-    }
192
-
193
-    /**
194
-     * Initialises this callback manager.
195
-     *
196
-     * @param parser The parser associated with this CallbackManager
197
-     */
198
-    public void initialise(final Parser parser) {
199
-        for (Class<?> type : CLASSES) {
200
-            if (type.isAnnotationPresent(SpecificCallback.class)) {
201
-                addCallbackType(getSpecificCallbackObject(parser, type));
202
-            } else {
203
-                addCallbackType(getCallbackObject(parser, type));
204
-            }
205
-        }
206
-    }
207
-
208
-    /**
209
-     * Retrieves a relevant {@link CallbackObject} for the specified type.
210
-     *
211
-     * @param parser The parser that this manager belongs to
212
-     * @param type The type of callback to create an object for
213
-     * @return The relevant CallbackObject
214
-     */
215
-    protected CallbackObject getCallbackObject(final Parser parser, final Class<?> type) {
216
-        return new CallbackObject(parser, this, type.asSubclass(CallbackInterface.class),
217
-                implementationMap);
218
-    }
219
-
220
-    /**
221
-     * Retrieves a relevant {@link CallbackObjectSpecific} for the specified type.
222
-     *
223
-     * @param parser The parser that this manager belongs to
224
-     * @param type The type of callback to create an object for
225
-     * @return The relevant CallbackObject
226
-     */
227
-    protected CallbackObjectSpecific getSpecificCallbackObject(
228
-            final Parser parser, final Class<?> type) {
229
-        return new CallbackObjectSpecific(parser, this, type.asSubclass(CallbackInterface.class),
230
-                implementationMap);
231
-    }
232
-
233
-    /**
234
-     * Add new callback type.
235
-     *
236
-     * @param callback CallbackObject subclass for the callback.
237
-     */
238
-    private void addCallbackType(final CallbackObject callback) {
239
-        if (!callbackHash.containsKey(callback.getType())) {
240
-            callbackHash.put(callback.getType(), callback);
241
-        }
242
-    }
243
-
244
-    /**
245
-     * Get reference to callback object.
246
-     *
247
-     * @param callback Name of type of callback object.
248
-     * @return CallbackObject returns the callback object for this type
249
-     */
250
-    private CallbackObject getCallbackType(final Class<? extends CallbackInterface> callback) {
251
-        if (!callbackHash.containsKey(callback)) {
252
-            throw new CallbackNotFoundException("Callback not found: " + callback.getName());
253
-        }
254
-
255
-        return callbackHash.get(callback);
256
-    }
257
-
258
-    /**
259
-     * Remove all callbacks associated with a specific object.
260
-     *
261
-     * @param o instance of ICallbackInterface to remove.
262
-     */
263
-    public void delAllCallback(final CallbackInterface o) {
264
-        callbackHash.values().stream()
265
-                .filter(cb -> cb != null && cb.getType().isInstance(o))
266
-                .forEach(cb -> cb.del(o));
41
+public class CallbackManager extends MBassador<ParserEvent> {
42
+
43
+    private final Object errorHandlerLock = new Object();
44
+    private final Parser parser;
45
+
46
+    public CallbackManager(final Parser parser) {
47
+        super(new BusConfiguration().addFeature(Feature.SyncPubSub.Default())
48
+                .addFeature(Feature.AsynchronousHandlerInvocation.Default(1, 1)).addFeature(
49
+                        Feature.AsynchronousMessageDispatch.Default()
50
+                                .setNumberOfMessageDispatchers(1)));
51
+        this.parser = parser;
52
+        setupErrorHandler();
267 53
     }
268 54
 
269
-    /**
270
-     * Add all callbacks that this object implements.
271
-     *
272
-     * @param o instance of ICallbackInterface to add.
273
-     */
274
-    public void addAllCallback(final CallbackInterface o) {
275
-        callbackHash.values().stream()
276
-                .filter(cb -> cb != null && cb.getType().isInstance(o))
277
-                .forEach(cb -> cb.add(o));
55
+    @SuppressWarnings("TypeMayBeWeakened")
56
+    public CallbackManager(final BusConfiguration configuration, final Parser parser) {
57
+        super(configuration);
58
+        setupErrorHandler();
59
+        this.parser = parser;
278 60
     }
279 61
 
280
-    /**
281
-     * Add a callback.
282
-     * This method will throw a CallbackNotFoundException if the callback does not exist.
283
-     *
284
-     * @param <S> The type of callback
285
-     * @param callback Type of callback object
286
-     * @param o instance of ICallbackInterface to add.
287
-     * @throws CallbackNotFoundException If callback is not found.
288
-     * @throws NullPointerException If 'o' is null
289
-     */
290
-    public <S extends CallbackInterface> void addCallback(
291
-            final Class<S> callback, final S o) throws CallbackNotFoundException {
292
-        if (o == null) {
293
-            throw new NullPointerException("CallbackInterface is null");
294
-        }
295
-
296
-        final CallbackObject cb = getCallbackType(callback);
297
-
298
-        if (cb != null) {
299
-            cb.add(o);
62
+    @Override
63
+    public void publish(final ParserEvent message) {
64
+        // TODO: HACKY REMOVE
65
+        if (message.getParser() == null) {
66
+            message.setParser(parser);
300 67
         }
301
-    }
302
-
303
-    /**
304
-     * Add a callback with a specific target.
305
-     * This method will throw a CallbackNotFoundException if the callback does not exist.
306
-     *
307
-     * @param <S> The type of callback
308
-     * @param callback Type of callback object.
309
-     * @param o instance of ICallbackInterface to add.
310
-     * @param target Parameter to specify that a callback should only fire for specific things
311
-     * @throws CallbackNotFoundException If callback is not found.
312
-     * @throws NullPointerException If 'o' is null
313
-     */
314
-    public <S extends CallbackInterface> void addCallback(
315
-            final Class<S> callback,
316
-            final S o, final String target) throws CallbackNotFoundException {
317
-        if (o == null) {
318
-            throw new NullPointerException("CallbackInterface is null");
68
+        if (message.getDate() == null) {
69
+            message.setDate(new Date());
319 70
         }
320
-
321
-        ((CallbackObjectSpecific) getCallbackType(callback)).add(o, target);
322
-    }
323
-
324
-    /**
325
-     * Remove a callback.
326
-     *
327
-     * @param callback Type of callback object.
328
-     * @param o instance of ICallbackInterface to remove.
329
-     */
330
-    public void delCallback(final Class<? extends CallbackInterface> callback,
331
-            final CallbackInterface o) {
332
-        getCallbackType(callback).del(o);
333
-    }
334
-
335
-    /**
336
-     * Gets a proxy object which can be used to despatch callbacks of the
337
-     * specified type. Callers may pass <code>null</code> for the first two
338
-     * arguments of any callback, and these will automatically be replaced
339
-     * by the relevant Parser instance and the current date.
340
-     *
341
-     * @param <T> The type of the callback to retrieve
342
-     * @param callback The callback to retrieve
343
-     * @return A proxy object which can be used to call the specified callback
344
-     */
345
-    @SuppressWarnings({"unchecked", "rawtypes"})
346
-    public <T extends CallbackInterface> T getCallback(final Class<T> callback) {
347
-        return (T) Proxy.newProxyInstance(getClass().getClassLoader(),
348
-                new Class[]{ callback }, new CallbackHandler(callback));
71
+        // TODO: HACKY REMOVE
72
+        super.publish(message);
349 73
     }
350 74
 
351
-    /**
352
-     * A Proxy invocation handler for a specified parser callback.
353
-     */
354
-    private class CallbackHandler implements InvocationHandler {
355
-
356
-        /** The callback that should be called. */
357
-        private final Class<? extends CallbackInterface> callback;
358
-
359
-        /**
360
-         * Creates a new callback handler for the specified callback.
361
-         *
362
-         * @param callback The callback to handle
363
-         */
364
-        public CallbackHandler(final Class<? extends CallbackInterface> callback) {
365
-            this.callback = callback;
366
-        }
367
-
368
-        @Override
369
-        public Object invoke(final Object proxy, final Method method, final Object[] args) {
370
-            getCallbackType(callback).call(args);
371
-            return null;
372
-        }
75
+    @SuppressWarnings({
76
+            "ThrowableResultOfMethodCallIgnored",
77
+            "CallToPrintStackTrace",
78
+            "UseOfSystemOutOrSystemErr"
79
+    })
80
+    private void setupErrorHandler() {
81
+        addErrorHandler(e -> {
82
+            if (Thread.holdsLock(errorHandlerLock)) {
83
+                // ABORT ABORT ABORT - we're publishing an error on the same thread we just tried
84
+                // to publish an error on. Something in the error reporting pipeline must be
85
+                // breaking, so don't try adding any more errors.
86
+                System.err.println("ERROR: Error when reporting error");
87
+                e.getCause().printStackTrace();
88
+                return;
89
+            }
373 90
 
91
+            synchronized (errorHandlerLock) {
92
+                final Throwable error = e.getCause().getCause();
93
+                publish(new ParserErrorEvent(parser, new Date(),
94
+                        new ParserError(ParserError.ERROR_EXCEPTION,
95
+                        error.getMessage(), Throwables.getStackTraceAsString(error))));
96
+            }
97
+        });
374 98
     }
375 99
 }

+ 0
- 287
common/src/com/dmdirc/parser/common/CallbackObject.java View File

@@ -1,287 +0,0 @@
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
-
24
-import com.dmdirc.parser.interfaces.FakableArgument;
25
-import com.dmdirc.parser.interfaces.FakableSource;
26
-import com.dmdirc.parser.interfaces.Parser;
27
-import com.dmdirc.parser.interfaces.callbacks.CallbackInterface;
28
-import com.dmdirc.parser.interfaces.callbacks.ErrorInfoListener;
29
-
30
-import java.lang.annotation.Annotation;
31
-import java.lang.reflect.Constructor;
32
-import java.lang.reflect.InvocationTargetException;
33
-import java.lang.reflect.Method;
34
-import java.util.Date;
35
-import java.util.HashMap;
36
-import java.util.List;
37
-import java.util.Map;
38
-import java.util.concurrent.CopyOnWriteArrayList;
39
-
40
-/**
41
- * Superclass for all callback types.
42
- */
43
-public class CallbackObject {
44
-
45
-    /** The type of callback that this object is operating with. */
46
-    protected final Class<? extends CallbackInterface> type;
47
-
48
-    /** Arraylist for storing callback information related to the callback. */
49
-    protected final List<CallbackInterface> callbackInfo
50
-            = new CopyOnWriteArrayList<>();
51
-
52
-    /** Reference to the Parser that owns this callback. */
53
-    protected Parser myParser;
54
-
55
-    /** Reference to the CallbackManager in charge of this callback. */
56
-    protected CallbackManager myManager;
57
-
58
-    /** A map of interfaces to their concrete implementations. */
59
-    private final Map<Class<?>, Class<?>> implementationMap;
60
-
61
-    /**
62
-     * Create a new instance of the Callback Object.
63
-     *
64
-     * @param parser Parser That owns this callback
65
-     * @param manager CallbackManager that is in charge of this callback
66
-     * @param type The type of callback to use
67
-     * @param implementationMap A map of interfaces to their parser-specific
68
-     * implementations
69
-     * @since 0.6.6
70
-     */
71
-    public CallbackObject(final Parser parser, final CallbackManager manager,
72
-            final Class<? extends CallbackInterface> type,
73
-            final Map<Class<?>, Class<?>> implementationMap) {
74
-        this.myParser = parser;
75
-        this.myManager = manager;
76
-        this.type = type;
77
-        this.implementationMap = implementationMap;
78
-    }
79
-
80
-    /**
81
-     * Add a callback pointer to the appropriate ArrayList.
82
-     *
83
-     * @param eMethod OBject to callback to.
84
-     */
85
-    protected final void addCallback(final CallbackInterface eMethod) {
86
-        if (!callbackInfo.contains(eMethod)) {
87
-            callbackInfo.add(eMethod);
88
-        }
89
-    }
90
-
91
-    /**
92
-     * Delete a callback pointer from the appropriate ArrayList.
93
-     *
94
-     * @param eMethod Object that was being called back to.
95
-     */
96
-    protected final void delCallback(final CallbackInterface eMethod) {
97
-        callbackInfo.remove(eMethod);
98
-    }
99
-
100
-    /**
101
-     * Call the OnErrorInfo callback.
102
-     *
103
-     * @param errorInfo ParserError object to pass as error.
104
-     */
105
-    protected final void callErrorInfo(final ParserError errorInfo) {
106
-        myManager.getCallback(ErrorInfoListener.class).onErrorInfo(myParser, new Date(), errorInfo);
107
-    }
108
-
109
-    /**
110
-     * Add a new callback.
111
-     *
112
-     * @param eMethod Object to callback to.
113
-     */
114
-    public void add(final CallbackInterface eMethod) {
115
-        addCallback(eMethod);
116
-    }
117
-
118
-    /**
119
-     * Remove a callback.
120
-     *
121
-     * @param eMethod Object to remove callback to.
122
-     */
123
-    public void del(final CallbackInterface eMethod) {
124
-        delCallback(eMethod);
125
-    }
126
-
127
-    /**
128
-     * Retrieves the type of callback that this callback object is for.
129
-     *
130
-     * @return This object's type
131
-     * @since 0.6.3m2
132
-     */
133
-    public Class<? extends CallbackInterface> getType() {
134
-        return type;
135
-    }
136
-
137
-    /**
138
-     * Actually calls this callback. The specified arguments must match those
139
-     * specified in the callback's interface, or an error will be raised.
140
-     *
141
-     * @param args The arguments to pass to the callback implementation
142
-     */
143
-    public void call(final Object... args) {
144
-        createFakeArgs(args);
145
-
146
-        for (CallbackInterface iface : callbackInfo) {
147
-            try {
148
-                type.getMethods()[0].invoke(iface, args);
149
-            } catch (SecurityException | IllegalAccessException |
150
-                    IllegalArgumentException | InvocationTargetException e) {
151
-                if (getType().equals(ErrorInfoListener.class)) {
152
-                    System.out.printf("Exception in onError Callback. [%s]\n", e.getMessage());
153
-                    e.printStackTrace();
154
-                } else {
155
-                    final ParserError ei = new ParserError(ParserError.ERROR_ERROR,
156
-                            "Exception in callback (" + e.getMessage() + ")",
157
-                            myParser.getLastLine());
158
-                    ei.setException(e);
159
-                    callErrorInfo(ei);
160
-                }
161
-            }
162
-        }
163
-    }
164
-
165
-    /**
166
-     * Replaces all null entries in the specified array with fake values, if the
167
-     * corresponding parameter of this callback's type is marked with the
168
-     * {@link FakableArgument} annotation. The fake classes are constructed by
169
-     * using parameters designated {@link FakableSource}.
170
-     *
171
-     * @param args The arguments to be faked
172
-     */
173
-    protected void createFakeArgs(final Object[] args) {
174
-        int i = 0;
175
-
176
-        for (Annotation[] anns : type.getMethods()[0].getParameterAnnotations()) {
177
-            for (Annotation ann : anns) {
178
-                if (ann.annotationType().equals(FakableArgument.class) && args[i] == null) {
179
-                    args[i] = getFakeArg(args, type.getMethods()[0].getParameterTypes()[i]);
180
-                }
181
-            }
182
-
183
-            i++;
184
-        }
185
-    }
186
-
187
-    /**
188
-     * Tries to create fake argument of the specified target class, by using
189
-     * {@link FakableSource} denoted parameters from the specified arg array.
190
-     *
191
-     * If an argument is missing, the method attempts to create a fake instance
192
-     * by recursing into this method again. Note that this could cause an
193
-     * infinite recursion in cases of cyclic dependencies. If recursion fails,
194
-     * the constructor is skipped.
195
-     *
196
-     * If the created object has a <code>setFake(boolean)</code> method, it is
197
-     * automatically invoked with an argument of <code>true</code>.
198
-     *
199
-     * @param args The arguments array to use for sources
200
-     * @param target The class that should be constructed
201
-     * @return An instance of the target class, or null on failure
202
-     */
203
-    protected Object getFakeArg(final Object[] args, final Class<?> target) {
204
-        final Map<Class<?>, Object> sources = new HashMap<>();
205
-        int i = 0;
206
-
207
-        for (Annotation[] anns : type.getMethods()[0].getParameterAnnotations()) {
208
-            for (Annotation ann : anns) {
209
-                if (ann.annotationType().equals(FakableSource.class)) {
210
-                    final Class<?> argType = type.getMethods()[0].getParameterTypes()[i];
211
-
212
-                    sources.put(argType, args[i]);
213
-                }
214
-            }
215
-
216
-            i++;
217
-        }
218
-
219
-        final Class<?> actualTarget = getImplementation(target);
220
-
221
-        for (Constructor<?> ctor : actualTarget.getConstructors()) {
222
-            final Object[] params = new Object[ctor.getParameterTypes().length];
223
-
224
-            i = 0;
225
-            Object param;
226
-            boolean failed = false;
227
-
228
-            for (Class<?> needed : ctor.getParameterTypes()) {
229
-                boolean found = false;
230
-
231
-                for (Map.Entry<Class<?>, Object> entry : sources.entrySet()) {
232
-                    if (entry.getKey().isAssignableFrom(needed)) {
233
-                        params[i] = entry.getValue();
234
-                        found = true;
235
-                    }
236
-                }
237
-
238
-                if (!found) {
239
-                    param = getFakeArg(args, needed);
240
-
241
-                    if (param == null) {
242
-                        failed = true;
243
-                    } else {
244
-                        params[i] = param;
245
-                    }
246
-                }
247
-
248
-                i++;
249
-            }
250
-
251
-            if (!failed) {
252
-                try {
253
-                    final Object instance = ctor.newInstance(params);
254
-
255
-                    for (Method method : actualTarget.getMethods()) {
256
-                        if (method.getName().equals("setFake")
257
-                                && method.getParameterTypes().length == 1
258
-                                && method.getParameterTypes()[0].equals(Boolean.TYPE)) {
259
-                            method.invoke(instance, true);
260
-                        }
261
-                    }
262
-
263
-                    return instance;
264
-                } catch (InstantiationException | IllegalAccessException |
265
-                        IllegalArgumentException | InvocationTargetException ex) {
266
-                    // Do nothing
267
-                }
268
-            }
269
-        }
270
-
271
-        return null;
272
-    }
273
-
274
-    /**
275
-     * Returns the concrete class which should be instantiated if this callback
276
-     * object desires an instance of the specified type. Generally, this will
277
-     * translate the common interfaces to specific parser-dependent
278
-     * implementations.
279
-     *
280
-     * @param type The type to be instantiated
281
-     * @return A concrete implementation of that type
282
-     */
283
-    protected Class<?> getImplementation(final Class<?> type) {
284
-        return implementationMap.containsKey(type) ? implementationMap.get(type) : type;
285
-    }
286
-
287
-}

+ 0
- 165
common/src/com/dmdirc/parser/common/CallbackObjectSpecific.java View File

@@ -1,165 +0,0 @@
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
-
24
-import com.dmdirc.parser.interfaces.ChannelInfo;
25
-import com.dmdirc.parser.interfaces.ClientInfo;
26
-import com.dmdirc.parser.interfaces.Parser;
27
-import com.dmdirc.parser.interfaces.SpecificCallback;
28
-import com.dmdirc.parser.interfaces.callbacks.CallbackInterface;
29
-
30
-import java.util.ArrayList;
31
-import java.util.HashMap;
32
-import java.util.Map;
33
-
34
-/**
35
- * Superclass for all callback types that have a "specific" target.
36
- */
37
-public class CallbackObjectSpecific extends CallbackObject {
38
-
39
-    /** Hashtable for storing specific information for callback. */
40
-    protected final Map<CallbackInterface, String> specificData
41
-            = new HashMap<>();
42
-
43
-    /**
44
-     * Create a new instance of the Callback Object.
45
-     *
46
-     * @param parser Parser That owns this callback
47
-     * @param manager CallbackManager that is in charge of this callback
48
-     * @param type The type of callback to use
49
-     * @param implementationMap A map of interfaces to their parser-specific
50
-     * @since 0.6.3m1
51
-     */
52
-    public CallbackObjectSpecific(final Parser parser, final CallbackManager manager,
53
-            final Class<? extends CallbackInterface> type,
54
-            final Map<Class<?>, Class<?>> implementationMap) {
55
-        super(parser, manager, type, implementationMap);
56
-    }
57
-
58
-    /**
59
-     * Used to check if a channel matches the specificData.
60
-     *
61
-     * @param eMethod Object that is being called back to
62
-     * @param cChannel ChannelInfo object for the channel to test
63
-     * @return true if channel given matches the specifics for the method given
64
-     */
65
-    protected boolean isValidChan(final CallbackInterface eMethod, final ChannelInfo cChannel) {
66
-        return !(specificData.containsKey(eMethod) && !myParser
67
-                .getStringConverter().equalsIgnoreCase(cChannel.getName(),
68
-                specificData.get(eMethod)));
69
-    }
70
-
71
-    /**
72
-     * Used to check if a hostname matches the specificData.
73
-     *
74
-     * @param eMethod Object that is being called back to
75
-     * @param sHost Hostname of user that sent the query
76
-     * @return true if host given matches the specifics for the method given
77
-     */
78
-    protected boolean isValidUser(final CallbackInterface eMethod, final String sHost) {
79
-        final String nickname = translateHostname(sHost);
80
-        return !(specificData.containsKey(eMethod) && !myParser
81
-                .getStringConverter().equalsIgnoreCase(nickname,
82
-                specificData.get(eMethod)));
83
-    }
84
-
85
-    /**
86
-     * Translates the specified hostname into the form which is used to
87
-     * register specific callbacks (e.g. nickname).
88
-     *
89
-     * @param hostname The hostname to be parsed
90
-     * @return The translated hostname
91
-     */
92
-    protected String translateHostname(final String hostname) {
93
-        return myParser.parseHostmask(hostname)[0];
94
-    }
95
-
96
-    // We override the default add method to make sure that any add with no
97
-    // specifics will have the specific data removed.
98
-    /**
99
-     * Add a new callback.
100
-     *
101
-     * @param eMethod Object to callback to.
102
-     */
103
-    @Override
104
-    public void add(final CallbackInterface eMethod) {
105
-        addCallback(eMethod);
106
-        if (specificData.containsKey(eMethod)) {
107
-            specificData.remove(eMethod);
108
-        }
109
-    }
110
-
111
-    /**
112
-     * Add a new callback with a specific target.
113
-     *
114
-     * @param eMethod Object to callback to.
115
-     * @param specificTarget Target that must match for callback to be called.
116
-     */
117
-    public void add(final CallbackInterface eMethod, final String specificTarget) {
118
-        add(eMethod);
119
-        if (!specificTarget.isEmpty()) {
120
-            specificData.put(eMethod, specificTarget);
121
-        }
122
-    }
123
-
124
-    /**
125
-     * Remove a callback.
126
-     *
127
-     * @param eMethod Object to remove callback to.
128
-     */
129
-    @Override
130
-    public void del(final CallbackInterface eMethod) {
131
-        delCallback(eMethod);
132
-        if (specificData.containsKey(eMethod)) {
133
-            specificData.remove(eMethod);
134
-        }
135
-    }
136
-
137
-    @Override
138
-    public void call(final Object... args) {
139
-        createFakeArgs(args);
140
-
141
-        for (CallbackInterface iface : new ArrayList<>(callbackInfo)) {
142
-            if (type.isAnnotationPresent(SpecificCallback.class)
143
-                    && (args[2] instanceof ClientInfo
144
-                    && !isValidUser(iface, ((ClientInfo) args[2]).getHostname())
145
-                    || args[2] instanceof ChannelInfo
146
-                    && !isValidChan(iface, (ChannelInfo) args[2])
147
-                    || !(args[2] instanceof ClientInfo
148
-                    || args[2] instanceof ChannelInfo)
149
-                    && args[args.length - 1] instanceof String
150
-                    && !isValidUser(iface, (String) args[args.length - 1]))) {
151
-                continue;
152
-            }
153
-
154
-            try {
155
-                type.getMethods()[0].invoke(iface, args);
156
-            } catch (ReflectiveOperationException e) {
157
-                final ParserError ei = new ParserError(ParserError.ERROR_ERROR,
158
-                        "Exception in callback (" + e.getMessage() + ')',
159
-                        myParser.getLastLine());
160
-                ei.setException(e);
161
-                callErrorInfo(ei);
162
-            }
163
-        }
164
-    }
165
-}

+ 45
- 0
common/src/com/dmdirc/parser/events/ParserErrorEvent.java View File

@@ -0,0 +1,45 @@
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
+
23
+package com.dmdirc.parser.events;
24
+
25
+import com.dmdirc.parser.common.ParserError;
26
+import com.dmdirc.parser.interfaces.Parser;
27
+
28
+import java.util.Date;
29
+
30
+/**
31
+ * Parser error event.
32
+ */
33
+public class ParserErrorEvent extends ParserEvent {
34
+
35
+    private final ParserError parserError;
36
+
37
+    public ParserErrorEvent(final Parser parser, final Date date, final ParserError parserError) {
38
+        super(parser, date);
39
+        this.parserError = parserError;
40
+    }
41
+
42
+    public ParserError getParserError() {
43
+        return parserError;
44
+    }
45
+}

+ 12
- 2
common/src/com/dmdirc/parser/events/ParserEvent.java View File

@@ -31,8 +31,8 @@ import java.util.Date;
31 31
  */
32 32
 public class ParserEvent {
33 33
 
34
-    private final Parser parser;
35
-    private final Date date;
34
+    private Parser parser;
35
+    private Date date;
36 36
 
37 37
     public ParserEvent(final Parser parser, final Date date) {
38 38
         this.parser = parser;
@@ -46,4 +46,14 @@ public class ParserEvent {
46 46
     public Date getDate() {
47 47
         return date;
48 48
     }
49
+
50
+    // TODO: HACKY REMOVE
51
+    public void setParser(final Parser parser) {
52
+        this.parser = parser;
53
+    }
54
+
55
+    // TODO: HACKY REMOVE
56
+    public void setDate(final Date date) {
57
+        this.date = date;
58
+    }
49 59
 }

Loading…
Cancel
Save