Showing posts with label JSON. Show all posts
Showing posts with label JSON. Show all posts

Monday, October 22, 2012

Get Address Information by IP



Introduction

There are many IP to Address services such like http://www.hostip.info/, http://ip-lookup.net/, http://www.iplocation.net/ and so on, this post will talking about how to get address information by given IP via the API provided by Hostip.info.

Prerequest

The sample of this post is based on http://ben-bai.blogspot.tw/2012/02/java-practice-javanet-practice-use.html

Required jar files:


 json-lib: http://sourceforge.net/projects/json-lib/files/json-lib/
 commons-beanutils-1.8.3.jar http://commons.apache.org/beanutils/download_beanutils.cgi
 commons-collections-3.2.1.jar http://commons.apache.org/collections/download_collections.cgi
 commons-lang-2.5.jar http://commons.apache.org/lang/download_lang.cgi
 commons-logging-1.1.1.jar http://commons.apache.org/logging/download_logging.cgi
 ezmorph-1.0.6.jar http://sourceforge.net/projects/ezmorph/files/ezmorph/



The Program

IPLookupService.java

Get position by given IP and then get formatted address by given lat/lng

package test;

import java.io.InputStreamReader;

import net.sf.json.JSONObject;

/**
 * required jar files:
 * json-lib: http://sourceforge.net/projects/json-lib/files/json-lib/
 * commons-beanutils-1.8.3.jar http://commons.apache.org/beanutils/download_beanutils.cgi
 * commons-collections-3.2.1.jar http://commons.apache.org/collections/download_collections.cgi
 * commons-lang-2.5.jar http://commons.apache.org/lang/download_lang.cgi
 * commons-logging-1.1.1.jar http://commons.apache.org/logging/download_logging.cgi
 * ezmorph-1.0.6.jar http://sourceforge.net/projects/ezmorph/files/ezmorph/
 *
 */
public class IPLookupService {
    public static void main (String[] args) {
        AddressInfo info = ipToLocation("98.76.54.32");
        System.out.println(info.getCountryName());
        System.out.println(info.getCountryCode());
        System.out.println(info.getCity());
        System.out.println(info.getLat());
        System.out.println(info.getLng());
        System.out.println(info.getFormattedAddress());
    }
    /**
     * return country, city, address by given IP
     * @param ip
     * @return
     */
    public static AddressInfo ipToLocation (String ip) {
        String country;
        AddressInfo info = null;
        double lat;
        double lng;
        StringBuilder sb = getResponse(
                "http://api.hostip.info/get_json.php?ip=" + ip + "&position=true");
        JSONObject jobj = JSONObject.fromObject(sb.toString());
        lat = jobj.getDouble("lat");
        lng = jobj.getDouble("lng");
        info = new AddressInfo(jobj.getString("country_name"), jobj.getString("country_code"),
                jobj.getString("city"), lat, lng,
                GeocodeService.getAddressByLatLng(lat, lng, "ja"));
        return info;
    }
    public static StringBuilder getResponse(String path){
        try {
            java.net.URL url = new java.net.URL(path);
            java.net.HttpURLConnection uc = (java.net.HttpURLConnection) url.openConnection();
            uc.setRequestProperty("User-agent", "Mozilla/5.0");

            uc.setRequestProperty("Accept-Charset", "UTF-8"); // encoding
            uc.setReadTimeout(30000);// timeout limit
            uc.connect();// connect
            int status = uc.getResponseCode();

            switch (status) {
                case java.net.HttpURLConnection.HTTP_GATEWAY_TIMEOUT://504 timeout
                    break;
                case java.net.HttpURLConnection.HTTP_FORBIDDEN://403 forbidden
                    break;
                case java.net.HttpURLConnection.HTTP_INTERNAL_ERROR://500 server error
                    break;
                case java.net.HttpURLConnection.HTTP_NOT_FOUND://404 not exist
                    break;
                case java.net.HttpURLConnection.HTTP_OK: // ok
                    InputStreamReader reader = new InputStreamReader(uc.getInputStream(), "UTF-8");

                    int ch;
                    StringBuilder sb = new StringBuilder("");
                    while((ch = reader.read())!= -1){
                        sb.append((char)ch);
                    }
                    return sb;
            }

        } catch (java.net.MalformedURLException e) { // invalid address format
            e.printStackTrace();
        } catch (java.io.IOException e) { // connection broken
            e.printStackTrace();
        }
        return null;
    }
}
class AddressInfo {
    private String _countryName;
    private String _countryCode;
    private String _city;
    private double _lat;
    private double _lng;
    private String _formattedAddress;
    AddressInfo (String countryName, String countryCode,
        String city, double lat, double lng, String formattedAddress) {
        _countryName = countryName;
        _countryCode = countryCode;
        _city = city;
        _lat = lat;
        _lng = lng;
        _formattedAddress = formattedAddress;
    }
    public String getCountryName () {
        return _countryName;
    }
    public String getCountryCode () {
        return _countryCode;
    }
    public String getCity () {
        return _city;
    }
    public double getLat () {
        return _lat;
    }
    public double getLng () {
        return _lng;
    }
    public String getFormattedAddress () {
        return _formattedAddress;
    }
}


