Saturday, May 7, 2011

JAR FINDER

While working on application, i always find the need to search directories containing all the jars to find a particular class file. So here is java code to search jars files from specified directory to find a class file.


Usage : java JarFind /usr/home/tomcat AuthenticatorBase.class

This will search AuthenticatorBase.class in all the jar files inside /usr/home/tomcat and display the result of all the match.

This is simple yet useful, at least i felt it is useful ;)




import java.io.File;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarFind {

public static ArrayList arraylist = new ArrayList();

public static void searchDir(String s, String s1) throws Exception {

File file = new File(s);
if (!file.exists() || !file.isDirectory()) {
System.out.println("Error cannot find the folder specified");

System.out.println(":)");
System.exit(0);
}
File afile[] = file.listFiles();
for (int i = 0; i < afile.length; i++)
if (!afile[i].isDirectory() && afile[i].getName().endsWith(".jar")) {
JarFile jarfile = new JarFile(afile[i]);
System.out.println("Scanning jar :" + afile[i]);
Enumeration enumeration = jarfile.entries();
do {
if (!enumeration.hasMoreElements())
break;
String s2 = enumeration.nextElement().toString();
s2 = s2.replace('/', '.');
if (s2.indexOf(s1) != -1
&& !arraylist.contains(afile[i].getPath()))
arraylist.add("Jar :" + afile[i].getPath()
+ " FileName :" + s2);
} while (true);
} else if (afile[i].isDirectory())
searchDir(afile[i].getPath(), s1);

}

public static void main(String args[]) throws Exception {
if (args.length < 2) {
System.out.println("Format: JarFind rootfolder pattern");
System.exit(0);
}
String s = args[0];
String s1 = args[1];
searchDir(s, s1);
System.out.println("");
System.out.println("");
System.out.println("");
System.out.println("------------------");
System.out.println(arraylist.size() + " Result Found");
System.out.println("------------------");
System.out.println("");

for (String str : arraylist) {
System.out.println(str);
}
}



}


Class version Finder

What version of java compiler has compiled my class file ?

What happens when we do bulldozed our java code with javac?

A class file is created in bytecode format.A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit quantities are constructed by reading in two, four, and eight consecutive 8-bit bytes, respectively. Multibyte data items are always stored in big-endian order, where the high bytes come first. In the Java and Java 2 platforms, this format is supported by interfaces java.io.DataInput and java.io.DataOutput and classes such as java.io.DataInputStream and java.io.DataOutputStream.

How do we know if class file is valid class file and with which version of java compiler it is been compiled ?

In a valid class file,
first four byte is hardcoded hexadecimal number(also known as magic number or Hexspeak) as 0xCAFEBABE.
next two byte contains the minor version of the compiler that compiled the class file.
next two byte contains the major version of the compiler that compiled the class file.
rest of the file contains about class name , super class, fields, methods etc.

A complete structure of a class file is as follows
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}

Open the class file in your favroute hex editor and and it will look llike this

"000000000 CA FE BA BE 00 00 00 2E-00 AD 0A 00 35 00 45 08 |Êþº¾
"000000010 00 46 08 00 47 0A 00 48-00 49 07 00 4A 0A 00 05 |
"000000020 00 4B 0A 00 05 00 4C 0A-00 05 00 4D 09 00 4E 00 |
.............................
.............................

Notice the first four byte is CA FE BA BE (the magic number). JVM will first look ou for this magic number if not present will throw java.lang.ClassFormatError.

Next two byte is 00 00 which is minor version.
Next two byte is 00 2E which is major version. As mentioned earlier multibyte data are stored in big-endian order. Here 2E is hexadecimal format of 46 ( JDK 1.2)


Possible major/minor value :
major           minor               Java platform version
45                3                     1.0
45                3                     1.1
46                0                     1.2
47                0                     1.3
48                0                     1.4
49                0                     1.5
50                0                     1.6

JAVA Program to identify the version of class file compiler


import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.*;

public class FindVersion {

 /**
  * @param args
  */
 public static void main(String[] args)throws Exception {
  // TODO Auto-generated method stub
  //System.out.println(args.length!=1);
  if (args.length != 1)
  {
   System.out.println("Usage :");
   System.out.println("java FindVersion ");
   System.exit(1);
  }
  DataInputStream data=null;
  String sfile=args[0];
  File file =new File(sfile);
  if (file.exists() && file.isFile()){
   data =new DataInputStream(new FileInputStream(file));
  }
  else{
   System.out.println("File not found :(");
      System.exit(1);
  }
  int magic= data.readInt();
  //System.out.println(magic);
  if (magic!=0XCAFEBABE)
  {
   System.out.println("not a valid java class file :(");
   System.exit(1);
  }
  int minor_version=data.readUnsignedShort();
  int mazor_version=data.readUnsignedShort();
  System.out.print(file.getName()+" is ");
  if (mazor_version==45.3)
   System.out.println("Compiled with JDK 1.1 :)");
  else if (mazor_version==46.0)
   System.out.println("Compiled with JDK 1.2 :)");
  else if (mazor_version==47.0)
   System.out.println("Compiled with JDK 1.3 :)");
  else if (mazor_version==48.0)
   System.out.println("Compiled with JDK 1.4 :)");
  else if (mazor_version==49.0)
    System.out.println("Compiled with JDK 1.5 :)");
  else if (mazor_version==50.0)
   System.out.println("Compiled with JDK 1.6 :)");
  else
   System.out.println("I dont know the compilation version :( ");

  System.out.println("Version Details");
  System.out.println("Minor version :"+minor_version);
  System.out.println("Mazor version :"+mazor_version);


 }

}



Referenced Material:
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html