com.triggertrap.ZeroConf.java Source code

Java tutorial

Introduction

Here is the source code for com.triggertrap.ZeroConf.java

Source

/**
 * ZeroConf plugin for Cordova/Phonegap
 *
 * Copyright (c) 2013-2014 Vlad Stirbu <vlad.stirbu@ieee.org>
 * Converted to Cordova 3.x
 * Refactored initialization
 * MIT License
 *
 * @author Matt Kane
 * Copyright (c) Triggertrap Ltd. 2012. All Rights Reserved.
 * Available under the terms of the MIT License.
 *
 * TODO take a look at Android NsdManager class...
 * 
 */

package com.triggertrap;

import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.apache.cordova.PluginResult.Status;
//import org.apache.http.conn.util.InetAddressUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.net.wifi.WifiManager;
import android.net.wifi.WifiInfo;
import android.util.Log;

import javax.jmdns.JmDNS;
import javax.jmdns.impl.JmDNSImpl;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;

public class ZeroConf extends CordovaPlugin {
    WifiManager.MulticastLock lock;
    private JmDNS jmdns = null;
    private ServiceListener listener;
    private CallbackContext callback;
    private WifiManager wifiManager;
    private WifiInfo wifiInfo;
    private int wifi_ip = 0;

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);

        wifiManager = (WifiManager) this.cordova.getActivity()
                .getSystemService(android.content.Context.WIFI_SERVICE);
        wifiInfo = wifiManager.getConnectionInfo();

        lock = wifiManager.createMulticastLock("ZeroConfPluginLock");
        lock.setReferenceCounted(true);
        lock.acquire();

        wifi_ip = wifiInfo.getIpAddress();
        Log.v("ZeroConf", "Initialized");
    }

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
        this.callback = callbackContext;

        if (action.equals("watch")) {
            final String type = args.optString(0);
            if (type != null) {
                cordova.getThreadPool().execute(new Runnable() {
                    public void run() {
                        watch(type); // Thread-safe.
                    }
                });
            } else {
                callbackContext.error("Service type not specified.");
                return false;
            }
        } else if (action.equals("unwatch")) {
            final String type = args.optString(0);
            if (type != null) {
                cordova.getThreadPool().execute(new Runnable() {
                    public void run() {
                        unwatch(type);
                    }
                });
            } else {
                callbackContext.error("Service type not specified.");
                return false;
            }
        } else if (action.equals("register")) {
            JSONObject obj = args.optJSONObject(0);
            if (obj != null) {
                final String type = obj.optString("type");
                final String name = obj.optString("name");
                final int port = obj.optInt("port");
                final String text = obj.optString("text");
                if (type == null) {
                    callbackContext.error("Missing required service info.");
                    return false;
                }
                cordova.getThreadPool().execute(new Runnable() {
                    public void run() {
                        register(type, name, port, text);
                    }
                });
            } else {
                callbackContext.error("Missing required service info.");
                return false;

            }

        } else if (action.equals("close")) {
            if (jmdns != null) {
                try {
                    jmdns.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else if (action.equals("unregister")) {
            if (jmdns != null) {
                jmdns.unregisterAllServices();
            }

        } else if (action.equals("list")) {
            final String type = args.optString(0);
            final int timeout = args.optInt(1);
            if (type != null && timeout > 0) {
                cordova.getThreadPool().execute(new Runnable() {
                    public void run() {
                        list(type, timeout); // Thread-safe.
                    }
                });
            } else {
                callbackContext.error("Missing required parameter: type, timeout.");
                return false;

            }
        } else {
            Log.e("ZeroConf", "Invalid action: " + action);
            callbackContext.error("Invalid action.");
            return false;
        }
        PluginResult result = new PluginResult(Status.NO_RESULT);
        result.setKeepCallback(true);
        // return result;
        return true;
    }

    private void watch(String type) {
        Log.d("ZeroConf", "Watch " + type);
        if (jmdns == null) {
            Log.d("ZeroConf", "jmdns is null");
            setupWatcher();
        }
        if (jmdns != null) {

            Log.d("ZeroConf", "Name: " + jmdns.getName() + " host: " + jmdns.getHostName());
            jmdns.addServiceListener(type, listener);
        } else {
            Log.d("ZeroConf", "jmdns is null. Cannot add addServiceListener.");
        }
    }

    private void unwatch(String type) {
        if (jmdns == null) {
            return;
        }
        jmdns.removeServiceListener(type, listener);
        Log.d("ZeroConf", "Set jmdns object back to null");
        jmdns = null;
    }

    private void register(String type, String name, int port, String text) {
        if (name == null) {
            name = "";
        }

        if (text == null) {
            text = "";
        }

        try {
            ServiceInfo service = ServiceInfo.create(type, name, port, text);
            jmdns.registerService(service);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void list(String type, int timeout) {
        try {
            JmDNS mdnsQuery = JmDNS.create(ZeroConf.getIPAddress(wifi_ip));
            ServiceInfo[] services = mdnsQuery.list(type, timeout);
            sendListCallback("list", services);
            mdnsQuery.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void setupWatcher() {
        Log.d("ZeroConf", "Setup watcher");
        try {
            wifiManager = (WifiManager) this.cordova.getActivity()
                    .getSystemService(android.content.Context.WIFI_SERVICE);
            wifiInfo = wifiManager.getConnectionInfo();

            lock = wifiManager.createMulticastLock("ZeroConfPluginLock");
            lock.setReferenceCounted(true);
            lock.acquire();

            wifi_ip = wifiInfo.getIpAddress();
            Log.d("ZeroConf", "Get current Wifi IP");

            jmdns = JmDNS.create(ZeroConf.getIPAddress(wifi_ip));
            Log.d("ZeroConf", "Clear Cache");
            ((JmDNSImpl) jmdns).getCache().clear();
            listener = new ServiceListener() {

                public void serviceResolved(ServiceEvent ev) {
                    Log.d("ZeroConf", "Resolved");

                    sendCallback("added", ev.getInfo());
                }

                public void serviceRemoved(ServiceEvent ev) {
                    Log.d("ZeroConf", "Removed");

                    sendCallback("removed", ev.getInfo());
                }

                public void serviceAdded(ServiceEvent event) {
                    Log.d("ZeroConf", "Added");

                    // Force serviceResolved to be called again
                    jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
                }
            };

        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
    }

    public void sendCallback(String action, ServiceInfo info) {
        JSONObject status = new JSONObject();
        try {
            status.put("action", action);
            status.put("service", jsonifyService(info));
            Log.d("ZeroConf", "Sending result: " + status.toString());

            PluginResult result = new PluginResult(PluginResult.Status.OK, status);
            result.setKeepCallback(true);
            this.callback.sendPluginResult(result);

        } catch (JSONException e) {

            e.printStackTrace();
        }

    }

    public void sendListCallback(String action, ServiceInfo[] services) {
        JSONObject status = new JSONObject();
        try {
            status.put("action", action);
            JSONArray array = new JSONArray();
            for (ServiceInfo service : services) {
                array.put(jsonifyService(service));
            }
            status.put("service", array);
            Log.d("ZeroConf", "Sending result: " + status.toString());

            PluginResult result = new PluginResult(PluginResult.Status.OK, status);
            result.setKeepCallback(true);
            this.callback.sendPluginResult(result);

        } catch (JSONException e) {

            e.printStackTrace();
        }

    }

    public static JSONObject jsonifyService(ServiceInfo info) {
        JSONObject obj = new JSONObject();
        try {
            obj.put("application", info.getApplication());
            obj.put("domain", info.getDomain());
            obj.put("port", info.getPort());
            obj.put("name", info.getName());
            obj.put("server", info.getServer());
            obj.put("description", info.getNiceTextString());
            obj.put("protocol", info.getProtocol());
            obj.put("qualifiedname", info.getQualifiedName());
            obj.put("type", info.getType());

            JSONArray addresses = new JSONArray();
            String[] add = info.getHostAddresses();
            for (int i = 0; i < add.length; i++) {
                addresses.put(add[i]);
            }
            obj.put("addresses", addresses);
            JSONArray urls = new JSONArray();

            String[] url = info.getURLs();
            for (int i = 0; i < url.length; i++) {
                urls.put(url[i]);
            }
            obj.put("urls", urls);

        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }

        return obj;

    }

    /**
     * Returns the first found IP4 address.
     * 
     * @return the first found IP4 address
     */
    public static InetAddress getIPAddress(int wifi_ipaddr) {
        try {
            String ipString = String.format("%d.%d.%d.%d", (wifi_ipaddr & 0xff), (wifi_ipaddr >> 8 & 0xff),
                    (wifi_ipaddr >> 16 & 0xff), (wifi_ipaddr >> 24 & 0xff));

            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) {
                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
                for (InetAddress addr : addrs) {
                    if (!addr.isLoopbackAddress() && (ipString.equals(addr.getHostAddress()))) {
                        //String sAddr = addr.getHostAddress().toUpperCase();
                        if (addr instanceof java.net.Inet4Address) {
                            //Log.d("found IP address to listen: " , sAddr);
                            return addr;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}