edu.umass.cs.msocket.proxy.location.LocationService.java Source code

Java tutorial

Introduction

Here is the source code for edu.umass.cs.msocket.proxy.location.LocationService.java

Source

/*******************************************************************************
 *
 * Mobility First - mSocket library
 * Copyright (C) 2013, 2014 - University of Massachusetts Amherst
 * Contact: arun@cs.umass.edu
 *
 * Licensed 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. 
 *
 * Initial developer(s): Arun Venkataramani, Aditya Yadav, Emmanuel Cecchet.
 * Contributor(s): ______________________.
 *
 *******************************************************************************/

package edu.umass.cs.msocket.proxy.location;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.URL;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.JSONArray;

import edu.umass.cs.gns.client.GnsProtocol.AccessType;
import edu.umass.cs.gns.client.GuidEntry;
import edu.umass.cs.gns.client.UniversalGnsClient;
import edu.umass.cs.gns.client.util.KeyPairUtils;
import edu.umass.cs.msocket.common.GnsConstants;
import edu.umass.cs.msocket.gns.GnsCredentials;
import edu.umass.cs.msocket.proxy.ProxyInfo;

/**
 * This class defines a LocationService
 * 
 * @author <a href="mailto:cecchet@cs.umass.edu">Emmanuel Cecchet</a>
 * @version 1.0
 */
public class LocationService extends Thread {
    private String proxyGroupName;
    private String locationServiceName;
    private GnsCredentials gnsCredentials;
    private boolean killed = false;
    private ProxyStatusThread statusThread;
    private ProxyInfo locationServiceInfo;
    private ServerSocket ss;
    private static final Logger logger = Logger.getLogger("LocationService");

    /**
     * Creates a new <code>LocationService</code> object
     * 
     * @param proxyGroupName
     * @param locationServiceName
     * @param gnsCredentials
     */
    public LocationService(String proxyGroupName, String locationServiceName, GnsCredentials gnsCredentials) {
        this.proxyGroupName = proxyGroupName;
        this.locationServiceName = locationServiceName;
        this.gnsCredentials = gnsCredentials;
    }

