Hi guys, 

I've improved the original plugin infrastructure, please find the 2nd revision 
of UI Plugins proof-of-concept (PoC) patch attached. 

Here's a quick summary of changes: 

    * PluginSourcePageServlet looks up the actual plugin code in local 
filesystem (<pluginName>.js), so you can experiment with different plugins. If 
you want to add new plugins, just modify 
WebadminDynamicHostingServlet.writeAdditionalJsData() method. 
    * PluginManager now calls UiInit function on plugins (plugin objects) 
within the scope of WebAdmin main section (user has logged in, main section UI 
is initialized and ready), and disables plugin execution outside main section 
(e.g. when the user logs out) . 

(Please find a sample plugin code attached as well. PluginSourcePageServlet 
tries to load it from a hard-coded location in local filesystem, you probably 
want to modify this to suit your environment.) 

UiInit function is a special event handler function that gets called once, 
after plugin reports as ready, and before other event handler functions are 
called. UiInit function would be a good place to extend default WebAdmin UI 
(adding main tab, etc.). 

This is illustrated on the following use case: 

    1. user requests WebAdmin page, during initialization a plugin iframe gets 
created and attached to DOM, plugin HTML page gets requested asynchronously, 
application init code still runs so iframe plugin code evaluation is blocked 
(this is because of JavaScript runtime being single-threaded in its nature) 
    2. application init code finishes, plugin code gets evaluated, plugin 
registers itself into pluginApi.plugins and reports back as ready (calls the 
ready function) 
    3. since the user is still in login section (not logged into WebAdmin), 
plugin invocation is disabled, until the user logs in 
    4. user logs into the application, UI redirects to main section, and after 
UI gets initialized, plugin invocation is enabled 
    5. UiInit function is called on the plugin 
    6. <NOT IMPLEMENTED YET> user performs some actions and WebAdmin calls 
different functions on the plugin 
    7. assume the user logs out, plugin invocation is disabled, until the user 
logs in again 
    8. user logs in again, but UiInit isn't called now because it has been 
called already before 
    9. goto step 6 

The reason why UiInit is called just once (after visiting main section for the 
first time), is because WebAdmin UI (Views) are mostly singletons, so even when 
you switch to different section (login section) and go to main section again, 
singleton Views will still be there, with any adjustments/extensions made 
previously by plugins. 

Now, as for the next steps, we can proceed with actual tasks Itamar outlined in 
his email: 

    * use UiInit event to extend UI (add main tab, etc.) 
    * define other events (table context menu event, etc.) 
    * allow plugins to do REST API calls through pluginApi object 