function added to GeocodeService.java

The new function returns formatted address by given lat/lng

    /**
     * return formatted address by given lat/lng
     * @param lat
     * @param lng
     * @param lang
     * @return
     */
    public static String getAddressByLatLng (double lat, double lng, String lang) {
        StringBuilder sb = getResponse("http://maps.googleapis.com/maps/api/geocode/json?"
                + "latlng="+lat+","+lng
                + "&sensor=true&language="+lang);
        JSONObject jobj = JSONObject.fromObject(sb.toString());
        return jobj.getJSONArray("results").getJSONObject(0).getString("formatted_address");
    }


The Result

http://maps.googleapis.com/maps/api/geocode/json?latlng=33.7629,-84.4226&sensor=true&language=ja
UNITED STATES
US
Atlanta, GA
33.7629
-84.4226
1068 Simpson Rd NW, アトランタ ジョージア 30314 アメリカ合衆国


Reference

http://stackoverflow.com/questions/2362413/any-reliable-api-available-to-determine-users-city-and-country-from-ip-address


Download

sample code at github
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/Practice/JAVA/Net/src/test/IPLookupService.java
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/Practice/JAVA/Net/src/test/GeocodeService.java

Thursday, January 26, 2012

JSP Practice: Simple chat

This post is about a simple JSP chat page, it's really simple, contains only:
2 jsp pages,
3 servlet,
1 css file
1 js file

and it use servlet3 annotation to do config so no web.xml

described as follows:

index.jsp

<%@ page isErrorPage="true" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<html>
    <head>
        <meta http-equiv="Content-Type" 
            content="text/html; charset=UTF-8"/>
        <title>Login page</title>
    </head>
    <body>
        <form action="login.go" method="post">
            <span>Type a name then press login to enter chat room</span>
            <input id="userId" type="text" value="Your ID" name="uid" />
            <input type="submit" value="login"/>
        </form>
    </body>
</html>

only a form, post to login.go with the user id

Login.java

package test.jsp.simplechat;

import java.io.IOException;
import java.util.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name="LoginServlet", urlPatterns={"/login.go"},
        loadOnStartup=1)
public class Login extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        String uid = new String(req.getParameter("uid").getBytes("ISO-8859-1"), "UTF-8");
        String newUid = uid;
        int i = 2;
        Map chat = Chat.getChatMap();
        synchronized (chat) {
            // prevent uid conflict
            if ("you".equalsIgnoreCase(newUid))
                newUid = uid + i++;
            while (chat.containsKey(newUid))
                newUid = uid + i++;
            uid = newUid;
            chat.put(uid, new ArrayList());
        }
        req.getSession().setAttribute("UID", uid);
        resp.sendRedirect("chat.jsp");
    }
}

the login servlet, check the user id here, if the user id is 'you' then append a number to it, because 'you' is a key word for display self message. Also append number to solve any id conflict.

Note the

String uid = new String(req.getParameter("uid").getBytes("ISO-8859-1"), "UTF-8");

is required or the utf-8 char will not stored to map correctly.

Finally store uid in session then redirect to chat.jsp

chat.jsp

<%@ page isErrorPage="true" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isELIgnored ="false" %>
<!-- Redirect to index.jsp if no UID -->
<c:if test="${UID == null}">
    <c:redirect url="index.jsp" />
