com.ecor.MDNS.java Source code

Java tutorial

Introduction

Here is the source code for com.ecor.MDNS.java

Source

/**
 * MDNS plugin for Cordova/Phonegap
 *
 * Copyright (c) 2013-2014 Corey Butler <corey@coreybutler.com>
 * Rewrote JavaScript
 * Updated Java plugin
 * Added some iOS skeleton code
 * Renamed from ZeroConf to MDNS
 *
 * @author Vlad Stirbu
 * 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.
 *
 */

package com.ecor;

import java.io.IOException;

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.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.InetAddress;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import java.security.MessageDigest;

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

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

public class MDNS extends CordovaPlugin {
    WifiManager.MulticastLock lock;

    private JmDNS jmdns;
    private ServiceListener listener;
    private CallbackContext callback;
    private InetAddress addr;
    private String macaddress;
    private MdnsServices knownservices = new MdnsServices();

    private static String TAG = "MDNS";

    private static interface Response {
        public static final String ADDED = "available";
        public static final String REMOVED = "unavailable";
        public static final String RESOLVED = "resolved";
    }

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

        WifiManager wifi = (WifiManager) this.cordova.getActivity()
                .getSystemService(android.content.Context.WIFI_SERVICE);
        lock = wifi.createMulticastLock(TAG + "PluginLock");
        lock.setReferenceCounted(true);
        lock.acquire();

        WifiInfo wifiinfo = wifi.getConnectionInfo();
        int intaddr = wifiinfo.getIpAddress();
        macaddress = wifiinfo.getMacAddress();

        byte[] byteaddr = new byte[] { (byte) (intaddr & 0xff), (byte) (intaddr >> 8 & 0xff),
                (byte) (intaddr >> 16 & 0xff), (byte) (intaddr >> 24 & 0xff) };

        try {
            addr = InetAddress.getByAddress(byteaddr);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.v(TAG, "Initialized");
        Log.d(TAG, "Mac Address: " + macaddress);
    }

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
        Log.d(TAG, "Executing an action...");
        this.callback = callbackContext;

        Log.d(TAG, "Action called: " + action);
        Log.d(TAG, args.toString());
        if (action.equals("macaddress")) {
            Log.d(TAG, "Mac Address: " + macaddress);
            final CallbackContext cb = callbackContext;
            cordova.getThreadPool().execute(new Runnable() {
                public void run() {
                    JSONObject json = new JSONObject();
                    try {
                        json.put("action", new String("macaddress"));
                        json.put("address", macaddress);
                        PluginResult result = new PluginResult(PluginResult.Status.OK, json);
                        result.setKeepCallback(true);
                        cb.sendPluginResult(result);
                    } catch (Exception e) {
                        e.printStackTrace();
                        cb.error("JSON Error retrieving Mac Address.");
                    }
                }
            });
        } else if (action.equals("monitor")) {
            final String type = args.optString(0);
            if (type != null) {
                Log.d(TAG, "Monitor type: " + type);
                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("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 {
            Log.e(TAG, "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) {
        if (jmdns == null) {
            setupWatcher();
        }

        // Create a timer to list services every second
        Timer timer = new Timer();
        final String t = type;
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                ServiceInfo[] svcs = jmdns.list(t);
                try {
                    if (svcs.length > 0) {
                        for (ServiceInfo i : svcs) {
                            if (!knownservices.contains(i)) {
                                Log.i(TAG, "Known services didn't contain the service.");
                                Log.d(TAG, i.toString());
                                knownservices.add(i);
                                sendCallback(Response.ADDED, i);
                                Log.d(TAG, Response.ADDED + " " + i.getName());
                            }
                        }
                    }
                } catch (Exception e) {
                    Log.d(TAG, "Unknown Issue");
                    e.printStackTrace();
                }
            }
        }, 0, 750);

        Log.d(TAG, "Watch " + type);
        Log.d(TAG, "Name: " + jmdns.getName() + " host: " + jmdns.getHostName());
        jmdns.addServiceListener(type, listener);
    }

    //  private void unwatch(String type) {
    //    if (jmdns == null) {
    //      return;
    //    }
    //    jmdns.removeServiceListener(type, listener);
    //  }

    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 setupWatcher() {
        Log.d(TAG, "Setup watcher");
        try {
            jmdns = JmDNS.create(addr);
            listener = new ServiceListener() {

                public void serviceResolved(ServiceEvent ev) {
                    Log.d(TAG, Response.RESOLVED + " --> " + ev.getName());

                    // Add to known services
                    knownservices.add(ev.getInfo());

                    sendCallback(Response.ADDED, ev.getInfo());
                }

                public void serviceRemoved(ServiceEvent ev) {
                    Log.d(TAG, Response.REMOVED + " --> " + ev.getInfo().getName() + " <== ");
                    try {
                        // Remove from known services
                        knownservices.remove(ev.getInfo());
                    } catch (Exception e) {
                        Log.e(TAG, "Error removing service.");
                        e.printStackTrace();
                    }

                    sendCallback(Response.REMOVED, ev.getInfo());
                }

                public void serviceAdded(ServiceEvent event) {
                    Log.d(TAG, Response.ADDED + " --> " + event.getName());

                    // 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(TAG, "Sending result: " + status.toString());

            PluginResult result = new PluginResult(PluginResult.Status.OK, status);

            result.setKeepCallback(true);
            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);
            obj.put("md5", ServiceMD5(info));

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

        return obj;

    }

    private static String ServiceMD5(ServiceInfo info) {
        JSONArray addresses = new JSONArray();
        String[] add = info.getHostAddresses();
        for (int i = 0; i < add.length; i++) {
            addresses.put(add[i]);
        }
        try {
            String raw = info.getType() + addresses.toString() + Integer.toString(info.getPort())
                    + info.getQualifiedName();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(raw.getBytes("UTF-8"));
            byte[] digest = md.digest();
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < digest.length; i++) {
                String hex = Integer.toHexString(0xff & digest[i]);
                if (hex.length() == 1)
                    hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}