Friday, July 06, 2007

Java shell tips

In which jar file does the class, CLASSNAME, reside?
for i in lib/*.jar; do jar tf $i | grep CLASSNAME >/dev/null && echo $i; done

To recursively search through all jars in the current directory...
find . -name "*.jar" | while read i; do jar tf $i | grep CLASSNAME >/dev/null && echo $i; done

And here's a handy little Python script that recursively "explodes" J2EE artifacts into their constituent components. If they're already exploded, it'll "implode" them. This is a great tool for quickly updating deployment descriptors at the command line.

#!/usr/bin/env python
#
# Each file passed on the command line that is a valid j2ee archive
# (war, jar, ear, sar) will be either exploded if archived or archived
# if exploded.

import sys,os
from zipfile import is_zipfile,ZipFile
from os.path import isdir,exists,realpath,dirname,basename,join
from shutil import rmtree

# The result of this try block is a function named 'mktempdir' that
# makes a temporary directory and returns its path. Python 2.3
# provides tempfile.mkdtemp, which does exactly what we need, but we
# must implement it ourself in older versions.
try:
from tempfile import mkdtemp as mktempdir
except ImportError:
from tempfile import mktemp
def mktempdir():
path = mktemp()
os.mkdir(path)
return path

# The result of this try block is a function called 'move', which
# moves a file or directory, possibly across filesystems. Python 2.3
# provides shutil.move, but older versions do not, so we revert to a
# system call. The os.rename function will not work across
# filesystems.
try:
from shutil import move
except ImportError:
def move(src,dest):
os.system("mv "+src+" "+dest)

# The presence of one of these indicates a J2EE artifact.
DEPLOYMENT_DESCRIPTORS = ("META-INF/application.xml", # ear
"WEB-INF/web.xml", # war
"META-INF/ejb-jar.xml", # jar
"META-INF/jboss-service.xml") # sar

def explode(file):
'''Recursively unpack the contents of a J2EE file into a directory of same name.'''
file = realpath(file)
tmp = mktempdir()
os.system("cd "+tmp+"; jar xMf "+file)
[explode(join(tmp,f)) for f in os.listdir(tmp) if is_j2ee_zip(join(tmp,f))]
os.remove(file)
move(tmp,file)
print "Exploded "+file

def implode(dir):
'''Recursively package the contents of a directory into a J2EE file with same name.'''
dir = realpath(dir)
[implode(join(dir,f)) for f in os.listdir(dir) if is_j2ee_dir(join(dir,f))]
tmp = mktempdir()+"/"+basename(dir)
os.system("cd "+dir+"; jar cMf "+tmp+" *")
rmtree(dir)
move(tmp,dir)
os.rmdir(dirname(tmp))
print "Imploded "+dir

def is_j2ee_dir(path):
'''Return True if directory contents are structured as a valid J2EE artifact.'''
if isdir(path):
for dd in DEPLOYMENT_DESCRIPTORS:
if exists(join(path,dd)): return True

def is_j2ee_zip(path):
'''Return True if path refers to a valid J2EE artifact.'''
if is_zipfile(path):
files = ZipFile(path).namelist()
for dd in DEPLOYMENT_DESCRIPTORS:
if dd in files: return True

for path in sys.argv[1:]:
if is_j2ee_zip(path):
explode(path)
elif is_j2ee_dir(path):
implode(path)