Tuesday, January 3, 2012

Jgroups LockService Example

import org.jgroups.*;
import org.jgroups.blocks.locking.LockService;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;

public class TheOne {

    private volatile AtomicBoolean becomeMaster = new AtomicBoolean (false);
    private JChannel channel;
    private LockService lock_service;
    private Thread acquiringThread;
    private Thread statusPrinter;

    public static void main(String[] args) throws Exception {
        Thread.currentThread().setName("MyMainThread");
        TheOne master = new TheOne();
        master.channel = new JChannel("/home/ssunel/udp.xml");
        master.channel.connect("lock-cluster");
        master.lock_service = new LockService(master.channel);
        master.startAcquiringThread();
        master.startStatusPrinterThread();
    }

    public void startAcquiringThread() {
        acquiringThread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.currentThread().setName("MyAcquiringThread");                   
                    getLock();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        acquiringThread.setDaemon(true);
        acquiringThread.start();
       
    }

    private void getLock() throws Exception{
        Lock lock = lock_service.getLock("mylock");
        lock.lock();
        becomeMaster.set(true);
        System.out.println(" -- I GOT THE LOCK !!!");
    }

    private void startStatusPrinterThread() {
        statusPrinter = new Thread(){
            @Override
            public void run() {
                Thread.currentThread().setName("MyStatusPrinterThread");                   
               
                while (true) {
                    try {
                        System.out.println("becomeMaster ? -> { " + becomeMaster + " }");
                        System.out.println("thread state ? -> { " + acquiringThread.getState() + " }");
                        sleep(2000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        statusPrinter.setDaemon(true);
        statusPrinter.start();
    }
}
Content of UDP.XML
open the jgroups.3.1-final.jar and edit the udp.xml inside it .
Add CENTRAL_LOCK tag 

Note : DistributedLockManager is Depracated in jgroups.3.1-final release .For older release example refer to http://javabender.blogspot.com/2010/10/solving-leader-election-problem-in.html


udp.xml content will be something like this :

<!--
  Default stack using IP multicasting. It is similar to the "udp"
  stack in stacks.xml, but doesn't use streaming state transfer and flushing
  author: Bela Ban
-->

<config xmlns="urn:org:jgroups"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.0.xsd">
    <UDP
        mcast_port="${jgroups.udp.mcast_port:45588}"
         tos="8"
         ucast_recv_buf_size="20M"
         ucast_send_buf_size="640K"
         mcast_recv_buf_size="25M"
         mcast_send_buf_size="640K"
         loopback="true"
         level="WARN"
         log_discard_msgs="false"
         discard_incompatible_packets="true"
         max_bundle_size="64K"
         max_bundle_timeout="30"
         ip_ttl="${jgroups.udp.ip_ttl:8}"
         enable_bundling="true"
         enable_diagnostics="true"
         thread_naming_pattern="cl"

         timer_type="new"
         timer.min_threads="4"
         timer.max_threads="10"
         timer.keep_alive_time="3000"
         timer.queue_max_size="500"

         thread_pool.enabled="true"
         thread_pool.min_threads="2"
         thread_pool.max_threads="8"
         thread_pool.keep_alive_time="5000"
         thread_pool.queue_enabled="true"
         thread_pool.queue_max_size="10000"
         thread_pool.rejection_policy="discard"

         oob_thread_pool.enabled="true"
         oob_thread_pool.min_threads="1"
         oob_thread_pool.max_threads="8"
         oob_thread_pool.keep_alive_time="5000"
         oob_thread_pool.queue_enabled="false"
         oob_thread_pool.queue_max_size="100"
         oob_thread_pool.rejection_policy="Run"/>

    <PING timeout="2000"
            num_initial_members="3"/>
    <MERGE2 max_interval="30000"
            min_interval="10000"/>
    <FD_SOCK/>
    <FD_ALL/>
    <VERIFY_SUSPECT timeout="1500"  />
    <BARRIER />
    <pbcast.NAKACK exponential_backoff="300"
                   xmit_stagger_timeout="200"
                   use_mcast_xmit="false"
                   discard_delivered_msgs="true"/>
    <UNICAST />
    <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
                   max_bytes="4M"/>
    <pbcast.GMS print_local_addr="true" join_timeout="3000"
                view_bundling="true"/>
    <UFC max_credits="2M"
         min_threshold="0.4"/>
    <MFC max_credits="2M"
         min_threshold="0.4"/>
    <FRAG2 frag_size="60K"  />
    <pbcast.STATE_TRANSFER />
    <CENTRAL_LOCK />
    <!-- pbcast.FLUSH  /-->
</config>

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