Implemented FELIX-4032 UPnP Plugin small refactoring
https://issues.apache.org/jira/browse/FELIX-4032

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1471282 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Activator.java b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Activator.java
index 65b5d4d..6e11114 100644
--- a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Activator.java
+++ b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Activator.java
@@ -82,11 +82,6 @@
                 new ConfigurationPrinterImpl(tracker), null);

         }

 

-        // delegate event

-        ControlServlet controller = ((WebConsolePlugin) plugin).controller;

-        if (controller != null)

-            controller.addingService(reference);

-

         return context.getService(reference);

     }

 

@@ -103,7 +98,9 @@
         {

             ControlServlet controller = ((WebConsolePlugin) plugin).controller;

             if (controller != null)

-                controller.removedService(reference, service);

+            {

+                controller.removedService(reference);

+            }

         }

 

         if (tracker.size() == 0 && plugin != null)

diff --git a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/ControlServlet.java b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/ControlServlet.java
index ab7ffda..9699dc9 100644
--- a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/ControlServlet.java
+++ b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/ControlServlet.java
@@ -41,18 +41,16 @@
 import org.osgi.service.upnp.UPnPAction;

 import org.osgi.service.upnp.UPnPDevice;

 import org.osgi.service.upnp.UPnPIcon;

-import org.osgi.service.upnp.UPnPLocalStateVariable;

 import org.osgi.service.upnp.UPnPService;

 import org.osgi.service.upnp.UPnPStateVariable;

 import org.osgi.util.tracker.ServiceTracker;

-import org.osgi.util.tracker.ServiceTrackerCustomizer;

 

 /**

  * This class handles requests from the Web Interface. It is separated from

  * the WebConsolePlugin just to improve readability. This servlet actually

  * is not registered in HTTP service.

  */

-public class ControlServlet extends HttpServlet implements ServiceTrackerCustomizer

+public final class ControlServlet extends HttpServlet 

 {

 

     private static final long serialVersionUID = -5789642544511401813L;

@@ -60,10 +58,11 @@
     private static final SimpleDateFormat DATA_FORMAT = new SimpleDateFormat(

         "EEE, d MMM yyyy HH:mm:ss Z"); //$NON-NLS-1$

 

-    final HashMap icons = new HashMap(10);

-    final HashMap sessions = new HashMap(10);

+    private final HashMap/*<String,UPnPDevice>*/ devices = new HashMap(10);

+    private final HashMap/*<String,UPnPIcon>*/ icons = new HashMap(10);

+    private final HashMap/*<String,SessionObject>*/ sessions = new HashMap(10);

 

-    private ServiceTracker tracker;

+    private final ServiceTracker tracker;

     private final BundleContext bc;

 

     private static final long LAST_MODIFIED = System.currentTimeMillis();

@@ -72,7 +71,7 @@
      * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,

      *      javax.servlet.http.HttpServletResponse)

      */

-    protected void doGet(HttpServletRequest request, HttpServletResponse response)

