Revision: 1075
Author: limpbizkit
Date: Sun Sep  6 09:58:11 2009
Log: Edited wiki page through web user interface.
http://code.google.com/p/google-guice/source/detail?r=1075

Modified:
  /wiki/Multibindings.wiki

=======================================
--- /wiki/Multibindings.wiki    Sun Nov 16 16:25:06 2008
+++ /wiki/Multibindings.wiki    Sun Sep  6 09:58:11 2009
@@ -2,5 +2,103 @@
  =Multibindings=
   
[http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/multibindings/Multibinder.html
  
Multibinder] and  
[http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/multibindings/MapBinder.html
  
MapBinder] are intended for plugin-type architectures, where you've got  
several modules contributing Servlets, Actions, Filters, Components or even  
just names.

+==Using Multibindings to host Plugins==
+Multibindings make it easy to support plugins in your application. Made  
popular by [http://www.eclipseplugincentral.com/ IDEs] and  
[https://addons.mozilla.org/en-US/firefox/ browsers], this pattern exposes  
APIs for extending the behaviour of an application.
+
+Neither the plugin consumer nor the plugin author need write much setup  
code for extensible applications with Guice. Simply define an interface,  
bind implementations, and inject implementations! To illustrate, we'll use  
plugins to summarize ugly URIs like `http://bit.ly/1mzgW1` into something  
readable on Twitter.
+
+First, we define an interface that plugin authors can implement. This is  
usually an interface that lends itself to several implementations. For this  
example, we would write a different implementation for each website that we  
could summarize.
+{{{
+interface UriSummarizer {
+  /**
+   * Returns a short summary of the URI, or null if this summarizer doesn't
+   * know how to summarize the URI.
+   */
+  String summarize(URI uri);
+}
+}}}
+
+Next, we'll get our plugin authors to implement the interface. Here's an  
implementation that shortens Flickr photo URLs:
+{{{
+class FlickrPhotoSummarizer implements UriSummarizer {
+  private static final Pattern PHOTO_PATTERN
+      = Pattern.compile("http://www\.flickr\.com/photos/[^/]+/(\d+)/");
+
+  public String summarize(URI uri) {
+    Matcher matcher = PHOTO_PATTERN.matcher(uri.toString());
+    if (!matcher.matches()) {
+      return null;
+    } else {
+      String id = matcher.group(1);
+      Photo photo = lookupPhoto(id);
+      return photo.getTitle();
+    }
+  }
+}
+}}}
+
+The plugin author registers their implementation using a multibinder. Some  
plugins may bind multiple implementations, or implementations of several  
extension-point interfaces.
+{{{
+public class FlickrPluginModule extends AbstractModule {
+  public void configure() {
+    Multibinder<UriSummarizer> uriBinder =  
Multibinder.newSetBinder(binder(), UriSummarizer.class);
+    uriBinder.addBinding().to(FlickrSummarizer.class);
+
+    ... // bind plugin dependencies, such as our Flickr API key
+  }
+}
+}}}
+
+Now we can consume the services exposed by our plugins. In this case,  
we're summarizing tweets:
+{{{
+public class TweetPrettifier {
+
+  private final Set<UriSummarizer> summarizers;
+  private final EmoticonImagifier emoticonImagifier;
+
+  @Inject TweetPrettifier(Set<UriSummarizer> summarizers,
+      EmoticonImagifier emoticonImagifier) {
+    this.summarizers = summarizers;
+    this.emoticonImagifier = emoticonImagifier;
+  }
+
+  public Html prettifyTweet(String tweetMessage) {
+    ... // split out the URIs and call prettifyUri() for each
+  }
+
+  public String prettifyUri(URI uri) {
+    // loop through the implementations, looking for one that supports  
this URI
+    for (UrlSummarizer summarizer : summarizers) {
+      String summary = summarizer.summarize(uri);
+      if (summary != null) {
+        return summary;
+      }
+    }
+
+    // no summarizer found, just return the URI itself
+    return uri.toString();
+  }
+}
+}}}
+
+Finally we must register the plugins themselves. The simplest mechanism to  
do so is to list them programatically:
+{{{
+public class PrettyTweets {
+  public static void main(String[] args) {
+    Injector injector = Guice.createInjector(
+        new GoogleMapsPluginModule(),
+        new BitlyPluginModule(),
+        new FlickrPluginModule()
+        ...
+    );
+
+    injector.getInstance(Frontend.class).start();
+  }
+}
+}}}
+If it is infeasible to recompile each time the plugin set changes, the  
list of plugin modules can be loaded from a configuration file.
+
+Note that this mechanism cannot load or unload plugins while the system is  
running. If you need to hot-swap application components, investigate  
[http://code.google.com/p/google-guice/wiki/OSGi Guice's OSGi bindings].
+
  ==Limitations==
  When you use !PrivateModules with multibindings, all of the elements must  
be bound in the same environment. You cannot create collections whose  
elements span private modules. Otherwise injector creation will fail.

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to