Wednesday, January 20, 2010

Using Hibernate Transformers

There are times we have a class, we would like to fill with data according the data returned from a query. The class is a simple POJO and not an Hibernate entity, so Hibernate won’t recognize this class.
This can be done in Hibernate by using Transformers. Let’s have a look on a simple example, showing how Transformers can be used. First, let’s have a look at a simple POJO class named: “UserActivityStat”.
This class contains some statistical information. We would like to fill the statistical information of an instance, directly from running an Hibernate HQL.
public class UserActivityStat
{
private int totalPhotos;
private int totalViews;

public UserActivityStat() {
}

public int getTotalPhotos() {
return totalPhotos;
}

public void setTotalPhotos(int totalPhotos) {
this.totalPhotos = totalPhotos;
}

public int getTotalViews() {
return totalViews;
}

public void setTotalViews(int totalViews) {
this.totalViews = totalViews;
}
}
Now, let’s have a look at a simple method, that uses hibernate HQL and the Transformers class to fill “UserActivityStat” instance with data:
public UserActivityStat getUserActivityStat(User user)
{
return (UserActivityStat)hibernateSession.createQuery("select count(*) as totalPhotos, sum(p.views) as totalViews " +
"from Photo p where p.user = :user " +
"p.dateCreated  <= :now").
setParameter("user", user).
setTimestamp("now", new Date()).
setResultTransformer(Transformers.aliasToBean(UserActivityStat.class)).uniqueResult();
}
Note, that each of the 2 columns has an alias. This alias must be the name of the property on the “UserActivityStat” class. Also note for the use of the “setResultTransformer” along the “Transformers” class.

Tuesday, January 19, 2010

Calculate the distance between 2 Ips in Java using maxmind

Calculating the distance between 2 ips can be done easily by using the great geo service: Maxmind.

Maxmind is an affordable geo service with broad range of solutions like:

  • Country
  • City
  • Organization
  • ISP

and more…

Maxmind services comes in 2 flavors:

  • Paid service: This is very accurate data, in a reasonable low cost.
  • Free service: This is a little less accurate data, but a totally free service.

In order to calculate the distance between 2 IPs, we will use the free version of Maxmind. The free service is called: geoLite. we will use the service named: geoLite city. The geoLite city data contains location information. The location contains latitude and longitude information for ip ranges. Latitude and longitude information is a coordinate method used in may location services such GPS.

In order to use Maxmind we need 2 things:

Calculating the distance between 2 IPs is very easy, since Maxmind did all the hard work for us. We just have to get “Location” instance for the 2 IP and use the “distance” method of the “Location” instance. The returned result is the distance between the 2 IPs in kilometers.

Let’s have a look at a sample code that calculates the distance between Google and Apple:

package com.bashan.blog.maxmind;
import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;
import java.io.IOException;
/**
 * @author Bashan
 */
public class MaxmindTest {
  public static void main(String args[]) throws Exception {
    LookupService lookupService = new LookupService("C:\\GeoLiteCity.dat");
    Location locationGoogle = lookupService.getLocation("74.125.39.147");
    Location locationMicrosoft = lookupService.getLocation("17.251.200.70");
    System.out.println("Google is located on: " + locationGoogle.city);
    System.out.println("Apple is located on: " + locationMicrosoft.city);
    System.out.print("Distance: " + locationGoogle.distance(locationMicrosoft) + " kilometers");
  }
}

And the output:

Google is located on: Mountain View
Apple is located on: Cupertino
Distance: 13.218970226605398 kilometers
Not too far as you can see… ;-)

Saturday, January 16, 2010

Get real IP from request in Java

Simply getting the IP of the remote client in Java is an easy task. Assuming we have a request instance, we can simply invoke the “getRemoteAddr” method:

request.getRemoteAddr();

