26 Sep 2008
As everybody probably knows, Java only supports Big Endian streams but every once and a while you find yourself in the predicament of wanting to interface with a legacy system that wants to use little endian encoding. So I’m attaching a class that will allow you to use the nice DataInputStream API but that will read the data in little endian format.
*On a side note if you don’t know the difference between big and little endian or what the etymology of the term is. Endianess is basically to do start reading from the left most or right most bit (assuming bits were arranged in this fashion) you can find more information here. The term comes from Jonathan Swift’s satirical novel Gulliver’s Travels where there was a large disagreement about which side of one’s soft-boiled egg you should open.
public class LittleEndianDataInputStream extends InputStream implements DataInput {
public LittleEndianDataInputStream(InputStream in) {
this.in = in;
this.d = new DataInputStream(in);
w = new byte[8];
}
public int available() throws IOException {
return d.available();
}
public final short readShort() throws IOException
{
d.readFully(w, 0, 2);
return (short)(
(w[1]&0xff) << 8 |
(w[0]&0xff));
}
/**
* Note, returns int even though it reads a short.
*/
public final int readUnsignedShort() throws IOException
{
d.readFully(w, 0, 2);
return (
(w[1]&0xff) << 8 |
(w[0]&0xff));
}
/**
* like DataInputStream.readChar except little endian.
*/
public final char readChar() throws IOException
{
d.readFully(w, 0, 2);
return (char) (
(w[1]&0xff) << 8 |
(w[0]&0xff));
}
/**
* like DataInputStream.readInt except little endian.
*/
public final int readInt() throws IOException
{
d.readFully(w, 0, 4);
return
(w[3]) << 24 |
(w[2]&0xff) << 16 |
(w[1]&0xff) << 8 |
(w[0]&0xff);
}
/**
* like DataInputStream.readLong except little endian.
*/
public final long readLong() throws IOException
{
d.readFully(w, 0, 8);
return
(long)(w[7]) << 56 |
(long)(w[6]&0xff) << 48 |
(long)(w[5]&0xff) << 40 |
(long)(w[4]&0xff) << 32 |
(long)(w[3]&0xff) << 24 |
(long)(w[2]&0xff) << 16 |
(long)(w[1]&0xff) << 8 |
(long)(w[0]&0xff);
}
public final float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
public final double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
public final int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
public final void readFully(byte b[]) throws IOException {
d.readFully(b, 0, b.length);
}
public final void readFully(byte b[], int off, int len) throws IOException {
d.readFully(b, off, len);
}
public final int skipBytes(int n) throws IOException {
return d.skipBytes(n);
}
public final boolean readBoolean() throws IOException {
return d.readBoolean();
}
public final byte readByte() throws IOException {
return d.readByte();
}
public int read() throws IOException {
return in.read();
}
public final int readUnsignedByte() throws IOException {
return d.readUnsignedByte();
}
@Deprecated
public final String readLine() throws IOException {
return d.readLine();
}
public final String readUTF() throws IOException {
return d.readUTF();
}
public final void close() throws IOException {
d.close();
}
private DataInputStream d; // to get at high level readFully methods of
// DataInputStream
private InputStream in; // to get at the low-level read methods of
// InputStream
private byte w[]; // work array for buffering input
}
Download: LittleEndianDataInputStream.java
enjoy
26 Sep 2008
In a lot of the projects I work on the software we write must communicate with other live devices that speak a variety of protocols and testing using mock objects will only get you so far. That is why I like to capture actual data that is coming out of these devices and include it directly in my unit tests.
public class ByteArrayUtils {
private ByteArrayUtils() {}
public static byte[] fromHexString(final String encoded) {
if ((encoded.length() % 2) != 0)
throw new IllegalArgumentException("Input must contain " +
"an even number of characters");
final byte result[] = new byte[encoded.length()/2];
StringBuffer buf = new StringBuffer(encoded);
for (int i = 0; i < buf.length(); i += 2) {
result[i/2] = (byte) Integer.parseInt(buf.substring(i, i+2), 16);
}
return result;
}
public static String toHexString(byte[] data) {
if (data == null) return "";
StringBuffer buf = new StringBuffer(data.length * 2);
for (int i = 0; i < data.length; i++) {
String ch = Integer.toHexString(data[i] & 0xff);
if (ch.length() == 1) {
buf.append("0");
}
buf.append(ch);
}
return buf.toString();
}
}
Using this class allows me to convert byte arrays into strings that I can then include directly in my unit test cases. You can then inject the byte array into you code, and its just like having the real device there (well sorta)
25 Sep 2008
I’m sure that you know if you have a Tivo or not, but I’m providing a class based on the “Tivo Connect Automatic Machine Discovery Protocol Specification” that will listen for the Tivo UDP heartbeat and provide a notification when the heartbeat is detected.
Usage:
TivoLocator.getInstance().addListener(new TivoLocatorListener() {
public void processTivoHeartbeat(TivoInformation info) {
System.out.println("Tivo IP: " + info.getAddress());
}
});
The Tivo will send out these hearbeats about every 60 seconds or so. The TivoInformation class will tell you information such as:
Internet Address: getAddress()
Connect Method: getMethod()
Platform: getPlatform()
Machine Name: getMachineName()
Identity: getIdentity()
Services: getServices()
Software Version: getSwVersion()
Code: TivoLocator.java
Spec: TivoConnectDiscoverySpec.pdf
25 Sep 2008
The Levenshtein distance between two strings is given by the minimum number of operations needed to transform one string into the other, where an operation is an insertion, deletion, or substitution of a single character.
public class LevenshteinDistance {
private static int minOfThree(int a, int b, int c) {
return Math.min(a, Math.min(b, c));
}
private static int calculateCost(char s, char t) {
return s==t?0:1;
}
private static int[][] initializeMatrix(int s, int t) {
int[][] matrix = new int[s + 1][t + 1];
for (int i = 0; i <= s; i++) {
matrix[i][0] = i;
}
for (int j = 0; j <= t; j++) {
matrix[0][j] = j;
}
return matrix;
}
public static int computeLevenshteinDistance(final String s, final String t) {
char[] s_arr = s.toCharArray();
char[] t_arr = t.toCharArray();
if(s.equals(t)) { return 0; }
if (s_arr.length == 0) { return t_arr.length;}
if (t_arr.length == 0) { return s_arr.length;}
int matrix[][] = initializeMatrix(s_arr.length, t_arr.length);
for (int i = 0; i < s_arr.length; i++) {
for (int j = 1; j <= t_arr.length; j++) {
matrix[i+1][j] = minOfThree(matrix[i][j] + 1,
matrix[i+1][j - 1] + 1,
matrix[i][j - 1] + calculateCost(s_arr[i], t_arr[j-1]));
}
}
return matrix[s_arr.length][t_arr.length];
}
}
Algorithm Visualization: http://www-igm.univ-mlv.fr/~lecroq/seqcomp/node2.html
Code: LevenshteinDistance.java
25 Sep 2008
I know that this seems trivial, but there are a few gotchas that have burned me a few times so I thought I would post the solution here.
The API will lead you to write this
MulticastSocket socket = new MulticastSocket(6000);<br />
socket.setTimeToLive(16);
And you’ll feel pretty good about it, but then you will deploy your software only to find out that the packets aren’t clearing the first router hop. Then you’ll fire up ethereal and upon inspection you will notice that the TTL in the packet is 0. What the hell? You can clearly see where you set it to 16.
There is a small hiccup inside java where they have been blending the java.net API to be stack agnostic and if you are on a dual stack (IPv4 & IPv6) capable machine and are only using the IPv4 stack you need to notify the JVM by setting a special system property. This can be done two ways:
First you can set the property in code
Properties props = System.getProperties();<br />
props.setProperty("java.net.preferIPv4Stack","true");<br />
System.setProperties(props);<br />
I agree with you that the third line doesn’t look nessecary, but in my experiance it is. Or you can set this option from the command-line:
java -Djava.net.preferIPv4Stack=true -jar program.jar<br />
I hope this post helps, because I was ready to tear my hair out.