Thursday, May 11, 2006

Convert IP from String to long

I wrote this for work, but we didn't need it. So in case someone else needs a java routine to convert an ip address from String to long and back again (and it needs to be compatible w/ the method used by Unix), here it is....


package com.td.wss.docs.util;

import java.util.StringTokenizer;

public class IpUtil
{
public static long ipToLong(String ip)
{
StringTokenizer thisTok=new StringTokenizer(ip, ".", false);

long outLong=0;

outLong += Long.parseLong((String)thisTok.nextElement()) << 24;
outLong += Long.parseLong((String)thisTok.nextElement()) << 16;
outLong += Long.parseLong((String)thisTok.nextElement()) << 8;
outLong += Long.parseLong((String)thisTok.nextElement());

return outLong;
}


public static String longToIp(long ip)
{
String ip0, ip1, ip2, ip3;

ip3 = String.valueOf((ip >> 24));
ip2 = String.valueOf((ip & 0x00FF0000) >> 16);
ip1 = String.valueOf((ip & 0x0000FF00) >> 8);
ip0 = String.valueOf((ip & 0x000000FF));

return ip3 + "." +
ip2 + "." +
ip1 + "." +
ip0;
}

/**
* Results should match http://www.t1shopper.com/tools/calculate/ip-subnet/
* @param args
*/
public static void main(String[] args)
{
// Test1
runTest("255.255.255.255");

// Test2
runTest("127.0.0.1");

// Test3
runTest("0.0.0.0");

// Test4
runTest("12.33.158.6");

}

private static void runTest(String ip)
{
long result = ipToLong(ip);
System.out.println("ip=" + ip + " as long " + result);

String ipStr = longToIp(result);
System.out.println("ip=" + result + " as ip " + ipStr);
}

}

Wednesday, July 20, 2005

Using commons EqualsBuilder in JUnit tests

A common JUnit test w/ databases is to create an object (or hierarchy of objects), save them, and then retrieve them back. You want to see if what you put in is what you get out.

These tests can be cumbersome to write, becuase comparing the inserted object with the fetched object will require the following test for each attribute of the class.


assertEquals( insertedObj.getAttribute1(),
fetchedObj.getAttribute1() );


So if there are 20 attributes, you have 20 assertEquals() to perform. And if you should happen to have a collection of child objects too, well, you've really got your work cut out for you.

So one way around this is to use the commons EqualsBuilder class and it's reflectionEquals() method.


import org.apache.commons.lang.builder.EqualsBuilder;
....
public void testStuff()
{
assertTrue("Compare inserted obj w/ fetched obj",
EqualsBuilder.reflectionEquals(insertedObj, fetchedObj));
}


This will do a full comparison of the objects on all of their attributes, instead of using their equals methods. And if you have a collection in your class, it will take the collections and compare them. At the collection level, however, it reverts back to the equals() method on the children of the respective collections (95% sure about that).

Monday, July 04, 2005

Hibernate 2.1.x, calling save() on same object twice causes two INSERTS

Hibernate is not performing as I would expect. When I am saving for the second time, it generates a second insert statement (as opposed to an UPDATE for the 2nd call). It probably has something to do with the specifics of my situation. I am....
  • creating an object

  • saving it within a session

  • later, i try updating this same object handle within the same session (i.e. no re-retrieve)

I really would like to do everything with the save() method, but it seems the solution (for now) lies in which API call I use.
  • save() seems geared towards new instances

  • update() seems geared towards existing ones

Theoretically, there should only be one call, and hibernate should determine this for me. There are references to a method called saveOrUpdate(), but it should only be used when sharing objects across sessions.

Tuesday, June 28, 2005

Hibernate 2.1.x Child Insert Problem - Composite Key On Child

While using hibernate, my parent-child relationship was having (approx.) the following issue.

"Assigned identifiers, including composite identifiers, can't be used to distinguish newly instantiated instances from instances saved or loaded in a previous session. You will need to provide some other way for Hibernate to distinguish."

...which is from this post...

The Interceptor solution is not clearly stated. (the other solutions only seem to work if you have a timestamp/version field in your table, which I don't) The solution is....

Make your model class extend this.


public class Persistent {
private boolean _saved = false;
public void onSave() {
_saved = true;
}
public void onLoad() {
_saved = true;
}
public boolean isSaved() {
return _saved;
}
}


And use this Interceptor when you create your hibernate session.


import java.io.Serializable;
import java.util.Iterator;

import com.td.wss.ft.model.Persistent;

import net.sf.hibernate.CallbackException;
import net.sf.hibernate.Interceptor;
import net.sf.hibernate.type.Type;

public class CompositeKeyFixInterceptor implements Interceptor, Serializable {

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#onLoad(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], net.sf.hibernate.type.Type[])
*/
public boolean onLoad(
Object entity,
Serializable id,
Object[] state,
String[] propertyName,
Type[] types) {

if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
return false;
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], net.sf.hibernate.type.Type[])
*/
public boolean onFlushDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyName,
Type[] types)
throws CallbackException {

return false;
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#onSave(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], net.sf.hibernate.type.Type[])
*/
public boolean onSave(
Object entity,
Serializable id,
Object[] state,
String[] propertyName,
Type[] types) {

if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
return false;
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#onDelete(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], net.sf.hibernate.type.Type[])
*/
public void onDelete(
Object entity,
Serializable id,
Object[] state,
String[] propertyName,
Type[] types)
throws CallbackException {

// do nothing
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#preFlush(java.util.Iterator)
*/
public void preFlush(Iterator entities) throws CallbackException {
// do nothing
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#postFlush(java.util.Iterator)
*/
public void postFlush(Iterator entities) throws CallbackException {
// do nothing
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#isUnsaved(java.lang.Object)
*/
public Boolean isUnsaved(Object entity) {
if (entity instanceof Persistent) {
return new Boolean( !( (Persistent) entity ).isSaved() );
} else {
return null;
}
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#findDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], net.sf.hibernate.type.Type[])
*/
public int[] findDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyName,
Type[] types) {

return null;
}

/* (non-Javadoc)
* @see net.sf.hibernate.Interceptor#instantiate(java.lang.Class, java.io.Serializable)
*/
public Object instantiate(Class clazz, Serializable id)
throws CallbackException {

return null;
}

}