Tuesday, October 25, 2011

How to @Consume MediaType.APPLICATION_JSON with Jersey


Sit Back And get REST...


 Blahh Blahh Blahh and the Code !







    @GET
    @Path(value = "/json")
    @Produces(MediaType.APPLICATION_JSON)
    public JSON getJSON() {
        JSON json = new JSON();
        json.setName("json");
        json.setSurname("gson");
        json.setAge(32);
        json.setHasCar(true);
        json.setMarried(true);
        json.setSalary(123L);

        List childs = new ArrayList();
        childs.add("serkan");
        childs.add("volkan");
        childs.add("aybars");
        json.setChilds(childs);

        return json;
    }

    @PUT
    @Path(value = "/pson")
    @Consumes( { MediaType.APPLICATION_JSON })   
    @Produces( { MediaType.TEXT_PLAIN })   
    public String consumeJSONObject (JSON  pson) {
        System.out.println("Consumed json object is : " + pson);
        return pson.toString();
    }




import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class JSON {

    private String name;
    private String surname;
    private Integer age;
    private long salary;
    private boolean isMarried;
    private boolean hasCar;
    private List childs;
    
    public JSON() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public long getSalary() {
        return salary;
    }

    public void setSalary(long salary) {
        this.salary = salary;
    }

    public boolean isMarried() {
        return isMarried;
    }

    public void setMarried(boolean isMarried) {
        this.isMarried = isMarried;
    }

    public boolean isHasCar() {
        return hasCar;
    }

    public void setHasCar(boolean hasCar) {
        this.hasCar = hasCar;
    }

    public List getChilds() {
        return childs;
    }

    public void setChilds(List childs) {
        this.childs = childs;
    }

    @Override
    public String toString() {
        return "JSON [name=" + name + ", surname=" + surname + ", age=" + age
                + ", salary=" + salary + ", isMarried=" + isMarried
                + ", hasCar=" + hasCar + ", childs=" + childs + "]";
    }
    


Json data in soapui : {"name":"json","surname":"gson","married":true,"age":32,"salary":123,"hasCar":true,"childs":["serkan","volkan","aybars"]}

note : Using Jersey 1.8 ! (really important)

Sunday, April 3, 2011

Line number information for SLF4J and LOG4J log messages

Briefly;

Line number information should be put into the log messages by processing classes and enhancing the byte code.


#Ant task definition and usage can be like below. Feel free to customize according to your requirements


<taskdefname="enhanceLogs"classname="your.lovely.company.LoggerEnhancement"classpathref="lib.ant.path"/>

<enhanceLogs classesDir="${classesDir}"loggerJarsDirectory="${logging.jars.dir}"/>

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class LoggerEnhancement extends Task {
    public String classesDir;
    public String loggerJarsDirectory;

    public String getLoggerJarsDirectory() {
        returnthis.loggerJarsDirectory;
    }

    public voidsetLoggerJarsDirectory(final String loggerJarsDirectory) {
        this.loggerJarsDirectory= loggerJarsDirectory;
    }

    public String getClassesDir() {
        returnthis.classesDir;
    }

    public voidsetClassesDir(final String classesDir) {
        this.classesDir= classesDir;
    }

    @Override
    public voidexecute() throws BuildException {
        try{
            this.enhanceClasses();
        } catch(final Exception e) {
            e.printStackTrace();
            throw new BuildException(e);
        }
    }

    private voidenhanceClasses() throws FileNotFoundException, Exception {
        finalList classFiles = this.getClassFiles(this.classesDir);
        for(final File file : classFiles) {
            String qualifiedClassName = file.toString().substring(this.classesDir.length() + 1, file.toString().length() - 6);
            qualifiedClassName = qualifiedClassName.replaceAll("\\\\", ".");
            this.enhanceClassFile(qualifiedClassName);
        }
    }

    private voidenhanceClassFile(final String className) throws Exception {
        finalClassPool pool = ClassPool.getDefault();
        pool.appendClassPath(this.classesDir);
        pool.appendClassPath(this.loggerJarsDirectory+ "\\" + "slf4j-api-1.6.1.jar");
        pool.appendClassPath(this.loggerJarsDirectory+ "\\" + "org.apache.log4j_1.2.15.v201005080500.jar");
        finalCtClass compiledClass = pool.get(className);
        if(compiledClass == null) {
            System.err.println("Class " + className + " not found");
        } else{
            final LoggerEnhancementExpEditor exp = new LoggerEnhancementExpEditor();
            exp.setClaz(compiledClass);
            compiledClass.instrument(exp);
            compiledClass.writeFile(this.classesDir);
        }
    }

    private List getClassFiles(final String classesDir) throws FileNotFoundException {
        finalList result = new ArrayList();

        finalFile startingDirectory = new File(classesDir);
        finalList files = this.getFileListing(startingDirectory);
        System.out.println(" -- Processing classes under directory:" + classesDir);
        for(final File file : files) {
            if (file.isFile() && file.getName().endsWith(".class")) {
                result.add(file);
            }
        }
        returnresult;
    }

    private List getFileListing(final File aStartingDir) throws FileNotFoundException {
        this.validateDirectory(aStartingDir);
        finalList result = this.getFileListingNoSort(aStartingDir);
        Collections.sort(result);
        returnresult;
    }

    private List getFileListingNoSort(final File aStartingDir) throws FileNotFoundException {
        finalList result = new ArrayList();
        finalFile[] filesAndDirs = aStartingDir.listFiles();
        finalList filesDirs = Arrays.asList(filesAndDirs);
        for(final File file : filesDirs) {
            result.add(file);
            if (!file.isFile()) {
                final List deeperList = this.getFileListingNoSort(file);
                result.addAll(deeperList);
            }
        }
        returnresult;
    }

    private voidvalidateDirectory(final File aDirectory) throws FileNotFoundException {
        if(aDirectory == null) {
            throw new IllegalArgumentException("Directory should not be null.");
        }
        if(!aDirectory.exists()) {
            throw new FileNotFoundException("Directory not exist: " + aDirectory.getAbsolutePath());
        }
        if(!aDirectory.isDirectory()) {
            throw new IllegalArgumentException("Is not a directory: " + aDirectory);
        }
        if(!aDirectory.canRead()) {
            throw new IllegalArgumentException("Directory cannot be read: " + aDirectory);
        }
    }

    static classLoggerEnhancementExpEditor extends ExprEditor {
        privateCtClass claz;

        publicCtClass getClaz() {
            return this.claz;
        }

        publicvoid setClaz(final CtClass claz) {
            this.claz= claz;
        }

        @Override
        publicvoid edit(final MethodCall m) throws CannotCompileException {

            if (this.isLoggerMethodCall(m)) {
                try {
                    System.out.println("      -- Enhancing log line: "
                                       + this.getClaz().getName()
                                       + "."
                                       + m.where().getName()
                                       + "("
                                       + this.getClaz().getSimpleName()
                                       + ".java:"
                                       + m.getLineNumber()
                                       + ")");

                    m.replace("{ $1 = $1 +\", "
                              + this.getClaz().getName()
                              + "."
                              + m.where().getName()
                              + "("
                              + this.getClaz().getSimpleName()
                              + ".java:"
                              + m.getLineNumber()
                              + ") "
                              + "\"; $_ = $proceed($$); }");
                } catch (final Exception e) {
                    throw new CannotCompileException(e);
                }
            }
        }

        privateboolean isLoggerMethodCall(final MethodCall m) {
            return this.isSlf4jLoggerMethod(m) || this.isLog4jLoggerMethod(m);
        }

        privateboolean isSlf4jLoggerMethod(final MethodCall m) {
            return m.getClassName().equals("org.slf4j.Logger") && this.isALogMethod(m);
        }

        privateboolean isLog4jLoggerMethod(final MethodCall m) {
            return m.getClassName().equals("org.apache.log4j.Logger") && this.isALogMethod(m);
        }

        privateboolean isALogMethod(final MethodCall m) {
            boolean result = false;

            final String[] slf4LogLevels = { "trace", "debug", "info", "warn", "error", "fatal" };
            final String methodName = m.getMethodName();
            for (final String logLevel : slf4LogLevels) {
                if (methodName.equals(logLevel)) {
                    result = true;
                }
            }
            return result;
        }

    }

}

Saturday, March 5, 2011

LOG4J Usage

<appender name="errorAppender" class="org.apache.log4j.RollingFileAppender">
            <param name="File" value="logs/errors.log" />
            <param name="Append" value="true" />
            <param name="MaxFileSize" value="10000KB" />
            <param name="MaxBackupIndex" value="50" />
            <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p [%-16t]%m [%l : %t] %n" />
            </layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="LevelMin" value="ERROR" />
</filter>
</appender>
<appender name="ASYNC_errorAppender" class="org.apache.log4j.AsyncAppender">
            <param name="BufferSize" value="1000"/>
            <param name="Blocking" value="true"/>
            <param name="LocationInfo" value="false"/>
            <appender-ref ref="errorAppender"/>
</appender>

<logger name="com.mycompany.product.core" additivity="false"<
            <level value="DEBUG" /<
            <appender-ref ref="ASYNC_coreappender" /<
            <appender-ref ref="ASYNC_errorAppender" /<
            <appender-ref ref="ASYNC_ConsoleAppender" /<
</logger<


"LocationInfo" parameter is set to FALSE because of line number calculation's performance impact.You can set it to TRUE when you needed it. Log4j will take necessary actions on the fly. (Nevertheless i don't undertsand why this calculation needed to to be done on my thread! )