+    protected final void doGet(HttpServletRequest request, HttpServletResponse response)

         throws ServletException, IOException

     {

 

@@ -80,7 +79,7 @@
 

         if (udn != null)

         {

-            UPnPIcon icon = (UPnPIcon) icons.get(udn);

+            UPnPIcon icon = getIcon(udn);

             if (icon == null)

             {

                 response.sendError(HttpServletResponse.SC_NOT_FOUND);

@@ -126,7 +125,7 @@
      * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,

      *      javax.servlet.http.HttpServletResponse)

      */

-    protected void doPost(HttpServletRequest request, HttpServletResponse response)

+    protected final void doPost(HttpServletRequest request, HttpServletResponse response)

         throws ServletException, IOException

     {

         try

@@ -160,7 +159,7 @@
                 SessionObject session = getSession(request)//

                 .subscribe(require("udn", request), service.getId()); //$NON-NLS-1$

 

-                json = serviceToJSON(service, session);

+                json = Serializer.serviceToJSON(service, session);

             }

             else if ("invokeAction".equals(method)) //$NON-NLS-1$

             {

@@ -198,7 +197,7 @@
 

     private final SessionObject getSession(HttpServletRequest request)

     {

-        String sessionID = request.getSession().getId();

+        final String sessionID = request.getSession().getId();

         SessionObject ret = (SessionObject) sessions.get(sessionID);

         if (ret == null)

         {

@@ -211,7 +210,7 @@
     private static final String require(String name, HttpServletRequest request)

         throws ServletException

     {

-        String value = request.getParameter(name);

+        final String value = request.getParameter(name);

         if (value == null)

             throw new ServletException("missing parameter: " + name);

         return value;

@@ -220,10 +219,10 @@
     private final UPnPService requireService(HttpServletRequest request)

         throws ServletException

     {

-        String deviceUdn = require("udn", request); //$NON-NLS-1$

-        String serviceUrn = require("urn", request); //$NON-NLS-1$

+        final String deviceUdn = require("udn", request); //$NON-NLS-1$

+        final String serviceUrn = require("urn", request); //$NON-NLS-1$

 

-        UPnPDevice device = getDevice(deviceUdn);

+        final UPnPDevice device = getDevice(deviceUdn);

         return getService(device, serviceUrn);

     }

 

@@ -235,7 +234,7 @@
             return null; // the device is dynamically removed

         }

 

-        Object parentUdn = ref.getProperty(UPnPDevice.UDN);

+        final Object parentUdn = ref.getProperty(UPnPDevice.UDN);

         if (parentUdn == null)

         {

             plugin.log(LogService.LOG_ERROR,

@@ -243,7 +242,7 @@
             return null;

         }

 

-        JSONObject json = deviceToJSON(ref, device);

+        final JSONObject json = Serializer.deviceToJSON(ref, device);

 

         // add child devices

         final Object[] refs = tracker.getServiceReferences();

@@ -251,8 +250,8 @@
         {

             ref = (ServiceReference) refs[i];

 

-            Object parent = ref.getProperty(UPnPDevice.PARENT_UDN);

-            Object currentUDN = ref.getProperty(UPnPDevice.UDN);

+            final Object parent = ref.getProperty(UPnPDevice.PARENT_UDN);

+            final Object currentUDN = ref.getProperty(UPnPDevice.UDN);

             if (parent == null)

             { // no parent

                 continue;

@@ -273,101 +272,10 @@
         return json;

     }

 

-    private static final JSONObject deviceToJSON(ServiceReference ref, UPnPDevice device)

-        throws JSONException

-    {

-        JSONObject json = new JSONObject();

-        json.put("icon", device.getIcons(null) != null); //$NON-NLS-1$

-

-        // add properties

-        String[] props = ref.getPropertyKeys();

-        JSONObject _props = new JSONObject();

-        for (int i = 0; props != null && i < props.length; i++)

-        {

-            _props.put(props[i], ref.getProperty(props[i]));

-        }

-        json.put("props", _props); //$NON-NLS-1$

-

-        UPnPService[] services = device.getServices();

-        for (int i = 0; services != null && i < services.length; i++)

-        {

-            json.append("services", services[i].getType()); //$NON-NLS-1$

-        }

-

-        return json;

-    }

-

-    private static final JSONObject serviceToJSON(UPnPService service,

-        SessionObject session) throws JSONException

-    {

-        JSONObject json = new JSONObject();

-

-        // add service properties

-        json.put("type", service.getType()); //$NON-NLS-1$

-        json.put("id", service.getId()); //$NON-NLS-1$

-

-        // add state variables

-        UPnPStateVariable[] vars = service.getStateVariables();

-        for (int i = 0; vars != null && i < vars.length; i++)

-        {

-            Object value = null;

-            if (vars[i] instanceof UPnPLocalStateVariable)

-            {

-                value = ((UPnPLocalStateVariable) vars[i]).getCurrentValue();

-            }

-

-            if (value == null)

-                value = session.getValue(vars[i].getName());

-            if (value == null)

-                value = "---"; //$NON-NLS-1$

-

-            json.append("variables", variableToJSON(vars[i], vars[i].getName()) //$NON-NLS-1$

-                .put("value", value));// //$NON-NLS-1$

-        }

-

-        // add actions

-        UPnPAction[] actions = service.getActions();

-        for (int i = 0; actions != null && i < actions.length; i++)

-        {

-            json.append("actions", actionToJSON(actions[i])); //$NON-NLS-1$

-        }

-

-        return json;

-    }

-    

-    private static final JSONObject variableToJSON(final UPnPStateVariable var, final String name)

-        throws JSONException

-    {

-        return new JSONObject()//

-        .put("name", name) // //$NON-NLS-1$

-        .put("default", var.getDefaultValue()) // //$NON-NLS-1$

-        .put("min", var.getMinimum()) //$NON-NLS-1$

-        .put("max", var.getMaximum()) //$NON-NLS-1$

-        .put("step", var.getStep()) //$NON-NLS-1$

-        .put("allowed", var.getAllowedValues()) //$NON-NLS-1$

-        .put("sendsEvents", var.sendsEvents()) //$NON-NLS-1$

-        .put("type", var.getUPnPDataType()); //$NON-NLS-1$

-    }

-

-    private static final JSONObject actionToJSON(UPnPAction action) throws JSONException

-    {

-        JSONObject json = new JSONObject();

-        json.put("name", action.getName()); //$NON-NLS-1$

-        String[] names = action.getInputArgumentNames();

-        for (int i = 0; names != null && i < names.length; i++)

-        {

-            UPnPStateVariable variable = action.getStateVariable(names[i]);

-            json.append("inVars", variableToJSON(variable, names[i]));  //$NON-NLS-1$

-        }

-

-        return json;

-

-    }

-

     private static final JSONObject invoke(UPnPAction action, String[] names,

         String[] vals) throws Exception

     {

-        JSONObject json = new JSONObject();

+        final JSONObject json = new JSONObject();

 

         // check input arguments

         Hashtable inputArgs = null;

@@ -408,15 +316,15 @@
         }

 

         // invoke

-        Dictionary out = action.invoke(inputArgs);

+        final Dictionary out = action.invoke(inputArgs);

 

         // prepare output arguments

         if (out != null && out.size() > 0)

         {

             for (Enumeration e = out.keys(); e.hasMoreElements();)

             {

-                String key = (String) e.nextElement();

-                UPnPStateVariable var = action.getStateVariable(key);

+                final String key = (String) e.nextElement();

+                final UPnPStateVariable var = action.getStateVariable(key);

 

                 Object value = out.get(key);

                 if (value instanceof Date)

@@ -428,7 +336,7 @@
                 }

                 else if (value instanceof byte[])

                 {

-                    value = hex((byte[]) value);

+                    value = Hex.encode((byte[]) value);

                 }

 

                 json.append("output", new JSONObject() // //$NON-NLS-1$

@@ -440,41 +348,48 @@
         return json;

     }

 

-    private static final String hex(byte[] data)

+    private final void fillCache()

     {

-        if (data == null)

-            return "null"; //$NON-NLS-1$

-        StringBuffer sb = new StringBuffer(data.length * 3);

-        synchronized (sb)

+        final ServiceReference[] refs = tracker.getServiceReferences();

+        for (int i = 0; i < refs.length; i++)

         {

-            for (int i = 0; i < data.length; i++)

+            final ServiceReference ref = refs[i];

+            final Object udn = ref.getProperty(UPnPDevice.UDN);

+            if (icons.containsKey(udn))

             {

-                sb.append(Integer.toHexString(data[i] & 0xff)).append('-');

+                continue;

             }

-            sb.deleteCharAt(sb.length() - 1);

+

+            final UPnPDevice device = (UPnPDevice) bc.getService(ref);

+            UPnPIcon icon = null;

+            try

+            { // Fix for FELIX-4012

+                UPnPIcon[] _icons = device == null ? null : device.getIcons(null);

+                icon = _icons != null && _icons.length > 0 ? _icons[0] : null;

+            }

+            catch (IllegalStateException e)

+            { // since OSGi r4.3 ignore it

+            }

+            icons.put(udn, icon);

+            devices.put(udn, device);

         }

-        return sb.toString();

+    }

+

+    private final UPnPIcon getIcon(final String udn)

+    {

+        fillCache();

+        return (UPnPIcon) icons.get(udn);

     }

 

     private final UPnPDevice getDevice(String udn)

     {

-        ServiceReference[] refs = tracker.getServiceReferences();

-        String _udn;

-        for (int i = 0; refs != null && i < refs.length; i++)

+        fillCache();

+        final UPnPDevice device = (UPnPDevice) devices.get(udn);

+        if (null == device)

         {

-            _udn = (String) refs[i].getProperty(UPnPDevice.UDN);

-            if (_udn != null && _udn.equals(udn))

-            {

-                UPnPDevice upnpDevice = (UPnPDevice) tracker.getService(refs[i]);

-                if (null == upnpDevice)

-                {

-                    break; // device not found

-                }

-                return upnpDevice;

-            }

+            throw new IllegalArgumentException("Device '" + udn + "' not found!");

         }

-

-        throw new IllegalArgumentException("Device '" + udn + "' not found!");

+        return device;

     }

 

     private static final UPnPService getService(UPnPDevice device, String urn)

@@ -521,42 +436,14 @@
 

     /* ---------- BEGIN SERVICE TRACKER */

     /**

-     * @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference,

-     *      java.lang.Object)

-     */

-    public final void modifiedService(ServiceReference ref, Object serv)

-    {/* unused */

-    }

-

-    /**

      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference,

      *      java.lang.Object)

      */

-    public final void removedService(ServiceReference ref, Object serv)

+    final void removedService(ServiceReference ref)

     {

-        icons.remove(ref.getProperty(UPnPDevice.UDN));

-    }

-

-    /**

-     * @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)

-     */

-    public final Object addingService(ServiceReference ref)

-    {

-        UPnPDevice device = (UPnPDevice) bc.getService(ref);

-

-        UPnPIcon[] _icons = null;

-        try // Fix for FELIX-4012

-        {

-            _icons = device == null ? null : device.getIcons(null);

-        } catch(IllegalStateException e) { // since OSGi r4.3

-            device = null; // don't track that device, it has been removed

-        }

-        if (_icons != null && _icons.length > 0)

-        {

-            icons.put(ref.getProperty(UPnPDevice.UDN), _icons[0]);

-        }

-

-        return device;

+        final Object udn = ref.getProperty(UPnPDevice.UDN);

+        icons.remove(udn);

+        devices.remove(udn);

     }

 

 }

diff --git a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Hex.java b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Hex.java
index 8ea6357..2b2a1c5 100644
--- a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Hex.java
+++ b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Hex.java
@@ -23,6 +23,31 @@
     {

         // prevent instantiation

     }

+    

+    /**

+     * Encodes HEX form a <code>String</code>. The new line (\n) and carriage

+     * return (\r) symbols in the string are ignored.

+     * 

+     * @param data the bytes to encode

+     * @return the encoded data

+     */

+    public static final String encode(byte[] data)

+    {

+        if (data == null)

+        {

+            return "null"; //$NON-NLS-1$

+        }

+        final StringBuffer sb = new StringBuffer(data.length * 3);

+        synchronized (sb)

+        {

+            for (int i = 0; i < data.length; i++)

+            {

+                sb.append(Integer.toHexString(data[i] & 0xff)).append('-');

+            }

+            sb.deleteCharAt(sb.length() - 1);

+            return sb.toString();

+        }

+    }

 

     /**

      * Decodes HEX form a <code>String</code>. The new line (\n) and carriage

diff --git a/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Serializer.java b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Serializer.java
new file mode 100644
index 0000000..7d04e9a
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/java/org/apache/felix/webconsole/plugins/upnp/internal/Serializer.java
@@ -0,0 +1,126 @@
+/*

+ * 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.upnp.internal;

+

+import org.json.JSONException;

+import org.json.JSONObject;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.upnp.UPnPAction;

+import org.osgi.service.upnp.UPnPDevice;

+import org.osgi.service.upnp.UPnPLocalStateVariable;

+import org.osgi.service.upnp.UPnPService;

+import org.osgi.service.upnp.UPnPStateVariable;

+

+class Serializer

+{

+

+    private Serializer()

+    {

+        // prevent instantiation

+    }

+

+    static final JSONObject deviceToJSON(ServiceReference ref, UPnPDevice device)

+        throws JSONException

+    {

+        final JSONObject json = new JSONObject();

+        json.put("icon", device.getIcons(null) != null); //$NON-NLS-1$

+

+        // add properties

+        final String[] props = ref.getPropertyKeys();

+        final JSONObject _props = new JSONObject();

+        for (int i = 0; props != null && i < props.length; i++)

+        {

+            _props.put(props[i], ref.getProperty(props[i]));

+        }

+        json.put("props", _props); //$NON-NLS-1$

+

+        final UPnPService[] services = device.getServices();

+        for (int i = 0; services != null && i < services.length; i++)

+        {

+            json.append("services", services[i].getType()); //$NON-NLS-1$

+        }

+

+        return json;

+    }

+

+    static final JSONObject serviceToJSON(UPnPService service,

+        SessionObject session) throws JSONException

+    {

+        final JSONObject json = new JSONObject();

+

+        // add service properties

+        json.put("type", service.getType()); //$NON-NLS-1$

+        json.put("id", service.getId()); //$NON-NLS-1$

+

+        // add state variables

+        final UPnPStateVariable[] vars = service.getStateVariables();

+        for (int i = 0; vars != null && i < vars.length; i++)

+        {

+            Object value = null;

+            if (vars[i] instanceof UPnPLocalStateVariable)

+            {

+                value = ((UPnPLocalStateVariable) vars[i]).getCurrentValue();

+            }

+

+            if (value == null)

+                value = session.getValue(vars[i].getName());

+            if (value == null)

+                value = "---"; //$NON-NLS-1$

+

+            json.append("variables", variableToJSON(vars[i], vars[i].getName()) //$NON-NLS-1$

+            .put("value", value));// //$NON-NLS-1$

+        }

+

+        // add actions

+        final UPnPAction[] actions = service.getActions();

+        for (int i = 0; actions != null && i < actions.length; i++)

+        {

+            json.append("actions", actionToJSON(actions[i])); //$NON-NLS-1$

+        }

+

+        return json;

+    }

+

+    static final JSONObject variableToJSON(final UPnPStateVariable var,

+        final String name) throws JSONException

+    {

+        return new JSONObject()//

+        .put("name", name) // //$NON-NLS-1$

+        .put("default", var.getDefaultValue()) // //$NON-NLS-1$

+        .put("min", var.getMinimum()) //$NON-NLS-1$

+        .put("max", var.getMaximum()) //$NON-NLS-1$

+        .put("step", var.getStep()) //$NON-NLS-1$

+        .put("allowed", var.getAllowedValues()) //$NON-NLS-1$

+        .put("sendsEvents", var.sendsEvents()) //$NON-NLS-1$

+        .put("type", var.getUPnPDataType()); //$NON-NLS-1$

+    }

+

+    static final JSONObject actionToJSON(UPnPAction action) throws JSONException

+    {

+        final JSONObject json = new JSONObject();

+        json.put("name", action.getName()); //$NON-NLS-1$

+        final String[] names = action.getInputArgumentNames();

+        for (int i = 0; names != null && i < names.length; i++)

+        {

+            final UPnPStateVariable variable = action.getStateVariable(names[i]);

+            json.append("inVars", variableToJSON(variable, names[i])); //$NON-NLS-1$

+        }

+

+        return json;

+

+    }

+}