- Instance pooling
- Automated session state maintenance
- Passivation/activation
- Annotations to escape the XML hell(that was EJB2.x).
- Native integration with JSPs, Servlets, JTA transactions, JMS providers, JAAS, etc being part of J2EE stack.
Thursday, December 17, 2009
EJB 3 SessionBeans vs. Spring
Monday, September 7, 2009
Java logging "message duplication" phenomenon
Problem Definition: There are times in multi-threaded java programming when you see duplicate messages in your log files.
What was I doing wrong: I had setup the logging infrastructure in a super class that all logging classes would extend. Everytime I was instantiating a class that would log it would initialize the logging infrastructure for itself. And everytime it did so it would add another Appender(log4j)/Handler(JUL) to the Logger class.
What is the resolution: Do this in the log setup code(specific for log4j):
Logger logger = Logger.getLogger("
Enumeration appenders = logger.getAllAppenders();
if (!appenders.hasMoreElements()) {
//initialize an Appender class
//Add the appender object to the logger
}
When I was doing it wrongly, I did not have the if block. Hope you would benefit from this piece of wisdom :)
Monday, August 17, 2009
Spring-2 some learnings while reading a book
Personally, I feel that they've overloaded the bean creation with lots of convenience methods like these:
- Autowiring: Use "byName", "byType", "constructor" and "autodetect" to autowire a bean by name and type, resp. Something like this:
class="com.springinaction.springidol.Instrumentalist"
autowire="byName">
<property name="song" value="Jingle Bells" />
</bean>
- You can tell all the beans defined in the context file to autowire themselves with something like this:
- Autowiring, though it is convenient to use might lead to wrong wirings. So, I personally might resort to the old-fashioned manual wiring.
- Bean Scoping: By default beans are created as Singletons. Therefore, spring provides the following "scope" options when you create a bean: singleton, prototype, request & session(only valid in spring mvc) and global-session(only valid if used in portlet context).
- factory-method: If you already have a java implementation that returns a singleton, anyways. Then you can use it as a bean by declaring the method that spring might use to create an instance of the bean by using the factory-bean bean attribute.
- Now, this is pampering the users to no end. You, now have a way to tell spring to run init and cleanup methods when a bean is created. This, you can do using the init-method and destroy-method bean attributes where you can mention the methods of that bean that must be executed for the resp. stages. If you have used the same named init and cleanup methods across all your beans then you can specify it by using the default-init-method and default-destroy-method beans attributes.
- Parent-child concept in Spring! This is inheritance, the spring way. If you have a bean that will be created a multiple times in the context file, then you can use it like this:
class="com.springinaction.springidol.Instrumentalist"
abstract="true">
<property name="instrument" ref="saxophone" />
<property name="song" value="Jingle Bells" />
</bean>
<bean id="kenny" parent="baseSaxophonist" />
<bean id="david" parent="baseSaxophonist" />
- You can also abstract out the common properties into a parent-child relationship like this:
<property name="song" value="Somewhere Over the Rainbow" />
</bean>
<bean id="taylor" class="com.springinaction.springidol.Vocalist" parent="basePerformer" />
<bean id="stevie" class="com.springinaction.springidol.Instrumentalist" parent="basePerformer">
<property name="instrument" ref="guitar" />
</bean>
- Method injection: Another sorcery provided by Spring-2 is method injection whereby, you can, during runtime, replace one method with another method. This is done in two ways:
- Method replacement: Here you would implement an interface called org.springframework.beans.factory.support.MethodReplacer and implement the method public class TigerReplacer implements MethodReplacer {
public Object reimplement(Object target, Method method,
Object[] args) throws Throwable;} Then you do something like this in the context file: <bean id="magicBox" class="com.springinaction.springidol.MagicBoxImpl">
<replaced-method name="getContents" replacer="tigerReplacer" />
</bean>
<bean id="tigerReplacer" class="com.springinaction.springidol.TigerReplacer" /> - Getter injection: In this method you leave the getter method to be injected as abstract and then the lookup-method in the context file in the following way: <bean id="stevie"
class="com.springinaction.springidol.Instrumentalist">
<lookup-method name="getInstrument" bean="guitar" />
<property name="song" value="Greensleeves" />
</bean>
Wednesday, July 15, 2009
Java dependency walker tool
Here it is: I've made this tool which is only one java class. I am also bundling the ant build file so that you do not have to spend too much time figuring out how to run this thing.
How to run this tool:
1. Pick one folder as a base folder for this tool. Make a folder structure src->com->gp. Copy the source code of the JavaDependencyWalker.java in a file with the same name in the gp folder.
2. Now, copy the code of build.xml into a file of the same name in the base folder.
3. If you already do not have an ant install please download it from here http://ant.apache.org and install it.
4. Edit the build.xml file and modify the three proerties mentioned at the top with the following guidelines:
- scolon.separated.folders.ofjars = For the value of this property put a semi-colon separated absolute paths where the program can find all the jar files required for the class to run. For example, if the main class is a web service client that uses axis2 APIs then put the path to the lib folder of the axis2 install here. Also, do not forget to put paths to jar files of the custom classes you have built here. For example, you must put the path to the jar that contains the main class to run!
- main.class = This is the main class to run, for which you are finding the exact jars requirements.
- args.to.class = Here give all the arguments that will be required for the main class to run.
Below is the source code:
JavaDependencyWalker:
package com.gp;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JavaDependencyWalker {
private Hashtable m_jarsHash = new Hashtable();
public JavaDependencyWalker(String jarPaths) {
StringTokenizer stTok = new StringTokenizer(jarPaths, ";");
while (stTok.hasMoreTokens()) {
File f = new File(stTok.nextToken());
if (f.exists() && f.isDirectory()) {
addAllJars(f);
} else {
System.err.println(f.getName() +
" :: Cannot find this folder.");
}
}
}
private void addAllJars(File f) {
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
addAllJars(files[i]);
}
} else {
if (f.getName().toLowerCase().endsWith(".jar") ||
f.getName().toLowerCase().endsWith(".zip")) {
try {
JarFile jf = new JarFile(f);
Enumeration entries = jf.entries();
while (entries.hasMoreElements()) {
String entryName =
((JarEntry)entries.nextElement()).getName();
if (entryName.endsWith(".class")) {
entryName =
entryName.substring(0, entryName.indexOf("."));
StringTokenizer stTok =
new StringTokenizer(entryName, "/");
String str = "";
while (stTok.hasMoreTokens()) {
str += stTok.nextToken() + ".";
}
str = str.substring(0, str.length() - 1);
m_jarsHash.put(str, f.getCanonicalPath());
} else {
// skip it
}
}
jf.close();
} catch (IOException e) {
System.err.println(f.getName() + " :: " + e.getMessage());
}
} else {
// skip this file
}
}
}
public String getJarFilepath(String classname) {
return (String)m_jarsHash.get(classname);
}
public static void usage() {
System.out.println("java -Ddeps=<semi-colon seperated paths where all jars/zips may be found> -DclassToRun=<fully qualified classname to run> JavaDependencyWalker <all arguments to give to the class to run>");
}
public static void main(String[] args) {
String dependencies = System.getProperty("deps");
String classname = System.getProperty("classToRun");
if (dependencies == null || classname == null) {
usage();
System.exit(1);
}
JavaDependencyWalker javaDependencyWalker =
new JavaDependencyWalker(dependencies);
try {
String cp = "";
boolean noFound = true;
do {
Runtime rt = Runtime.getRuntime();
String cmdArr[] = null;
if (cp.equals("")) {
cmdArr = new String[args.length+2];
cmdArr[0] = "java";
cmdArr[1] = classname;
for (int i=0; i < args.length; i++) {
cmdArr[i+2] = args[i];
}
// cmd =
//"java " + args[1] + " ";
}
else {
cmdArr = new String[args.length+4];
cmdArr[0] = "java";
cmdArr[1] = "-classpath";
cmdArr[2] = cp;
cmdArr[3] = classname;
for (int i=0; i < args.length; i++) {
cmdArr[i+4] = args[i];
}
}
System.out.println("Command:" + cmdArr);
Process proc = rt.exec(cmdArr);
DataInputStream in =
new DataInputStream(proc.getErrorStream());
String line;
noFound = false;
while ((line = in.readLine()) != null) {
//System.out.println(line);
if (line.indexOf("ClassNotFoundException") != -1) {
String classNF =
line.substring(line.lastIndexOf(":") + 1).trim();
String cnfPackage = classNF.replace('/', '.');
if (javaDependencyWalker.getJarFilepath(cnfPackage) ==
null)
throw new Exception("No jar found for class " +
cnfPackage);
System.out.println("cnf: " + classNF + " found in " +
javaDependencyWalker.getJarFilepath(classNF));
noFound = true;
cp += javaDependencyWalker.getJarFilepath(cnfPackage) + ";";
} else if (line.indexOf("NoClassDef") != -1) {
String classNF =
line.substring(line.lastIndexOf(":") + 1).trim();
String ncdfPackage = classNF.replace('/', '.');
if (javaDependencyWalker.getJarFilepath(ncdfPackage) ==
null)
throw new Exception("No jar found for class " +
classNF);
System.out.println("NCDF: " + classNF + " found in " +
javaDependencyWalker.getJarFilepath(ncdfPackage) +
" " + ncdfPackage);
noFound = true;
cp += javaDependencyWalker.getJarFilepath(ncdfPackage) + ";";
}
}
} while (noFound);
StringTokenizer st = new StringTokenizer(cp, ";");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
}
}
}
ant build.xml:
<project name="JavaDependencyWalker" default="compile">
<property name="scolon.separated.folders.ofjars" value="c:/FUPv5/lib;c:/FUPv5/DeleteFile/classes;c:/FUPv5/WSClient/classes;c:/FUPv5/common/classes"/>
<property name="main.class" value="com.oracle.orion.fupv5.ws.client.SRWSClient"/>
<property name="args.to.class" value="-sr sdfds34 -user sldkfjd -password sdlfkjd -endpoint http://wd2088.us.oracle.com:7778/gateway/services/SID0003321 -type ddf -comm sdfd -stat Done"/>
<path id="classpath">
<pathelement location="classes"/>
</path>
<target name="compile">
<mkdir dir="classes"/>
<javac destdir="classes" classpathref="classpath" source="1.5" target="1.5" >
<src path="src"/>
</javac>
</target>
<target name="run" depends="compile">
<java classname="com.gp.JavaDependencyWalker" classpathref="classpath" fork="yes">
<jvmarg line="-Ddeps=${scolon.separated.folders.ofjars} -DclassToRun=${main.class}"/>
<arg line="${args.to.class}"/>
</java>
</target>
</project>
Monday, June 1, 2009
Obtaining a write lock on a file in java over multiple JVMs
I made a singleton class which handles the file that needs this sort of control, in our case it was the dirlist files. Why a singleton class? So that there is only one instance of the handler in the whole jvm and multiple threads in the same jvm can have synchronized access to this file. How does it obtain the write lock? By writing a .lck file in the same folder as this file. Below is the code we wrote for the handler:
package com.oracle.orion.fupv5.common;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* This class must be the only means to access with the dirlist files for reading or
* for writing.
*/
public class DirlistFileHandler {
private static DirlistFileHandler dfHandler;
private String dirlistFilepath;
private boolean locked = false;
private final String dirlistLockFile="FUPDirlistLock.lck";
private DirlistFileHandler(String filepath) {
dirlistFilepath = filepath;
}
/**
* This is the only method to get an instance of this class.
*
* @param filepath The absolute filepath to the dirlist file.
*/
public static DirlistFileHandler getInstance(String filepath) {
if (dfHandler == null) {
dfHandler = new DirlistFileHandler(filepath);
}
return dfHandler;
}
/**
* This method will return a BufferedReader instance to the dirlist file.
* One can then use this reader to access every line of the code by using
* the method readLine() of the BufferedReader class. Please close this
* reader instance after you are done with it.
*/
public BufferedReader getReader() throws FileNotFoundException {
BufferedReader in = new BufferedReader(new FileReader(dirlistFilepath));
return in;
}
/**
* This method will return a FileWriter instance to the dirlist file.
* One can then use this writer to write a new line at the end of file.
* Please close this writer instance after you are done with it. And
* call the releaseWriter() method of this class when you are closing
* the writer. When the caller successfully gets a writer to the dirlist
* file then the dirlist file is write locked until the releaseWriter() method is
* called.
*/
public FileWriter getWriter() throws FUPException, IOException {
if (isFileLocked()) {
throw new FUPException(ErrorConstants.DIRLIST_FILE_LOCKED);
}
synchronized(this) {
writeLockFile();
return new FileWriter(dirlistFilepath);
}
}
/**
* Use this method to release the write lock held over the dirlist file.
*/
public void releaseWriter() {
synchronized(this) {
removeLockFile();
}
}
/**
* It is adviced to use this method to ascertain that there is no write
* lock over the dirlist file before writing a new line to it, rather than
* trying to get the writer to it directly because you will need to handle
* an excpetion if it is locked. Instead use this method to check a lock
* and if a lock is present sleep for sometime and try to check it again.
*/
public boolean isFileLocked() {
File f = new File(dirlistLockFile);
if (f.exists()) {
return true;
}
else {
return false;
}
}
/**
* This method creates a new lock file in the same folder as the dirlist file.
*/
protected void writeLockFile() throws FileNotFoundException, IOException {
File df = new File(dirlistFilepath);
FileOutputStream fos = new FileOutputStream(df.getParentFile().getAbsolutePath()+"/"+dirlistLockFile);
fos.write((System.currentTimeMillis()+"").getBytes());
fos.flush();
fos.close();
}
/**
* This method removes the lock file.
*/
protected boolean removeLockFile() {
File f = new File(dirlistLockFile);
f.delete();
}
}
How to do an "around" logging Spring AOP Advice on all methods of a class?
package ro.vodafone.search.admin.common;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
public class LogInterceptor implements MethodInterceptor{
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
Logger logger = Logger.getLogger(methodInvocation.getMethod().getDeclaringClass());
try {
logger.info(methodInvocation.getMethod().getDeclaringClass()+ "."+ methodInvocation.getMethod().getName()+ " entered with parameters: " + methodInvocation.getArguments());
result = methodInvocation.proceed();
if (methodInvocation.getMethod().getReturnType() != null && result != null)
logger.info(methodInvocation.getMethod().getDeclaringClass() + "." + methodInvocation.getMethod().getName()+ " exitting with parameters: " + result);
else
logger.info(methodInvocation.getMethod().getDeclaringClass() + "." + methodInvocation.getMethod().getName()+" exitting");
} catch (Throwable ex) {
logger.error("Error while executing the method:"+methodInvocation.getMethod().getName(), ex);
throw ex;
}
return result;
}
}
Then in the spring app context file define the interceptors over the target in this way:
<bean id="logInterceptor" class="ro.vodafone.search.admin.common.LogInterceptor"/>
<bean id="searchAdminService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="service"/>
</property>
<property name="interceptorNames">
<list>
<value>logInterceptor</value>
</list>
</property>
</bean>
Sunday, April 19, 2009
Shell/Perl scripting versus Java programming
What are shell scripts most suited for?
Typical operations performed by shell scripts include file manipulation, program execution, and printing text. In their most basic form, shell scripts allow several commands that would be entered "by hand" at a command line interface to be executed automatically and rapidly. Most shells implement basic pattern matching capabilities like this, which allow them to perform commands on groups of items with similar names and sometimes parse simple strings of text.
What are java program most suited for?
Like any other full-fledged programming language java is widely embraced by Enterprise architects for the following reasons:
- Make programming easier by being simple, object-oriented and familiar.
- Leave less ambiguity by being a strongly-typed language.
- Ability to do any programmatic task like socket programming, file manipulation, streaming bytes, providing security, database operations, providing user interfaces among other things
- Ability to interact with other totally disparate systems with the use of Web Services by providing APIs.
- Ability to provide robust, fault tolerant, fail safe and scaleable systems with the help of industrial strength Application Servers and frameworks that promote distributed applications.
- The ability to code quickly and easily by providing multiple coding platform options like Jdeveloper, Eclipse, etc.
Why are most tasks in the FUP module of Orion being ported to Java?
Following are the reasons, IMO, why FUP is being ported to Java:
- Other systems in Orion need to call actions in FUP which require FUP to expose this functionality in a universally accepted way i.e. by exposing Web Services.
- FUP calls functionality in other modules of the Orion system. This requires FUP to be able to call the Web Services exposed by the other modules in a universally accepted way.
- To conform to the standards being adhered to by the other systems in Orion i.e. Java & JEE architecture.
- To become easy to extend and maintain. Java & JEE are already used by other teams other than FUP. Use of Java/JEE by FUP will enable other teams to understand and extend it better.
Why must script files not be migrated to java?
Most of the existing FUP commandline scripts, which include shell and perl scripts, are performing the following operations:
- Creating new folders.
- Moving/Copying files from one folder to another.
- Executing certain command-line commands.
- Outputting some debug statements while executing.
Following are the reasons why a few FUP scripts must not be migrated to java:
- These scripts are not being called by other modules of Orion. But they do call WS exposed by other modules. A java command line may be provided wherever an external WS is being called.
- File manipulations like moving & copying of files and creation & removal of folders is something which is a strength of shell scripts.
- Calling of command line executables too is a strength of shell scripts.
Therefore, as long as a piece of code is not being accessed by other modules in the Orion system one may keep using the same scripts. Places where other modules are being called in these scripts may be modified to use java functionality.
What are the scripts that do not qualify for porting to java?
- Daily/Weekly/Monthly reporting cronjob.
- ADR cronjob.