    /**
     * Establish a connection with the GNS, register the proxy in the proxy group,
     * start a monitoring socket and register its IP in the GNS,
     * 
     * @throws Exception
     */
    public void registerLocationServiceInGns() throws Exception {
        logger.info("Looking for location service " + locationServiceName + " GUID and certificates...");
        GuidEntry myGuid = KeyPairUtils.getGuidEntryFromPreferences(
                gnsCredentials.getGnsHost() + ":" + gnsCredentials.getGnsPort(), locationServiceName);

        final UniversalGnsClient gnsClient = gnsCredentials.getGnsClient();
        if (myGuid == null) {
            logger.info(
                    "No keys found for location service " + locationServiceName + ". Generating new GUID and keys");
            myGuid = gnsClient.guidCreate(gnsCredentials.getGuidEntry(), locationServiceName);
        }
        logger.info("We are guid " + myGuid.getGuid());

        // Make sure we are using our GUID info from now on
        gnsCredentials.setGuidEntry(myGuid);

        // Determine our IP
        String sIp = null;
        BufferedReader in;
        try {
            logger.info("Determining public IP");
            // Determine our external IP address by contacting http://icanhazip.com
            URL whatismyip = new URL("http://icanhazip.com");
            in = new BufferedReader(new InputStreamReader(whatismyip.openStream()));
            sIp = in.readLine();
            in.close();
        } catch (Exception e) {
        }

        locationServiceInfo = new ProxyInfo(myGuid.getGuid(), locationServiceName, sIp);

        try {
            // Contact http://freegeoip.net/csv/[IP] to resolve IP address location
            URL locator = new URL("http://freegeoip.net/csv/" + sIp);
            in = new BufferedReader(new InputStreamReader(locator.openStream()));
            String csv = in.readLine();
            in.close();
            // Read location result
            StringTokenizer st = new StringTokenizer(csv, ",");
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read IP");
            st.nextToken(); // IP
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read country code");
            String countryCode = st.nextToken().replace("\"", "");
            locationServiceInfo.setCountryCode(countryCode);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read country name");
            String countryName = st.nextToken().replace("\"", "");
            locationServiceInfo.setCountryName(countryName);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read state code");
            String stateCode = st.nextToken().replace("\"", "");
            locationServiceInfo.setStateCode(stateCode);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read state name");
            String stateName = st.nextToken().replace("\"", "");
            locationServiceInfo.setStateName(stateName);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read city");
            String city = st.nextToken().replace("\"", "");
            locationServiceInfo.setCity(city);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read zip");
            String zip = st.nextToken().replace("\"", "");
            locationServiceInfo.setZipCode(zip);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read latitude");
            String latitudeStr = st.nextToken().replace("\"", "");
            double latitude = Double.parseDouble(latitudeStr);
            if (!st.hasMoreTokens())
                throw new IOException("Failed to read longitude");
            String longitudeStr = st.nextToken().replace("\"", "");
            double longitude = Double.parseDouble(longitudeStr);
            locationServiceInfo.setLatLong(new GlobalPosition(latitude, longitude, 0));
        } catch (Exception e) {
            logger.log(Level.WARNING, "Failed to locate IP address " + e);
        }

        // Look for the group GUID
        String groupGuid = gnsClient.lookupGuid(proxyGroupName);

        // Check if we are a member of the group
        JSONArray members = gnsClient.groupGetMembers(groupGuid, myGuid);
        boolean isVerified = false;
        for (int i = 0; i < members.length(); i++) {
            if (myGuid.getGuid().equals(members.get(i))) {
                isVerified = true;
                break;
            }
        }

        // Make sure we advertise ourselves as a location service (readable for
        // everyone)
        gnsClient.fieldReplaceOrCreate(myGuid.getGuid(), GnsConstants.SERVICE_TYPE_FIELD,
                new JSONArray().put(GnsConstants.LOCATION_SERVICE), myGuid);
        gnsClient.aclAdd(AccessType.READ_WHITELIST, myGuid, GnsConstants.SERVICE_TYPE_FIELD, null);

        // Update our location
        gnsClient.setLocation(locationServiceInfo.getLatLong().getLongitude(),
                locationServiceInfo.getLatLong().getLatitude(), myGuid);

        if (!isVerified) {
            logger.log(Level.WARNING,
                    "This location service has not been verified yet, it will stay in the unverified list until it gets added to the proxy group");
        }
    }

    /**
     * Terminate this location service and its ProxyStatus thread
     */
    public void killIt() {
        killed = true;
        if (ss != null)
            try {
                ss.close();
            } catch (IOException ignore) {
            }
    }

    /**
     * @see java.lang.Thread#run()
     */
    @Override
    public void run() {
        while (!killed) {
            try {
                // Create the server socket
                ss = new ServerSocket(0);

                // Publish location service IP in the GNS
                final UniversalGnsClient gnsClient = gnsCredentials.getGnsClient();
                final String ipPort = locationServiceInfo.getIpAddress() + ":" + ss.getLocalPort();
                logger.info("Publishing Location service IP (" + ipPort + ") in GNS.");
                final GuidEntry guidEntry = gnsCredentials.getGuidEntry();
                gnsClient.fieldReplaceOrCreate(guidEntry.getGuid(), GnsConstants.LOCATION_SERVICE_IP,
                        new JSONArray().put(ipPort), guidEntry);
                gnsClient.aclAdd(AccessType.READ_WHITELIST, guidEntry, GnsConstants.LOCATION_SERVICE_IP, null);

                // Start the thread that collect information about proxy status
                statusThread = new ProxyStatusThread(proxyGroupName, gnsCredentials);
                statusThread.start();

                // Now accepting connections
                while (!ss.isClosed()) {
                    new LocateServiceThread(ss.accept(), this).start();
                }
            } catch (Exception e) {
                logger.log(Level.WARNING, "Location service failed with error " + e, e);
            }
        }
        if (statusThread != null)
            statusThread.killIt();

        logger.log(Level.INFO, "Location service has been terminated");
    }

    /**
     * Returns the statusThread value.
     * 
     * @return Returns the statusThread.
     */
    public ProxyStatusThread getStatusThread() {
        return statusThread;
    }

    /**
     * Returns the proxyInfo value.
     * 
     * @return Returns the proxyInfo.
     */
    public ProxyInfo getLocationServiceInfo() {
        return locationServiceInfo;
    }

}