</c:if>
<html>
    <head>
        <meta http-equiv="Content-Type" 
            content="text/html; charset=UTF-8"/>
        <title>Login page</title>
        <link href="css/chat.css" rel="stylesheet" type="text/css">
        <script type="text/javascript" src="js/chat.js"></script>
    </head>
    <body>
        <form action="logout.go" method="post">
            <div>This is chat page</div>
            <div>Type message then press ENTER key to send message</div>
            <div>Click logout to return the login page</div>
            <div>Your name: <span id="uid">${UID}</span></div>
            <div id="content" class="content"></div>
            <div>
                <!-- listen to keyup to send message if enter pressed -->
                <textarea class="msg-input" onkeyup="chat.dokeyup(event);">input text here</textarea>
            </div>
            <input type="submit" value="logout" />
        </form>
    </body>
</html>

First check UID and redirect to 'login.jsp' if UID is not in session.
link to style and js file, there is a timer will start while load js file.
listen to keyup event of input area to send content if enter pressed,
logout if logout button clicked.

chat.js

// init
window.chat = {};

// post to send message to chat.do
chat.sendMsg = function (msg) {
    var request;

    msg = msg.replace(/&/g, '&amp;') // encode to prevent XSS
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/\n/g, '<br />'); // replace textarea newline to line break tag
    alert(msg);
    if (request = this.getXmlHttpRequest()) {
        request.open('POST', 'chat.do?action=send&msg='+msg+'&time='+new Date().getTime());
        request.send(null);
        chat.updateContent('<div>You said: '+msg+'</div>');
    }
};

// post 'get' action to chat.do to require new message if any
chat.startListen = function () {
    if (!chat.listen)
        chat.listen = setInterval (function () {
            var request;
            if (request = chat.getXmlHttpRequest()) {
                request.open('POST', 'chat.do?action=get&time='+new Date().getTime());
                request.send(null);
                request.onreadystatechange = function() {
                    if(request.readyState === 4) {
                        if(request.status === 200) {
                            var json = request.responseText;
                            // has new message
                            if (json && json.length) {
                                // parse to array
                                var obj = eval('(' + json + ')');
                                var msg = '';
                                for (var i = 0; i < obj.length; i++) {
                                    msg += '<div>'+obj[i]+'</div>';
                                }
                                chat.updateContent(msg);
                            }
                        } else if(request.status === 400 || request.status === 500)
                            document.location.href = 'index.jsp';
                    }
                };
            }
        }, 3000);
};

chat.updateContent = function (msg) {
    var content = document.getElementById('content'),
        atBottom = (content.scrollTop + content.offsetHeight) >= content.scrollHeight;
    content.innerHTML += msg;
    // only scroll to bottom if it is at bottom before msg added
    if (atBottom)
        content.scrollTop = content.scrollHeight;
};
chat.dokeyup = function (event) {
    if (!event) // IE will not pass event
        event = window.event;
    if (event.keyCode == 13 && !event.shiftKey) { // ENTER pressed
        var target = (event.currentTarget) ? event.currentTarget : event.srcElement,
            value = target.value;
        // make sure not only space char
        if (value && value.replace(/^\s\s*/, '').replace(/\s\s*$/, '').length > 0) {
            this.sendMsg(target.value);
            target.value = '';
        }
    }
};
// get the XmlHttpRequest object
chat.getXmlHttpRequest = function () {
    if (window.XMLHttpRequest
        && (window.location.protocol !== 'file:' 
        || !window.ActiveXObject))
        return new XMLHttpRequest();
    try {
        return new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) {
        throw new Error('XMLHttpRequest not supported');
    }
};
onload = function () {
    chat.startListen();
};

This file do two things,

It starts a timer after page loaded by chat.startListen();, it will periodically send an ajax request to server to get the latest message if any then put them into content div and scroll content to bottom as need.

The keyup event of input area will trigger the chat.dokeyup, then call chat.sendMsg if enter pressed and input area is not empty.

Chat.java

package test.jsp.simplechat;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;

@WebServlet(name="ChatServlet", urlPatterns={"/chat.do"},
  loadOnStartup=1)