The problem, is that the IP we get is not always the correct IP. For example if our server is behind a load balancer, the method “request.getRemoteAddr” returns the IP of the load balancer and not the IP of the remote client. Another common example, is that the client is behind some proxy or even several proxies. The IP we will get will not be the correct IP.

Fortunately, In most of the cases when a request passes in a load balancer or a proxy, the IP of the remote client is passed in the header of the request. The header key most of the time is: x-forwarded-for. The header value can be one or more IP addresses. The first address, is the address of the remote client. The second or any other IP is the IP of the proxy on the way. The IP of the last proxy is the IP returned in: “request.getRemoteAddr”. For example, if we have 3 proxies, the request header will look like:

x-forwarded-for: client1, proxy1, proxy2

The IP of the client if the first IP. The IP of the third proxy will be returned when calling to: “request.getRemoteAddr”.

There is one none-common case that may happen. The first IP can be an IP of a private network (for example, an IP that starts with “192” or “10”). I such case we will want to take the second IP.

Writing a Java code that will get the IP from the request is quite easy. We will use assistance from code of these older posts: Convert IP String to numeric representation and numeric representation to IP String in Java, Test if IPv4 belongs to a private network address. The general logic of the code is:

  • Look for “x-forwarded-for” header.
  • If header exists, get the first IP.
  • Check that:
    • IP is valid.
    • IP is not a private IP.
  • If IP passes these 2 tests. Return this IP. If not move to the next IP and do the same test and so on.
  • If header doesn’t exist. Return the IP from calling “request.getRemoteAddr”.

Let’s see how it looks in Java:

package com.bashan.blog.ip;
import org.apache.commons.lang.text.StrTokenizer;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Pattern;
/**
 * @author Bashan
 */
public class IpUtils {
  public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
  public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");
  public static String longToIpV4(long longIp) {
    int octet3 = (int) ((longIp >> 24) % 256);
    int octet2 = (int) ((longIp >> 16) % 256);
    int octet1 = (int) ((longIp >> 8) % 256);
    int octet0 = (int) ((longIp) % 256);
    return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
  }
  public static long ipV4ToLong(String ip) {
    String[] octets = ip.split("\\.");
    return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16) +
        (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
  }
  public static boolean isIPv4Private(String ip) {
    long longIp = ipV4ToLong(ip);
    return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255")) ||
        (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255")) ||
        longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
  }
  public static boolean isIPv4Valid(String ip) {
    return pattern.matcher(ip).matches();
  }
  public static String getIpFromRequest(HttpServletRequest request) {
    String ip;
    boolean found = false;
    if ((ip = request.getHeader("x-forwarded-for")) != null) {
      StrTokenizer tokenizer = new StrTokenizer(ip, ",");
      while (tokenizer.hasNext()) {
        ip = tokenizer.nextToken().trim();
        if (isIPv4Valid(ip) && !isIPv4Private(ip)) {
          found = true;
          break;
        }
      }
    }
    if (!found) {
      ip = request.getRemoteAddr();
    }
    return ip;
  }
}

Note that the class “StrTokenizer” used to iterate the IPs of the header, is the Apache version from Apache commons lang.

You can download the class here.

Friday, January 15, 2010

Test if IPv4 belongs to a private network address

Sometime we need to check if a given IP belongs to a private network. IP of a private network belong to a special range of IPs. It is most likely, that if you have a small local network at your home or work, the IP in that network is starting with “192” or “10”. For example: “192.168.0.1” or “10.0.0.1”.

The ranges of private network IPs is:



STARTEND
10.0.0.010.255.255.255
172.16.0.0 172.31.255.255
192.168.0.0 192.168.255.255

Since we are dealing here with range of IPs, it will be much easier to convert the IPs to long representation. We will use the code from this blog: Convert IP String to numeric representation and numeric representation to IP String in Java, to easily do the job.

Let’s have a look at the function “isIPv4Private”:

package com.bashan.blog.ip;
/**
 * @author Bashan
 */
public class IpUtils {
  public static String longToIpV4(long longIp) {
    int octet3 = (int) ((longIp >> 24) % 256);
    int octet2 = (int) ((longIp >> 16) % 256);
    int octet1 = (int) ((longIp >> 8) % 256);
    int octet0 = (int) ((longIp) % 256);
    return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
  }
  public static long ipV4ToLong(String ip) {
    String[] octets = ip.split("\\.");
    return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16) +
        (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
  }
  public static boolean isIPv4Private(String ip)
  {
    long longIp = ipV4ToLong(ip);
    return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255")) ||
        (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255")) ||
        longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
  }
  public static void main(String[] args) {
    System.out.println(isIPv4Private("210.5.80.10"));
    System.out.println(isIPv4Private("192.168.0.1"));
  }
}
You can download the class here.

Friday, December 25, 2009

Validating empty text field using JSF

JSF has a pretty comprehensive support for validations, but it is lack of a validation for an empty field. The built-in “required” property of JSF is not so usable, since it validates empty fields only. If a field has a space in it, JSF will accept it. In most scenarios, when inputting text in a form, a space (or several spaces) is considered to be an empty field. Since JSF doesn’t support “out of the box” validation for empty field, we will write our own Validator that will do the job.

Writing a JSF Validator mainly involves 3 things:

  1. Writing the Validator code by implementing a JSF Validator interface.
  2. Registering Validator in JSF faces-config.xml.
  3. Using the Validator in a JSF page.

In order to write the Validator we have to implement “validate” method of Validator interface. This method will be called automatically by JSF, when we use the Validator in some of our input fields. Our Validator class simply checks that the field value is not empty. If the field is empty a ValidationException is thrown from the Validator. JSF mechanism knows to treat this exception as a validation error, when it checks the form inputs for validation errors. Let’s have a look at the Validator code:

package com.bashan.blog.jsf.validator;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
/**
 * @author Bashan
 */
public class RequiredValidator implements Validator {
  public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    if (value == null || "".equals(value.toString().trim())) {
      FacesMessage message = new FacesMessage();
      String messageStr = (String)component.getAttributes().get("message");
      if (messageStr == null) {
        messageStr = "Please enter data";
      }
      message.setDetail(messageStr);
      message.setSummary(messageStr);
      message.setSeverity(FacesMessage.SEVERITY_ERROR);
      throw new ValidatorException(message);
    }
  }
}

Note, that the Validator tries to get an attribute named “message” from the component for which it is attached. The “message” attribute should contain a custom error message to show to the user. If “message” attribute is not used, a default error message: “Please enter data” is shown to the user.

Now, let’s register the Validator in JSF faces-config.xml file. This file should be located under the “WEB-INF” directory by default:

<?xml version="1.0" encoding="windows-1255"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config> 
  <validator>
    <validator-id>RequiredValidator</validator-id>
    <validator-class>com.bashan.blog.jsf.validator.RequiredValidator</validator-class>
  </validator>
</faces-config>

You can see in this “faces-config.xml” file the validator id, which is used to call the validator from a JSF page, and the JSF class corresponds to this validator id.

Finally, let’s have a look how this validator is used in a JSF page:

<h:inputTextarea id="someText" value="#{support.message}" styleClass="textarea1" required="true" requiredMessage="Please write something">
  <f:attribute name="message" value="Please write something" />
  <f:validator validatorId="RequiredValidator" />             
</h:inputTextarea>
<div>
  <h:message for="someText" styleClass="error"/>
</div>

This is only a fragment of a JSF page, showing a text area control and a message under it. Note, that the control can be any JSF input like <h:inputText />. Also note for the <f:attribue /> control used for sending a custom message to the Validator. Another important thing worth mentioning, it that the “required” attribute of the <h:inputTextArea /> control is also used with the same error message (using the “requiredMessage” property). One can say, using 2 validations is redundant, and that only the “RequiredValidator” could have been used. This was true, unless JSF mechanism had a problematic issue with empty fields: When field is empty (has no value and no spaces) validators and converters are not invoked. For this reason, both “required” and “RequiredValidtor” are needed to be used.

Monday, December 21, 2009

Tomcat Virtual Hosting

Tomcat is not only a servlet container. It supports many of the features of any HTTP web server and can be also used to serve static content as well. From my experience, it can handle heavy traffic quite decently. It doesn’t fall from it’s big brother: Apache Server, and frankly, there are times it seem to be functioning even better.

One of Tomcat’s features, is Virtual Hosting. Virtual Hosting means that a single web server can server more than one website at the same time. The server knows which website to server according to the domain of the request. For example, if you have 2 domains: http://one.com and http://two.com and you direct both domains to the same IP, the server will get requests from 2 different domains. Then it should know to serve “one” website to requests coming from domain http://onew.com and “second” website to requests coming from domain http://two.com.

Configuring Tomcat to support Virtual Hosting is an easy task. The configuration takes place in Tomcat’s server.xml file, which is placed under the “conf” directory. Inside the “Engine” xml tag, “Host” element should be added for every domain you would like to serve. For example, if we have a web application named “one” and a domain named: http://one.com, The “Host” element should look like:

<Host name="one.com" appBase="webapps/one">
  <Context path="" docBase="" debug="0"/>
  <Alias>www.one.com</Alias>
</Host>

Note that “one” is places under “webapps” which is Tomcat’s natural directory for web applications. Therefore, a relative path is used. In addition, take a look at the alias: www.one.com. That will allow the server to acept traffic from both: http://one.com and http://www.one.com.
Let’s have a look at a full server.xml example file, which defines 2 virtual hosts for 2 web applications: “one” and “two”:
<?xml version='1.0' encoding='utf-8'?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You 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.
-->
<!-- Note:  A "Server" is not itself a "Container", so you may not
     define subcomponents such as "Valves" at this level.
     Documentation at /docs/config/server.html
 -->
<Server port="8005" shutdown="SHUTDOWN">
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container",
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
  <Service name="Catalina">

    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->
 
 
    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
    -->
    <Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" disableUploadTimeout="true" compression="on" compressableMimeType="text/html,text/xml,text/plain,application/xml"/>
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->        
    <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->
    <!--
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <!-- An Engine represents the entry point (within Catalina) that processes
         every request.  The Engine implementation for Tomcat stand alone
         analyzes the HTTP headers included with the request, and passes them
         on to the appropriate Host (virtual host).
         Documentation at /docs/config/engine.html -->
    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">      
    -->
    <Engine name="Catalina" defaultHost="localhost">
      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->     
      <!-- The request dumper valve dumps useful debugging information about
           the request and response data received and sent by Tomcat.
           Documentation at: /docs/config/valve.html -->
      <!--
      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
      -->
      <!-- This Realm uses the UserDatabase configured in the global JNDI
           resources under the key "UserDatabase".  Any edits
           that are performed against this UserDatabase are immediately
           available for use by the Realm.  -->
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
      <!-- Define the default virtual host
           Note: XML Schema validation will not work with Xerces 2.2.
       -->
      <!--Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false"-->
        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->
        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
        -->
      <!--/Host-->
  <Host name="one.com" appBase="webapps/one">
   <Context path="" docBase="" debug="0"/>
   <Alias>www.one.com</Alias>
  </Host>
  <Host name="two.com" appBase="webapps/two">
     <Context path="" docBase="" debug="0"/>
     <Alias>www.two.com</Alias>
  </Host>
    </Engine>
  </Service>
</Server>

Note, that I remarked Tomcat’s default “Host” element:

<!--Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false"-->

Remarking the default “Host” element is necessary. Otherwise Tomcat will simply load each web application twice: one for the default host definition and the second for the virtual host definition.