I've tried to implement "add main tab" functionality. Unfortunately, this isn't 
quite easy to do with GWT-Platform (GWTP) framework we use. Each tab in 
WebAdmin has some place (GWT history token = URL hash fragment) associated. The 
way GWTP handles tabs is that individual tabs (Presenter) reveal themselves 
into tab container (TabContainerPresenter), with presenter reveal flow being 
processed bottom-up. I strongly suggest to go through 
[http://code.google.com/p/gwt-platform/wiki/GettingStarted] to get some basic 
understanding of GWTP framework and how tabs work in general. 

Long story short, to add tabs dynamically in a proper way, we need to write 
custom presenter proxy, here are some links on this matter: 
Discussion 
[https://groups.google.com/forum/#!topic/gwt-platform/aJrGOf9Gu04/discussion ] 
Dynamic tab example 
[http://code.google.com/r/goudreauchristian-update/source/browse/ ] 
Working demo [http://olivier.monaco.free.fr/lab/gwtp-editor/] 

So adding main/sub tabs is a task that will require some additional work, 
especially since we wish to combine both static tabs and dynamic tabs in one 
tab container. I'll try to work on this one. 

On the other hand, it would be great if others could take the latest PoC patch 
(attached), and experiment with other stuff like context menu events, REST API 
calls, etc. You can always reach me on #ovirt (vszocs) if you have a question 
or need help with anything. 

Cheers, 
Vojtech 

Attachment: myPlugin.js.example
Description: Binary data

From 68a36755c1f8588224de0ce36910c574b33a64e6 Mon Sep 17 00:00:00 2001
From: Vojtech Szocs <vsz...@redhat.com>
Date: Thu, 19 Jul 2012 14:48:40 +0200
Subject: [PATCH] WIP: UI Plugins PoC, revision 2

Change-Id: Id28812ddbe90574de0178f0c07da713fe9fd8cda
Signed-off-by: Vojtech Szocs <vsz...@redhat.com>
---
 .../server/gwt/GwtDynamicHostPageServlet.java      |    1 +
 .../server/gwt/PluginSourcePageServlet.java        |  111 +++++++++++
 .../server/gwt/WebadminDynamicHostingServlet.java  |    4 +
 .../ovirt/engine/ui/webadmin/gin/SystemModule.java |    4 +
 .../ui/webadmin/plugin/PluginDefinitions.java      |   30 +++
 .../ui/webadmin/plugin/PluginEventHandler.java     |   23 +++
 .../engine/ui/webadmin/plugin/PluginManager.java   |  199 ++++++++++++++++++++
 .../main/presenter/MainSectionPresenter.java       |   17 ++-
 .../webadmin/src/main/webapp/WEB-INF/web.xml       |   10 +
 9 files changed, 398 insertions(+), 1 deletions(-)
 create mode 100644 frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/PluginSourcePageServlet.java
 create mode 100644 frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginDefinitions.java
 create mode 100644 frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginEventHandler.java
 create mode 100644 frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginManager.java

diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GwtDynamicHostPageServlet.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GwtDynamicHostPageServlet.java
index f19739a..685e685 100644
--- a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GwtDynamicHostPageServlet.java
+++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GwtDynamicHostPageServlet.java
@@ -46,6 +46,7 @@ public abstract class GwtDynamicHostPageServlet extends HttpServlet {
     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
         PrintWriter writer = response.getWriter();
         response.setContentType("text/html; charset=UTF-8"); //$NON-NLS-1$
+        response.setHeader("Cache-Control", "no-cache"); //$NON-NLS-1$ //$NON-NLS-2$
 
         writer.append("<!DOCTYPE html><html><head>"); //$NON-NLS-1$
         writer.append("<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">"); //$NON-NLS-1$
diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/PluginSourcePageServlet.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/PluginSourcePageServlet.java
new file mode 100644
index 0000000..b0342a8
--- /dev/null
+++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/PluginSourcePageServlet.java
@@ -0,0 +1,111 @@
+package org.ovirt.engine.ui.frontend.server.gwt;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Renders the HTML source page for the given UI plugin.
+ */
+public class PluginSourcePageServlet extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Log logger = LogFactory.getLog(PluginSourcePageServlet.class);
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        // Read plugin name as HTTP request parameter
+        String pluginName = request.getParameter("plugin"); //$NON-NLS-1$
+        if (pluginName == null) {
+            logger.error("Missing plugin name request parameter"); //$NON-NLS-1$
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+
+        // Locate plugin code in local file system
+        // TODO hard-coded plugin location
+        File pluginCodeLocation = new File("/home/vszocs/Downloads"); //$NON-NLS-1$
+        File pluginCodeFile = new File(pluginCodeLocation, pluginName + ".js"); //$NON-NLS-1$
+        if (!pluginCodeFile.isFile() || !pluginCodeFile.canRead()) {
+            logger.error("Cannot read plugin code: " + pluginCodeFile.getAbsolutePath()); //$NON-NLS-1$
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+
+        // TODO simulate plugin dependencies
+        List<String> pluginDependencyList =
+                Arrays.asList("https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js";); //$NON-NLS-1$
+
+        // TODO simulate plugin configuration
+        String pluginConfigurationObject = "{ \"foo\": 123 }"; //$NON-NLS-1$
+
+        // Render HTML source page to the output
+        response.setContentType("text/html; charset=UTF-8"); //$NON-NLS-1$
+        response.setHeader("Cache-Control", "no-cache"); //$NON-NLS-1$ //$NON-NLS-2$
+
+        Reader in = null;
+        Writer out = null;
+
+        try {
+            in = new BufferedReader(new InputStreamReader(new FileInputStream(pluginCodeFile), "UTF-8")); //$NON-NLS-1$
+            out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), "UTF-8")); //$NON-NLS-1$
+
+            renderPluginSourcePage(in, pluginDependencyList, pluginConfigurationObject, out);
+            out.flush();
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+    void renderPluginSourcePage(Reader pluginCodeInput, List<String> pluginDependencyList,
+            String pluginConfigurationObject, Writer output) throws IOException {
+        output.write("<!DOCTYPE html><html><head>"); //$NON-NLS-1$
+        output.write("<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">"); //$NON-NLS-1$
+
+        for (String dependency : pluginDependencyList) {
+            output.write("<script type=\"text/javascript\" src=\""); //$NON-NLS-1$
+            output.write(dependency);
+            output.write("\"></script>"); //$NON-NLS-1$
+        }
+
+        output.write("</head><body>"); //$NON-NLS-1$
+        output.write("<script type=\"text/javascript\">"); //$NON-NLS-1$
+        output.write("(function( pluginApi, pluginConfig ) {"); //$NON-NLS-1$
+
+        copyChars(pluginCodeInput, output);
+
+        output.write("}) ( parent.pluginApi, "); //$NON-NLS-1$
+        output.write(pluginConfigurationObject);
+        output.write(" );"); //$NON-NLS-1$
+        output.write("</script>"); //$NON-NLS-1$
+        output.write("</body></html>"); //$NON-NLS-1$
+    }
+
+    void copyChars(Reader in, Writer out) throws IOException {
+        char[] buffer = new char[4 * 1024]; // Use 4 kB buffer
+        int numRead = 0;
+
+        while ((numRead = in.read(buffer, 0, buffer.length)) > 0) {
+            out.write(buffer, 0, numRead);
+        }
+    }
+
+}
diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/WebadminDynamicHostingServlet.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/WebadminDynamicHostingServlet.java
index 428dcc5..dcaf49a 100644
--- a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/WebadminDynamicHostingServlet.java
+++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/WebadminDynamicHostingServlet.java
@@ -36,6 +36,10 @@ public class WebadminDynamicHostingServlet extends GwtDynamicHostPageServlet {
             appModeData.put("value", String.valueOf(applicationMode)); //$NON-NLS-1$
             writeJsObject(writer, "applicationMode", appModeData); //$NON-NLS-1$
         }
+
+        Map<String, String> pluginDefinitions = new HashMap<String, String>();
+        pluginDefinitions.put("myPlugin", "/webadmin/webadmin/PluginSourcePage?plugin=myPlugin"); //$NON-NLS-1$ //$NON-NLS-2$
+        writeJsObject(writer, "pluginDefinitions", pluginDefinitions); //$NON-NLS-1$
     }
 
     private Integer getApplicationMode(HttpServletRequest request) {
diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/SystemModule.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/SystemModule.java
index 3069b99..b049683 100644
--- a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/SystemModule.java
+++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/SystemModule.java
@@ -9,6 +9,8 @@ import org.ovirt.engine.ui.webadmin.ApplicationResources;
 import org.ovirt.engine.ui.webadmin.ApplicationTemplates;
 import org.ovirt.engine.ui.webadmin.place.ApplicationPlaces;
 import org.ovirt.engine.ui.webadmin.place.WebAdminPlaceManager;
+import org.ovirt.engine.ui.webadmin.plugin.PluginEventHandler;
+import org.ovirt.engine.ui.webadmin.plugin.PluginManager;
 import org.ovirt.engine.ui.webadmin.system.ApplicationInit;
 import org.ovirt.engine.ui.webadmin.system.InternalConfiguration;
 
@@ -31,6 +33,8 @@ public class SystemModule extends BaseSystemModule {
         bind(PlaceManager.class).to(WebAdminPlaceManager.class).in(Singleton.class);
         bind(ApplicationInit.class).asEagerSingleton();
         bind(InternalConfiguration.class).asEagerSingleton();
+        bind(PluginManager.class).asEagerSingleton();
+        bind(PluginEventHandler.class).asEagerSingleton();
     }
 
     void bindConfiguration() {
diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginDefinitions.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginDefinitions.java
new file mode 100644
index 0000000..d1118cb
--- /dev/null
+++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginDefinitions.java
@@ -0,0 +1,30 @@
+package org.ovirt.engine.ui.webadmin.plugin;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+
+/**
+ * Overlay type for {@code pluginDefinitions} global JS object.
+ */
+public final class PluginDefinitions extends JavaScriptObject {
+
+    protected PluginDefinitions() {
+    }
+
+    public static native PluginDefinitions instance() /*-{
+        return $wnd.pluginDefinitions;
+    }-*/;
+
+    public native JsArrayString getPluginNames() /*-{
+        var pluginNames = [];
+        for (var key in this) {
+            pluginNames.push(key);
+        }
+        return pluginNames;
+    }-*/;
+
+    public native String getPluginSourcePageUrl(String pluginName) /*-{
+        return this[pluginName];
+    }-*/;
+
+}
diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginEventHandler.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginEventHandler.java
new file mode 100644
index 0000000..cbafb2f
--- /dev/null
+++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginEventHandler.java
@@ -0,0 +1,23 @@
+package org.ovirt.engine.ui.webadmin.plugin;
+
+import com.google.gwt.event.shared.EventBus;
+import com.google.inject.Inject;
+
+/**
+ * Handles WebAdmin application events (extension points) to be consumed by UI plugins.
+ * <p>
+ * Should be bound as GIN eager singleton, created early on during application startup.
+ */
+public class PluginEventHandler {
+
+    @Inject
+    public PluginEventHandler(EventBus eventBus, PluginManager manager) {
+//        eventBus.addHandler(ExtUserLoginEvent.getType(), new ExtUserLoginHandler() {
+//            @Override
+//            public void onExtUserLogin(ExtUserLoginEvent event) {
+//                invokePlugins("UserLogin");
+//            }
+//        });
+    }
+
+}
diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginManager.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginManager.java
new file mode 100644
index 0000000..5663a09
--- /dev/null
+++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/plugin/PluginManager.java
@@ -0,0 +1,199 @@
+package org.ovirt.engine.ui.webadmin.plugin;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.IFrameElement;
+import com.google.gwt.dom.client.Style.BorderStyle;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.Style.Unit;
+
+/**
+ * The main component of WebAdmin UI plugin infrastructure.
+ * <p>
+ * Should be bound as GIN eager singleton, created early on during application startup.
+ */
+public class PluginManager {
+
+    private static final Logger logger = Logger.getLogger(PluginManager.class.getName());
+
+    // Maps plugin names to corresponding iframe elements
+    private final Map<String, IFrameElement> pluginIFrames = new HashMap<String, IFrameElement>();
+
+    // Maps plugin names to corresponding plugin objects (only for plugins which are currently ready)
+    private final Map<String, JavaScriptObject> pluginObjects = new HashMap<String, JavaScriptObject>();
+
+    // Contains plugin names for plugins that have been initialized
+    // (UiInit event handler function was already called on corresponding plugin objects)
+    private final Set<String> initializedPlugins = new HashSet<String>();
+
+    // Controls plugin invocation, allowing WebAdmin to call plugins only within a specific application context
+    private boolean canInvokePlugins = false;
+
+    public PluginManager() {
+        exposePluginApi();
+        loadPlugins();
+    }
+
+    /**
+     * Called when WebAdmin enters the state that allows plugins to be invoked.
+     */
+    public void enablePluginInvocation() {
+        canInvokePlugins = true;
+
+        // Try to initialize all plugins which are currently ready
+        for (String pluginName : pluginObjects.keySet()) {
+            initPlugin(pluginName);
+        }
+    }
+
+    /**
+     * Called when WebAdmin leaves the state that allows plugins to be invoked.
+     */
+    public void disablePluginInvocation() {
+        canInvokePlugins = false;
+    }
+
+    boolean isPluginReady(String pluginName) {
+        return pluginObjects.containsKey(pluginName);
+    }
+
+    boolean isPluginInitialized(String pluginName) {
+        return initializedPlugins.contains(pluginName);
+    }
+
+    /**
+     * Initialize the given plugin by calling UiInit event handler function on the corresponding plugin object.
+     * <p>
+     * Note that UiInit event handler function will be called just once during the lifetime of a plugin.
+     */
+    void initPlugin(String pluginName) {
+        if (canInvokePlugins && isPluginReady(pluginName) && !isPluginInitialized(pluginName)) {
+            JavaScriptObject pluginObject = pluginObjects.get(pluginName);
+            invokePlugin(pluginObject, "UiInit", null); //$NON-NLS-1$
+
+            initializedPlugins.add(pluginName);
+        }
+    }
+
+    /**
+     * Invokes an event handler function on all plugins which are currently ready.
+     */
+    public void invokePlugins(String functionName, JavaScriptObject contextObject) {
+        if (canInvokePlugins) {
+            for (String pluginName : pluginObjects.keySet()) {
+                if (isPluginInitialized(pluginName)) {
+                    invokePlugin(pluginObjects.get(pluginName), functionName, contextObject);
+                }
+            }
+        }
+    }
+
+    /**
+     * Invokes an event handler function on the given plugin object.
+     */
+    private native void invokePlugin(JavaScriptObject pluginObject, String functionName, JavaScriptObject contextObject) /*-{
+        var handlerFunction = pluginObject[functionName];
+
+        if (typeof handlerFunction === 'function') {
+            if (contextObject != null) {
+                handlerFunction(contextObject);
+            } else {
+                handlerFunction();
+            }
+        }
+    }-*/;
+
+    /**
+     * Loads all plugins that were detected when serving WebAdmin host page.
+     */
+    void loadPlugins() {
+        PluginDefinitions defs = PluginDefinitions.instance();
+
+        if (defs != null) {
+            JsArrayString pluginNames = defs.getPluginNames();
+
+            for (int i = 0; i < pluginNames.length(); i++) {
+                String name = pluginNames.get(i);
+                String sourcePageUrl = defs.getPluginSourcePageUrl(name);
+
+                logger.info("Loading plugin [" + name + "] from URL " + sourcePageUrl); //$NON-NLS-1$ //$NON-NLS-2$
+                loadPlugin(name, sourcePageUrl);
+            }
+        }
+    }
+
+    /**
+     * Loads a plugin using its source page (HTML page that executes the actual plugin code).
+     * <p>
+     * WebAdmin requires all plugins to have a source page because each plugin runs within the context of an iframe.
+     */
+    void loadPlugin(String pluginName, String pluginSourcePageUrl) {
+        if (pluginIFrames.containsKey(pluginName)) {
+            logger.warning("Plugin [" + pluginName + "] is already loaded"); //$NON-NLS-1$ //$NON-NLS-2$
+            return;
+        }
+
+        // Create an iframe used to load the plugin source page
+        IFrameElement iframe = Document.get().createIFrameElement();
+        iframe.setSrc(pluginSourcePageUrl);
+        iframe.setFrameBorder(0);
+        iframe.getStyle().setPosition(Position.ABSOLUTE);
+        iframe.getStyle().setWidth(0, Unit.PT);
+        iframe.getStyle().setHeight(0, Unit.PT);
+        iframe.getStyle().setBorderStyle(BorderStyle.NONE);
+        pluginIFrames.put(pluginName, iframe);
+
+        // Attach the iframe to DOM document body
+        Document.get().getBody().appendChild(iframe);
+    }
+
+    /**
+     * Indicates that the given plugin is ready for use.
+     */
+    void pluginReady(String pluginName, JavaScriptObject pluginObject) {
+        if (pluginName == null) {
+            logger.warning("Plugin name is null or undefined"); //$NON-NLS-1$
+            return;
+        }
+
+        if (!pluginIFrames.containsKey(pluginName)) {
+            logger.warning("Plugin [" + pluginName + "] reports in as ready, but has no iframe associated"); //$NON-NLS-1$ //$NON-NLS-2$
+            return;
+        }
+
+        // Register the plugin object
+        pluginObjects.put(pluginName, pluginObject);
+        logger.info("Plugin [" + pluginName + "] is ready for use"); //$NON-NLS-1$ //$NON-NLS-2$
+
+        // Try to initialize the plugin
+        initPlugin(pluginName);
+    }
+
+    private native void exposePluginApi() /*-{
+        var instance = this;
+
+        // Expose the global pluginApi object
+        $wnd.pluginApi = {
+
+            // Plugins will register themselves into this object by adding new property:
+            // - property name is the name of the plugin
+            // - property value is the plugin object containing event handler functions
+            plugins: {},
+
+            // Plugins will call this function to indicate that they are ready for use
+            ready: function(pluginName) {
+                var pluginObject = this.plugins[pluginName];
+                instan...@org.ovirt.engine.ui.webadmin.plugin.PluginManager::pluginReady(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(pluginName,pluginObject);
+            }
+
+        };
+    }-*/;
+
+}
diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/MainSectionPresenter.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/MainSectionPresenter.java
index 718d8fc..15b887c 100644
--- a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/MainSectionPresenter.java
+++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/presenter/MainSectionPresenter.java
@@ -1,5 +1,7 @@
 package org.ovirt.engine.ui.webadmin.section.main.presenter;
 
+import org.ovirt.engine.ui.webadmin.plugin.PluginManager;
+
 import com.google.gwt.event.shared.EventBus;
 import com.google.gwt.event.shared.GwtEvent.Type;
 import com.google.inject.Inject;
@@ -28,11 +30,13 @@ public class MainSectionPresenter extends Presenter<MainSectionPresenter.ViewDef
     public static final Type<RevealContentHandler<?>> TYPE_SetMainContent = new Type<RevealContentHandler<?>>();
 
     private final HeaderPresenterWidget header;
+    private final PluginManager pluginManager;
 
     @Inject
-    public MainSectionPresenter(EventBus eventBus, ViewDef view, ProxyDef proxy, HeaderPresenterWidget header) {
+    public MainSectionPresenter(EventBus eventBus, ViewDef view, ProxyDef proxy, HeaderPresenterWidget header, PluginManager pluginManager) {
         super(eventBus, view, proxy);
         this.header = header;
+        this.pluginManager = pluginManager;
         getView().setUiHandlers(header);
     }
 
@@ -46,6 +50,17 @@ public class MainSectionPresenter extends Presenter<MainSectionPresenter.ViewDef
         super.onReveal();
 
         setInSlot(TYPE_SetHeader, header);
+
+        // Enable plugin invocation within the scope of main section
+        pluginManager.enablePluginInvocation();
+    }
+
+    @Override
+    protected void onHide() {
+        super.onHide();
+
+        // Disable plugin invocation outside the scope of main section
+        pluginManager.disablePluginInvocation();
     }
 
 }
diff --git a/frontend/webadmin/modules/webadmin/src/main/webapp/WEB-INF/web.xml b/frontend/webadmin/modules/webadmin/src/main/webapp/WEB-INF/web.xml
index a50f8aa..62f0312 100644
--- a/frontend/webadmin/modules/webadmin/src/main/webapp/WEB-INF/web.xml
+++ b/frontend/webadmin/modules/webadmin/src/main/webapp/WEB-INF/web.xml
@@ -23,6 +23,16 @@
 		<url-pattern>/webadmin/WebAdmin.html</url-pattern>
 	</servlet-mapping>
 
+	<servlet>
+		<servlet-name>PluginSourcePage</servlet-name>
+		<servlet-class>org.ovirt.engine.ui.frontend.server.gwt.PluginSourcePageServlet</servlet-class>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>PluginSourcePage</servlet-name>
+		<url-pattern>/webadmin/PluginSourcePage</url-pattern>
+	</servlet-mapping>
+
 	<!-- Default page to serve -->
 	<welcome-file-list>
 		<welcome-file>index.html</welcome-file>
-- 
1.7.4.4

_______________________________________________
Engine-devel mailing list
Engine-devel@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-devel

Reply via email to