public class Chat extends HttpServlet {
 /**
  * 
  */
 private static final long serialVersionUID = 113880057049845876L;
 // message map, mapping user UID with a message list
 private static Map<String, List<String>> _chat = new HashMap<String, List<String>>();
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
  req.setCharacterEncoding("UTF-8");
  String action = req.getParameter("action");
  // send message
  if ("send".equals(action)) {
   // get param with UTF-8 enconding
   String msg = new String(req.getParameter("msg").getBytes("ISO-8859-1"), "UTF-8");
   String uid = (String)req.getSession().getAttribute("UID");
   for (String s : _chat.keySet()) {
    if (!s.equals(uid)) {
     synchronized (_chat.get(s)) {
      // put message to any other user's msg list
      _chat.get(s).add(uid+" said: "+msg);
     }
    }
   }
  } else if ("get".equals(action)) { // get message
   String uid = (String)req.getSession().getAttribute("UID");
   if (uid == null)
    resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
   List<String> l = _chat.get(uid);
   synchronized (l) {
    if (l.size() > 0) {
     // for UTF-8 chars
     resp.setCharacterEncoding("UTF-8");
     PrintWriter out = resp.getWriter();
     JSONArray jsna = new JSONArray();
     // add all msg to json array and clear list
     while (l.size() > 0)
      jsna.add(l.remove(0));

     out.println(jsna);
     out.close();
    }
   }
  }
 }
 public static Map<String, List<String>> getChatMap () {
  return _chat;
 }
}

This class hold a map which mapping the user id with a message list,
when a user request send the message, it put the message to all other user's message list.
when a user request get message, it put all message from that user's message list into a json array and write it to response writer.

chat.css

.content {
 width: 600px;
 height: 400px;
 overflow: auto; 
 border: 1px solid #991111;
}
.msg-input {
 width: 600px;
 border: 1px solid #119911;
}

simply style the content and message input area.

Logout.java

package test.jsp.simplechat;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name="Logout", urlPatterns={"/logout.go"},
        loadOnStartup=1)
// practice: invalidate session
public class Logout extends HttpServlet {
    /**
     * 
     */
    private static final long serialVersionUID = -6175876557872938832L;

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        req.getSession().invalidate();
        resp.sendRedirect("index.jsp");
    }
}

Simply invalidate the session and redirect to index.jsp

Download:
Download full project from github:
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/JSPChat

Dependency:
The required jar files:
commons-beanutils-1.8.3.jar
commons-collections-3.2.1.jar
commons-lang-2.5.jar
commons-logging-1.1.1.jar
ezmorph-1.0.6.jar
json-lib-2.4-jdk15.jar                     // these six are for json
jstl-1.2.jar                                      // this one is for JSTL

Wednesday, January 25, 2012

Basic Servlet Practice

A project of really basic practice, not good practice, just practice.

You can download the basic practice project from github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/BasicServletPractice

Description:

index.html

This page practice two things:
Use AJAX to get the hint of id and password,
it send the http get request to context 'auth.hint',

Use form submit to do login,
the submit form action is the http post to context 'login.go',

error.jsp

This is the error page defined in 'web.xml',
it simply display the exception message

the exception is from login servlet

content.html

This page practice JSON,
it use AJAX to get the content from ContentServlet,
and use eval method to transfer the content to array,
the array combined by a string and two inner array,
the first string is a javascript command which executed by eval method,
the two inner array are the content and displayed by that command.

If it receive the bad request status,
it will redirect to login page

Hint.java

This file practice set/get attribute from session,
output the text to client and config servlet by annotation.

It provide the hint of id and password,
or show alert message if ask too much times.

Login.java

This file practice get parameter from request,
redirect to another page.
It config in web.xml

It get the input id and password,
if it is correct, redirect to content page,
throw ServletException with message 'Login fail' otherwise

Content.java

This file practice JSON,
it also config by annotation.

It create two small JSON array,
then put a command that will execute at client and
the two small array into a big one.

** To use JSON, the jars below are required
json-lib-2.4-jdk15.jar, ezmorph-1.0.6.jar, commons-logging-1.1.1.jar,
commons-lang-2.5.jar, commons-collections-3.2.1.jar, commons-beanutils-1.8.3.jar

Ref: http://json-lib.sourceforge.net/

Logout.java

This file invalidate the session then redirect to login page.

ReqFilter.java

This file practice the filter, and config filter by annotation

This is a filter protect the content page,
it triggered by the 'content.gen' context
(the content page send request to it to get content)

if a session do not contain the 'Login' data,
the request can not pass this filter and will get the 'bad request' status.