How to build a simple GWT event bus using Generators

227 views
Skip to first unread message

Dele

unread,
Jan 21, 2012, 3:43:43 PM1/21/12
to Google Web Toolkit
Hello everyone,

I've put out a blog on using GWT's built-in code generation feature to
create a simple event bus.

http://northconcepts.com/blog/2012/01/20/how-to-build-a-simple-gwt-event-bus-using-generators/

Looking forward to your ideas and feedback.

Thomas Broyer

unread,
Jan 22, 2012, 10:19:15 AM1/22/12
to google-we...@googlegroups.com
Might I ask why you didn't simply use com.google.web.bindery.event.shared.EventBus? (or com.google.gwt.event.shared.EventBus at the time you wrote your first article)
(and its SimpleEventBus implementation, or one of your own if you want the "deferred commands" based dispatching)

Dele

unread,
Jan 23, 2012, 4:39:10 AM1/23/12
to Google Web Toolkit
Thomas,

I could have used those classes, but I wanted to go in a different
direction.

Having used Java's AWT and Swing from the early days, Event classes
and fireXXX methods have been drilled into my brain as the way events
are done. Both Java and GWT based event busses seems to have followed
this path.

My goal in the first article was to show a different approach. An
approach that uses the same listener interface for both publishing and
listening to events. This makes it clear which methods are called on
observers, eliminates event classes (unless you really want them), and
reduces total lines of code. The second article added features I
don't typically see in most event bus implementations: filtering,
topics, generic listeners, and event-based exception handling.

For the GWT event bus, I wanted the same simple, symmetrical approach
along with the additional features above. What I didn't want was
having to add "public static Type<Handler> TYPE = new
Type<Handler>();", "public Type<Handler> getAssociatedType(){...}",
and "protected void dispatch(final Handler handler){...}". I also
didn't want a bunch of GwtEvent subclasses in my application.

There's nothing wrong with the classes you've asked about, just a
different approach for me -- like strawberry vs vanilla.

Cheers,
Dele

Thomas Broyer

unread,
Jan 23, 2012, 5:41:22 AM1/23/12
to google-we...@googlegroups.com
OK, thanks for the explanation.

I see one drawback in the way you implemented it: you're looking at all the types in the TypeOracle, and putting them in a map; that means the compiler cannot prune unused listeners, as all listeners *are* potentially used (they're referenced in the map). This is the same kind of drawback as GWT-RPC, where referencing List<?> will compile in all List subclasses even if you only ever transfer ArrayList<?>s (and e.g. never transfer Collections$EmptyList, Collections$SingletonList, Collections$UnmodifiableList or Arrays$ArrayList).

Overcoming this implies referencing all the listeners you *want* to use, either in an annotation (similar to @WithTokenizers on PlaceHistoryMapper, or RequestFactory's @ExtraTypes) or in an interface (similar to GIN's Ginjector, or RequestFactory) and let the user do the GWT.create(). It only changes slightly the event bus setup (GWT.create() on a custom class/interface instead of "new EventBus()", or something similar).

Also, if you want to be able to share code between your client and server, you'd want the client-side code to be "compatible" with the server-side one, while using different implementations. You can do that easily with super-source; see http://code.google.com/webtoolkit/doc/latest/DevGuideOrganizingProjects.html#DevGuideModuleXml

Dele

unread,
Jan 23, 2012, 7:29:48 AM1/23/12
to Google Web Toolkit
Thomas,

Your analysis is dead on. There are 17 built-in GWT listeners
interfaces and publishers added to the registry (not to mention user-
defined listeners) whether or not they are used in the final
application. The generated Javascript (*.cache.html) are about 280K,
will be interesting to see how much are due to the extra classes.

I like that you've provided options with your findings. Thanks.

Annotations: This could work, but the developer has already specified
which listeners they want to use -- just by using them. It might be
burdensome to explicitly declare them again. This seems like
something the framework (or compiler) should be handling out-of-sight.

GWT create: Do I understand your point correctly, are you suggesting
passing a factory interface to GWT.create()? Something like:

public interface MyEventBus extends IEventBus {
SearchListener createSearchPublisher();
}

If so, I like it. Providing an API to set eventSource and topic would
be needed, but this looks like a great approach. Thanks for
suggesting it. Honestly, I'm more than a little jealous I didn't
think of it myself :)

Cheers,
Dele

Dele

unread,
Jan 31, 2012, 5:49:11 AM1/31/12
to Google Web Toolkit

Here's the size breakdown of the generated Javascript (*.cache.html)
under GWT 2.4 for the example app.

When the event bus' code generation is enabled, it includes all event
publishers whether or not they are used in the final app. When
disabled, only an empty PublisherFactoryRegistryImpl is generated to
satisfy the compiler. None of the publishers are generated.

Normal compile:
- Event bus disabled: 90 KB
- Event bus enabled: 110 KB

Compile without obfuscation (-style PRETTY):
- Event bus disabled: 250 KB
- Event bus enabled: 310 KB

Under a normal compile, the event bus overhead for each permutation is
about 20 KB on disk. This includes the event bus engine, the 17 built-
in GWT EventListeners, the ExceptionListener, and the SearchListener.
The actual overhead for unused EventListeners is somewhere below 20
KB, I'm guessing it's even below 10 KB.

I'm willing to live with a 10 KB overhead to use a simpler event bus.

Cheers,
Dele
Reply all
Reply to author
Forward
0 new messages