You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by da...@apache.org on 2015/07/02 13:09:06 UTC

svn commit: r1688806 - in /felix/trunk/webconsole-plugins/subsystems: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/webconsole/ src/main/java/org/apache/feli...

Author: davidb
Date: Thu Jul  2 11:09:06 2015
New Revision: 1688806

URL: http://svn.apache.org/r1688806
Log:
FELIX-4947 Webconsole plugin for OSGi Subsystems

Initial commit with basic functionality working. This plugin was highly inspired by the existing web console bundles page.

Added:
    felix/trunk/webconsole-plugins/subsystems/
    felix/trunk/webconsole-plugins/subsystems/pom.xml
    felix/trunk/webconsole-plugins/subsystems/src/
    felix/trunk/webconsole-plugins/subsystems/src/main/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java
    felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html
    felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js

Added: felix/trunk/webconsole-plugins/subsystems/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/pom.xml?rev=1688806&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/subsystems/pom.xml (added)
+++ felix/trunk/webconsole-plugins/subsystems/pom.xml Thu Jul  2 11:09:06 2015
@@ -0,0 +1,109 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>felix-parent</artifactId>
+        <version>2.1</version>
+        <relativePath>../../../pom/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.felix.webconsole.plugins.subsystems</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <name>Apache Felix Web Console Subsystes Plugin</name>
+    <description>
+        This is a plugin for the Apache Felix OSGi web console to integrate with OSGi Subsystems.
+    </description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.4</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>
+                            ${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Bundle-Activator>
+                            org.apache.felix.webconsole.plugins.subsystem.internal.Activator
+                        </Bundle-Activator>
+                        <Private-Package>
+                            org.apache.felix.webconsole.plugins.subsystem.*
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                        <source>1.6</source>
+                        <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>1.2.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20070829</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>5.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>5.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.webconsole</artifactId>
+            <version>4.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

Added: felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java?rev=1688806&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java (added)
+++ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java Thu Jul  2 11:09:06 2015
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.webconsole.plugins.subsystem.internal;
+
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+    private SimpleWebConsolePlugin plugin;
+
+    public void start(BundleContext context) throws Exception
+    {
+        plugin = new WebConsolePlugin(context).register();
+    }
+
+    public void stop(BundleContext context) throws Exception
+    {
+        plugin = null;
+    }
+
+    /*
+    public synchronized URLStreamHandlerService addingService(ServiceReference<URLStreamHandlerService> reference)
+    {
+        SimpleWebConsolePlugin p = plugin;
+        if (p == null)
+        {
+            URLStreamHandlerService svc = bundleContext.getService(reference);
+            plugin = new WebConsolePlugin(svc).register(bundleContext);
+        }
+        return bundleContext.getService(reference);
+    }
+
+    public void modifiedService(ServiceReference<URLStreamHandlerService> reference, URLStreamHandlerService service)
+    {
+        // Unused
+    }
+
+    public synchronized void removedService(ServiceReference<URLStreamHandlerService> reference, URLStreamHandlerService service)
+    {
+        if (plugin != null)
+        {
+            plugin.unregister();
+            plugin = null;
+        }
+    }
+    */
+}
+
+//public class Activator implements BundleActivator
+//{
+//    private SubsystemPluginServlet plugin;
+//
+//    public void start(final BundleContext context) throws Exception
+//    {
+//        plugin = new SubsystemPluginServlet();
+//
+////        // now we create the listener
+////        this.eventListener = new EventListener(this.plugin, context);
+////
+////        // and the optional features handler
+////        this.featuresHandler = new OptionalFeaturesHandler(this.plugin, context);
+//
+//        // finally we register the plugin
+//        final Dictionary props = new Hashtable();
+//        props.put( Constants.SERVICE_DESCRIPTION, "Subsystems Plugin for the Apache Felix Web Console" );
+//        props.put( "felix.webconsole.label", "subsystems");
+//        props.put( "felix.webconsole.title", "Subsystems");
+////        props.put( "felix.webconsole.css", "/events/res/ui/events.css");
+//        props.put( "felix.webconsole.category", "OSGi");
+//        context.registerService(Servlet.class.getName(),
+//                                plugin,
+//                                props);
+//    }
+//
+//    /**
+//     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+//     */
+//    public void stop(final BundleContext context) throws Exception
+//    {
+////        if ( this.pluginRegistration != null )
+////        {
+////            this.pluginRegistration.unregister();
+////            this.pluginRegistration = null;
+////        }
+////        if ( this.eventListener != null )
+////        {
+////            this.eventListener.destroy();
+////            eventListener = null;
+////        }
+////        if ( this.featuresHandler != null)
+////        {
+////            this.featuresHandler.destroy();
+////            this.featuresHandler = null;
+////        }
+////        if ( this.plugin != null ) {
+////            this.plugin.destroy();
+////            this.plugin = null;
+////        }
+//    }
+//}