"Blocking" parameter is set to TRUE. Normally I prefer to set it true but this is my error log so i don't want to miss a error log if it happens.

"BufferSize" param is set to 1000 means :
     1) if you set blocking param to false : you can miss some logs when your buffer is full.
     2)if you set blocking param to true : your threads can be suspended while trying to log something while buffer is full. I don't prefer this kind of usage in production mode if my log entries not so critical like callDetailRecords/errors.

I will not write about why/when you need to use async logger. I want to finalize this blog entry ASAP before the blogger.com is blocked county wide  (Turkey : A Middle East Country)

Take Care..

Friday, November 12, 2010

IODH

Zero Syncronization issues ! Simple ! Clean !

public class Something {
private Something() {
}

private static class LazyHolder {
private static final Something INSTANCE = new Something();
}

public static final Something getInstance() {
return LazyHolder.INSTANCE;
}
}

OR

static Singleton instance;

public static synchronized Singleton getInstance() {
if (instance == null)
instance == new Singleton();
return instance;
}

Why it is called LAZY ? : IODH utilizes lazy class initialization. The JVM won't execute a class's static initializer until you actually touch something in the class. This applies to static nested classes, too...

Read more on : wikipedia , Double-checked_locking

Wednesday, November 3, 2010

Transaction isolation levels and 3 phenomena..


dirty read
A transaction reads data written by a concurrent uncommitted transaction.
nonrepeatable read
A transaction re-reads data it has previously read and finds that data has been modified by another transaction (that committed since the initial read).
phantom read
A transaction re-executes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another recently-committed transaction.
Isolation Level Dirty Read Nonrepeatable Read Phantom Read
Read uncommitted Possible Possible Possible
Read committed Not possible Possible Possible
Repeatable read Not possible Not possible Possible
Serializable Not possible Not possible Not possible

see also : http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html Similar things to Java's ReentrantReadWriteLock