package com.docuverse.identicon;
import java.net.InetAddress;
import java.security.MessageDigest;
/**
* Utility methods useful for implementing identicon functionality. Methods are
* class methods for convenience.
* <p>
* Key method of interest is {@link #getIdenticonCode} which converts IP address
* into identicon code.<br>
* <strong>IMPORTANT</strong>: <code>inetSalt</code> value must be set to
* reasonably long random string prior to invoking this method.
* </p>
*
* @author don
*/
public class IdenticonUtil {
private static final int DEFAULT_IDENTICON_SIZE = 16;
private static final int MINIMUM_IDENTICON_SIZE = 15;
private static final int MAXIMUM_IDENTICON_SIZE = 64;
private static final int DEFAULT_INET_MASK = 0xffffffff;
private static int inetMask = DEFAULT_INET_MASK;
private static String inetSalt;
/**
* Returns current IP address mask. Default is 0xffffffff.
*
* @return current IP address mask
*/
public static int getInetMask() {
return inetMask;
}
/**
* Sets current IP address mask. Default is 0xffffffff.
*
* @param inetMask
*/
public static void setInetMask(int inetMask) {
IdenticonUtil.inetMask = inetMask;
}
/**
* Returns current inetSalt value.
*
* @return the value
*/
public static String getInetSalt() {
return inetSalt;
}
/**
* Sets current inetSalt value.
*
* @param inetSalt
*/
public static void setInetSalt(String inetSalt) {
IdenticonUtil.inetSalt = inetSalt;
}
/**
* Returns identicon code for given IP address.
* <p>
* Current implementation uses first four bytes of SHA1(int(mask(ip))+salt)
* where mask(ip) uses inetMask to remove unwanted bits from IP address.
* Also, since salt is a string for convenience sake, int(mask(ip)) is
* converetd into a string and combined with inetSalt prior to hashing.
* </p>
*
* @param inetAddr
* IP address
* @return identicon code for <code>inetAddr</code>
* @throws Exception
*/
public static int getIdenticonCode(InetAddress inetAddr) throws Exception {
if (inetSalt == null)
throw new Exception(
"inetSalt must be set prior to retrieving identicon code");
byte[] ip = inetAddr.getAddress();
int ipInt = (((ip[0] & 0xFF) << 24) | ((ip[1] & 0xFF) << 16)
| ((ip[2] & 0xFF) << 8) | (ip[3] & 0xFF))
& inetMask;
StringBuilder s = new StringBuilder();
s.append(ipInt);
s.append('+');
s.append(inetSalt);
MessageDigest md;
md = MessageDigest.getInstance("SHA1");
byte[] hashedIp = md.digest(s.toString().getBytes("UTF-8"));
int code = ((hashedIp[0] & 0xFF) << 24) | ((hashedIp[1] & 0xFF) << 16)
| ((hashedIp[2] & 0xFF) << 8) | (hashedIp[3] & 0xFF);
return code;
}
/**
* Returns identicon code specified as an input parameter or derived from an
* IP address.
* <p>
* This method is a convenience method intended to be used by servlets like
* below:
* </p>
*
* <pre>
* int code = IdenticonUtil.getIdenticonCode(request.getParameter("code"), request
* .getRemoteAddr());
* </pre>
*
* @param codeParam
* code parameter, if <code>null</code> remoteAddr parameter
* will be used to determine the value.
* @param remoteAddr
* HTTP requester's IP address. Optional if code was specified.
* @return the code
*/
public static int getIdenticonCode(String codeParam, String remoteAddr) {
int code = 0;
try {
if (codeParam != null) {
code = Integer.parseInt(codeParam);
} else {
code = IdenticonUtil.getIdenticonCode(InetAddress
.getByName(remoteAddr));
}
} catch (Exception e) {
e.printStackTrace();
}
return code;
}
public static int getIdenticonSize(String param) {
int size = DEFAULT_IDENTICON_SIZE;
try {
String sizeParam = param;
if (sizeParam != null) {
size = Integer.parseInt(sizeParam);
if (size < MINIMUM_IDENTICON_SIZE)
size = MINIMUM_IDENTICON_SIZE;
else if (size > MAXIMUM_IDENTICON_SIZE)
size = MAXIMUM_IDENTICON_SIZE;
}
} catch (Exception e) {
e.printStackTrace();
}
return size;
}
public static String getIdenticonETag(int code, int size, int version) {
StringBuilder s = new StringBuilder("W/\"");
s.append(Integer.toHexString(code));
s.append('@');
s.append(size);
s.append('v');
s.append(version);
s.append('\"');
return s.toString();
}
}