phex.common.Ip2CountryManager.java Source code

Java tutorial

Introduction

Here is the source code for phex.common.Ip2CountryManager.java

Source

/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2005 Phex Development Group
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 *  --- CVS Information ---
 *  $Id: Ip2CountryManager.java,v 1.9 2005/11/03 16:23:34 gregork Exp $
 */
package phex.common;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.collections.list.UnmodifiableList;

import phex.common.address.AddressUtils;
import phex.common.address.IpAddress;
import phex.utils.*;

/**
 * 
 * @author gkoukkoullis
 */
public class Ip2CountryManager implements Manager {
    private static Ip2CountryManager instance;

    /**
     * Indicates if the database is fully loaded or not.
     */
    private boolean isLoaded;
    private List ipCountryRangeList;

    private Ip2CountryManager() {
        isLoaded = false;
        ipCountryRangeList = new ArrayList();
    }

    public static Ip2CountryManager getInstance() {
        if (instance == null) {
            instance = new Ip2CountryManager();
        }
        return instance;
    }

    /**
     * This method is called in order to initialize the manager.  Inside
     * this method you can't rely on the availability of other managers.
     * @return true if initialization was successful, false otherwise.
     */
    public boolean initialize() {
        return true;
    }

    /**
     * This method is called in order to perform post initialization of the
     * manager. This method includes all tasks that must be done after initializing
     * all the several managers. Inside this method you can rely on the
     * availability of other managers.
     * @return true if initialization was successful, false otherwise.
     */
    public boolean onPostInitialization() {
        return true;
    }

    /**
     * This method is called after the complete application including GUI completed
     * its startup process. This notification must be used to activate runtime
     * processes that needs to be performed once the application has successfully
     * completed startup.
     */
    public void startupCompletedNotify() {
        Runnable runnable = new Runnable() {
            public void run() {
                loadIp2CountryDB();
            }
        };
        ThreadPool.getInstance().addJob(runnable, "IP2CountryLoader");
    }

    /**
     * This method is called in order to cleanly shutdown the manager. It
     * should contain all cleanup operations to ensure a nice shutdown of Phex.
     */
    public void shutdown() {
    }

    /**
     * Returns the country code if found, empty string if not found, and null
     * if DB has not been loaded yet.
     * @param address
     * @return
     */
    public String getCountryCode(IpAddress address) {
        if (!isLoaded) {
            return null;
        }
        IpCountryRange range = binarySearch(address.getHostIP());
        if (range == null) {
            return "";
        }
        return range.countryCode;
    }

    private void loadIp2CountryDB() {
        InputStream inStream = ClassLoader.getSystemResourceAsStream("phex/resources/ip2country.csv");
        if (inStream == null) {
            Logger.logMessage(Logger.FINE, Logger.NETWORK, "Default GWebCache file not found.");
            return;
        }
        BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));

        ArrayList initialList = new ArrayList(5000);
        IpCountryRange range;
        String line;
        try {
            line = reader.readLine();
            while (line != null) {
                range = new IpCountryRange(line);
                initialList.add(range);
                line = reader.readLine();
            }
        } catch (IOException exp) {
            NLogger.error(NLoggerNames.GLOBAL, exp, exp);
        } finally {
            IOUtil.closeQuietly(reader);
        }
        initialList.trimToSize();
        Collections.sort(initialList);
        ipCountryRangeList = UnmodifiableList.decorate(initialList);
        isLoaded = true;
    }

    private IpCountryRange binarySearch(byte[] hostIp) {
        int low = 0;
        int high = ipCountryRangeList.size() - 1;

        while (low <= high) {
            int mid = (low + high) >> 1;
            IpCountryRange midVal = (IpCountryRange) ipCountryRangeList.get(mid);
            int cmp = midVal.compareHostAddress(hostIp);
            if (cmp < 0) {
                low = mid + 1;
            } else if (cmp > 0) {
                high = mid - 1;
            } else {
                return midVal; // key found
            }
        }
        return null; // key not found
    }

    private class IpCountryRange implements Comparable {
        byte[] from;
        byte[] to;
        String countryCode;

        public IpCountryRange(String line) {
            // "33996344","33996351","GB"
            int startIdx, endIdx;
            startIdx = 0;

            endIdx = line.indexOf((int) ',', startIdx);
            from = AddressUtils.parseIntIP(line.substring(startIdx, endIdx));

            startIdx = endIdx + 1;
            endIdx = line.indexOf((int) ',', startIdx);
            to = AddressUtils.parseIntIP(line.substring(startIdx, endIdx));

            startIdx = endIdx + 1;
            countryCode = line.substring(startIdx);
        }

        public int compareHostAddress(byte[] hostIp) {
            long hostIpL;
            hostIpL = IOUtil.unsignedInt2Long(IOUtil.deserializeInt(hostIp, 0));
            long fromIpL = IOUtil.unsignedInt2Long(IOUtil.deserializeInt(from, 0));
            long cmp = hostIpL - fromIpL;
            if (cmp == 0) {
                return 0;
            }
            if (cmp < 0) {// host Ip is lower..
                return 1;
            }

            // validate to range..
            long toIpL = IOUtil.unsignedInt2Long(IOUtil.deserializeInt(to, 0));
            cmp = hostIpL - toIpL;
            if (cmp == 0 || cmp < 0) {// we are between from and to
                return 0;
            } else {// host Ip is higher..
                return -1;
            }
        }

        public int compareTo(Object o) {
            if (o == this) {
                return 0;
            }
            IpCountryRange range = (IpCountryRange) o;

            byte[] ip1 = (byte[]) from;
            byte[] ip2 = (byte[]) range.from;

            long ip1l = IOUtil.unsignedInt2Long(IOUtil.deserializeInt(ip1, 0));
            long ip2l = IOUtil.unsignedInt2Long(IOUtil.deserializeInt(ip2, 0));

            if (ip1l < ip2l) {
                return -1;
            }
            // only if rate and object is equal return 0
            else {
                return 1;
            }
        }
    }
}