Added: felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java?rev=1688806&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java (added)
+++ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java Thu Jul  2 11:09:06 2015
@@ -0,0 +1,431 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.webconsole.plugins.subsystem.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.DefaultVariableResolver;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
+import org.apache.felix.webconsole.WebConsoleUtil;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+
+public class WebConsolePlugin extends SimpleWebConsolePlugin
+{
+    private static final long serialVersionUID = 4329827842860201817L;
+    private static final String UNABLE_TO_FIND_TARGET_SUBSYSTEM = "Unable to find target subsystem";
+
+    private static final String LABEL = "subsystems";
+    private static final String TITLE = "Subsystems";
+    private static final String CATEGORY = "OSGi";
+    private static final String CSS[] = { "/res/ui/bundles.css" }; // yes, it's correct!
+    private static final String RES = "/" + LABEL + "/res/";
+
+    private final BundleContext bundleContext;
+    private final String template;
+
+    public WebConsolePlugin(BundleContext bc)
+    {
+        super(LABEL, TITLE, CSS);
+        bundleContext = bc;
+
+        template = readTemplateFile("/res/plugin.html");
+    }
+
+    @Override
+    public String getCategory()
+    {
+        return CATEGORY;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String path = request.getPathInfo();
+        // don't process if this is request to load a resource
+        if (!path.startsWith(RES))
+        {
+            RequestInfo reqInfo = new RequestInfo(request);
+            if (reqInfo.extension.equals("json"))
+            {
+                renderResult(response, reqInfo);
+
+                // nothing more to do
+                return;
+            }
+        }
+        super.doGet(request, response);
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+    {
+        String action = WebConsoleUtil.getParameter(req, "action");
+        if ("install".equals(action))
+        {
+            installSubsystem(req);
+
+            if (req.getRequestURI().endsWith("/install")) {
+                // just send 200/OK, no content
+                resp.setContentLength( 0 );
+            } else {
+                // redirect to URL
+                resp.sendRedirect(req.getRequestURI());
+            }
+
+            return;
+        }
+        else
+        {
+            boolean success = false;
+            RequestInfo reqInfo = new RequestInfo(req);
+            if ("start".equals(action))
+            {
+                startSubsystem(reqInfo.id);
+                success = true;
+            }
+            else if ("stop".equals(action))
+            {
+                stopSubsystem(reqInfo.id);
+                success = true;
+            }
+            else if ("uninstall".equals(action))
+            {
+                uninstallSubsystem(reqInfo.id);
+                success = true;
+            }
+            else
+            {
+                super.doPost(req, resp);
+            }
+
+            if (success)
+            {
+                renderResult(resp, reqInfo);
+            }
+        }
+    }
+
+    private void installSubsystem(HttpServletRequest req) throws IOException
+    {
+        @SuppressWarnings("rawtypes")
+        Map params = (Map) req.getAttribute( AbstractWebConsolePlugin.ATTR_FILEUPLOAD );
+
+        FileItem[] subsystemItems = getFileItems(params, "subsystemfile");
+
+        for (final FileItem subsystemItem : subsystemItems)
+        {
+            File tmpFile = null;
+            try
+            {
+                // copy the data to a file for better processing
+                tmpFile = File.createTempFile("installSubsystem", ".tmp");
+                subsystemItem.write(tmpFile);
+            }
+            catch (Exception e)
+            {
+                log(LogService.LOG_ERROR, "Problem accessing uploaded subsystem file: " + subsystemItem.getName(), e);
+
+                // remove the temporary file
+                if (tmpFile != null)
+                {
+                    tmpFile.delete();
+                    tmpFile = null;
+                }
+            }
+
+            if (tmpFile != null)
+            {
+                final File file = tmpFile;
+                // TODO support install in other subsystems than the root one
+                // TODO currently this means that when installing more than one subsystem they
+                // will be installed concurrently. Not sure if this is the best idea.
+                // However the client UI does not support selecting more than one file, so
+                // from a practical point of view this is currently not an issue.
+                asyncSubsystemOperation(0, new SubsystemOperation()
+                {
+                    @Override
+                    public void exec(Subsystem ss)
+                    {
+                        try
+                        {
+                            InputStream is = new FileInputStream(file);
+                            try
+                            {
+                                ss.install("inputstream:" + subsystemItem.getName(), is);
+                            }
+                            finally
+                            {
+                                is.close();
+                                file.delete();
+                            }
+                        }
+                        catch (IOException e)
+                        {
+                            log(LogService.LOG_ERROR, "Problem installing subsystem", e);
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    private void startSubsystem(long id) throws IOException
+    {
+        asyncSubsystemOperation(id, new SubsystemOperation()
+        {
+            // Lamba, where art thou. So close yet so far away...
+            @Override
+            public void exec(Subsystem ss)
+            {
+                ss.start();
+            }
+        });
+    }
+
+    private void stopSubsystem(long id) throws IOException
+    {
+        asyncSubsystemOperation(id, new SubsystemOperation()
+        {
+            @Override
+            public void exec(Subsystem ss)
+            {
+                ss.stop();
+            }
+        });
+    }
+
+    private void uninstallSubsystem(long id) throws IOException
+    {
+        asyncSubsystemOperation(id, new SubsystemOperation()
+        {
+            @Override
+            public void exec(Subsystem ss)
+            {
+                ss.uninstall();
+            }
+        });
+    }
+
+    private void asyncSubsystemOperation(long id, final SubsystemOperation op) throws IOException
+    {
+        try
+        {
+            Collection<ServiceReference<Subsystem>> refs =
+                    bundleContext.getServiceReferences(Subsystem.class,
+                            "(" + SubsystemConstants.SUBSYSTEM_ID_PROPERTY + "=" + id + ")");
+
+            if (refs.size() < 1)
+                throw new IOException(UNABLE_TO_FIND_TARGET_SUBSYSTEM);
+
+            final ServiceReference<Subsystem> ref = refs.iterator().next();
+            new Thread(new Runnable() {
+                @Override
+                public void run()
+                {
+                    Subsystem ss = bundleContext.getService(ref);
+                    try
+                    {
+                        op.exec(ss);
+                    }
+                    finally
+                    {
+                        bundleContext.ungetService(ref);
+                    }
+                }
+            }).start();
+        }
+        catch (InvalidSyntaxException e)
+        {
+            throw new IOException(e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private FileItem[] getFileItems(Map params, String name)
+    {
+        final List<FileItem> files = new ArrayList<FileItem>();
+        FileItem[] items = (FileItem[]) params.get( name );
+        if ( items != null )
+        {
+            for ( int i = 0; i < items.length; i++ )
+            {
+                if (!items[i].isFormField() && items[i].getSize() > 0)
+                {
+                    files.add(items[i]);
+                }
+            }
+        }
+
+        return files.toArray( new FileItem[files.size()] );
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void renderContent(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
+    {
+        RequestInfo reqInfo = getRequestInfo(req);
+
+        StringWriter w = new StringWriter();
+        PrintWriter w2 = new PrintWriter(w);
+        renderResult(w2, reqInfo);
+
+        // prepare variables
+        DefaultVariableResolver vars = ((DefaultVariableResolver) WebConsoleUtil.getVariableResolver(req));
+        vars.put("__data__", w.toString());
+
+        res.getWriter().print(template);
+    }
+
+    private void renderResult(HttpServletResponse response, RequestInfo reqInfo) throws IOException
+    {
+        response.setContentType("application/json");
+        response.setCharacterEncoding("UTF-8");
+        renderResult(response.getWriter(), reqInfo);
+    }
+
+    private void renderResult(PrintWriter pw, RequestInfo reqInfo) throws IOException
+    {
+        JSONWriter jw = new JSONWriter(pw);
+        try
+        {
+            jw.object();
+
+            List<Subsystem> subsystems = getSubsystems();
+
+            jw.key("status");
+            jw.value(subsystems.size());
+
+            jw.key("data");
+            jw.array();
+            for (Subsystem ss : subsystems)
+            {
+                subsystem(jw, ss);
+            }
+            jw.endArray();
+
+            jw.endObject();
+        }
+        catch (JSONException je)
+        {
+            throw new IOException(je);
+        }
+    }
+
+    private void subsystem(JSONWriter jw, Subsystem ss) throws JSONException
+    {
+        jw.object();
+
+        jw.key("id");
+        jw.value(ss.getSubsystemId());
+        jw.key("name");
+        jw.value(ss.getSymbolicName());
+        jw.key("version");
+        jw.value(ss.getVersion());
+        jw.key("state");
+        jw.value(ss.getState());
+
+        jw.endObject();
+    }
+
+    private List<Subsystem> getSubsystems() throws IOException
+    {
+        try
+        {
+            List<Subsystem> l = new ArrayList<Subsystem>();
+            for (ServiceReference<Subsystem> ref : bundleContext.getServiceReferences(Subsystem.class, null))
+            {
+                l.add(bundleContext.getService(ref));
+            }
+            return l;
+        }
+        catch (InvalidSyntaxException e)
+        {
+            throw new IOException(e);
+        }
+    }
+
+    public SimpleWebConsolePlugin register()
+    {
+        return register(bundleContext);
+    }
+
+    static RequestInfo getRequestInfo(HttpServletRequest request)
+    {
+        return (RequestInfo) request.getAttribute(WebConsolePlugin.class.getName());
+    }
+
+    class RequestInfo
+    {
+        public final long id;
+        public final Object extension;
+
+        protected RequestInfo(HttpServletRequest req)
+        {
+            String info = req.getPathInfo();
+            // remove label and starting slash
+            info = info.substring(getLabel().length() + 1);
+
+            // get extension
+            if (info.endsWith(".json"))
+            {
+                extension = "json";
+                info = info.substring(0, info.length() - 5);
+            }
+            else
+            {
+                extension = "html";
+            }
+
+            if (info.startsWith("/"))
+                info = info.substring(1);
+
+            if ("".equals(info))
+                id = -1;
+            else
+                id = Long.parseLong(info);
+
+            req.setAttribute(WebConsolePlugin.this.getClass().getName(), this);
+        }
+    }
+
+    interface SubsystemOperation
+    {
+        void exec(Subsystem ss);
+    }
+}

Added: felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties?rev=1688806&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties (added)
+++ felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties Thu Jul  2 11:09:06 2015
@@ -0,0 +1,32 @@
+#Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Web Console strings for reference all strings here are commented.
+# This file may be used to produce a translation of the strings
+#
+# Note that properties files are ISO-8859-1 encoded. To provide translations
+# for languages requiring different character encodings, you may use the
+# native2ascii Maven Plugin from http://mojo.codehaus.org/native2ascii-maven-plugin/
+# to translate the natively encoded files to ISO-8859-1 during bundle build
+#
+# Translations requiring non-ISO-8859-1 encoding are placed in the
+# src/main/native2ascii/OSGI-INF/l10n folder and are converted using said
+# plugin while building the bundle
+#
+
+# Components plugin
+subsystems.name=Subsystem Name
+

Added: felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html?rev=1688806&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html (added)
+++ felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html Thu Jul  2 11:09:06 2015
@@ -0,0 +1,92 @@
+<!-- 
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+ 
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<script type="text/javascript" src="${pluginRoot}/res/plugin.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+var ssData = ${__data__};
+// ]]>
+</script>
+<p class="statline">&nbsp;</p>
+
+
+<div id="subsystems"> <!-- data available -->
+	<!-- top header -->
+	<form method='post' enctype='multipart/form-data' action="${pluginRoot}">
+        <div class="ui-widget-header ui-corner-top buttonGroup">
+            <button class='installButton' type='button'>${install}</button>
+		</div>
+	</form>
+	
+	<table id="plugin_table" class="tablesorter nicetable noauto">
+	<thead>
+		<tr>
+			<th class="col_Id">${id}</th>
+                        <th class="col_Name">${subsystems.name}</th>
+			<th class="col_Version">${version}</th>
+			<th class="col_Status">Status</th>
+			<th class="col_Actions">Actions</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr>
+			<td>&nbsp;</td> <!-- id -->
+			<td> <!-- name with arrow -->
+				<div class="bIcon ui-icon ui-icon-triangle-1-e" style="float:left" title="Details">&nbsp;</div>
+			</td> 
+            <td>&nbsp;</td> <!-- version -->
+			<td>&nbsp;</td> <!-- status -->
+			<td>
+				<ul class="icons">
+					<li class="dynhover ui-helper-hidden" title="${start}"><span class="ui-icon ui-icon-play">&nbsp;</span></li>
+					<li class="dynhover ui-helper-hidden" title="${stop}"><span class="ui-icon ui-icon-stop">&nbsp;</span></li>
+                    <li class="dynhover" title="${bundles.uninstall}"><span class="ui-icon ui-icon-trash">&nbsp;</span></li>
+				</ul>
+			</td>
+		</tr>
+	</tbody>
+	</table>
+</div> <!-- end data available -->
+
+<!-- bottom header -->
+<form method='post' enctype='multipart/form-data' action="${pluginRoot}">
+    <div class="ui-widget-header ui-corner-bottom buttonGroup">
+        <button class='installButton' type='button'>${install}</button>
+	</div>
+</form>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
+
+<div id="uploadDialog" class="ui-helper-hidden" title="Upload / Install Subsystem">
+    <form method="post" enctype="multipart/form-data" action="${pluginRoot}">
+    <table class="nicetable">
+        <tr>
+            <td style="text-align:right">Start Subsystem</td>
+            <td>
+                <input type="hidden" name="action" value="install"/>
+                <input type="checkbox" name="subsystemstart" value="start"/>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <td>&nbsp;</td>
+                <input class="multi" accept="jar|zip|esa" type="file" name="subsystemfile" />
+            </td>
+        </tr>
+    </table>
+    </form>
+</div>

Added: felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js?rev=1688806&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js (added)
+++ felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js Thu Jul  2 11:09:06 2015
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *	  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+function renderData( subsystemData ) {
+	tableBody.empty();
+	for (var idx in subsystemData.data) {
+		entry( subsystemData.data[idx] );
+	}	
+}
+
+function entry( dataEntry ) {
+	var id = dataEntry.id;
+	var name = dataEntry.name;
+	var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'entry' + id);
+	
+	_.find('td:eq(0)').text(id);
+	_.find('td:eq(1)').text(name);
+	_.find('td:eq(2)').text(dataEntry.version);
+	_.find('td:eq(3)').text(dataEntry.state);
+	
+	// setup buttons
+	if (dataEntry.state === "ACTIVE") {
+		_.find('li:eq(1)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(id, 'stop') });
+	} else {
+		_.find('li:eq(0)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(id, 'start') });
+	}
+	_.find('li:eq(2)').click(function() { changeDataEntryState(id, 'uninstall') });
+}
+
+function changeDataEntryState(id, action) {
+	$.post(pluginRoot + '/' + id, {'action': action}, function(data) {
+		renderData(data);
+		
+		// This is a total hack, but it's the only way in which I could get the 
+		// table to re-sort itself. TODO remove the next line and find a proper way.
+		window.location.reload();
+	}, 'json');
+}
+
+var tableBody = false;
+var tableEntryTemplate = false;
+var pluginTable = false;
+var uploadDialog = false;
+
+$(document).ready(function(){
+	$('.installButton').click(function() {
+		uploadDialog.dialog('open');
+		return false;
+	});	
+	
+	pluginTable = $('#plugin_table');
+	tableBody = pluginTable.find('tbody');
+	tableEntryTemplate = tableBody.find('tr').clone();
+	
+	// upload dialog
+	var uploadDialogButtons = {};
+	uploadDialogButtons["Install"] = function() {
+		$(this).find('form').submit();
+	}
+	uploadDialog = $('#uploadDialog').dialog({
+		autoOpen: false,
+		modal   : true,
+		width   : '50%',
+		buttons : uploadDialogButtons
+	});	
+
+	renderData(ssData);
+
+	$('.reloadButton').click(document.location.reload);
+
+	pluginTable.tablesorter({
+		headers: {
+			0: { sorter:'digit'},
+			4: { sorter: false }
+		},
+		sortList: [[1,0]],
+		textExtraction:mixedLinksExtraction
+	});
+});
+