Saturday, July 27, 2013

Using CXF Interceptors to measure WebService or REST Service time


Let's say I have this simple service:

@WebService
public interface Hello {
     

      String sayHello();

      String sayGoodbye();

}


I want to know how often and how long sayHello() is executed compared to sayGoodbye(). I could add:

@WebService
public interface Hello { 
      
      @Profiled(tag = "sayHello")
      String sayHello();

      @Profiled(tag = "sayGoodbye")
      String sayGoodbye();

}

In this fashion, I would use Perf4Js @Profiled annotation and it would log messages telling me each time a sayHello() or sayGoodbye() method was called. However, that's not enough. I've just cut out the time of one of the most important parts of WebServices, XML processing.

Enter the CXF Interceptor, assuming of course that I was using CXF, I can write a custom interceptor by extending AbstractPhaseInterceptor<Message>, a fairly generic extension that would apply to JAXWS and JAXRS services. The new in interceptor would start a new Perf4j StopWatch (log4j or slf4j implementation if you please) and the new out interceptor would stop the StopWatch which would force the log record.  With the interceptor, I can also control the phase at which the interceptor is invoked.

Now my service would look like this:

@org.apache.cxf.interceptor.InInterceptors (interceptors = "net.halverson.interceptor.TimerInInterceptor" ) 
@org.apache.cxf.interceptor.OutInterceptors (interceptors = "net.halverson.interceptor.TimerOutInterceptor" ) 
@WebService 
public interface Hello { 
     
      String sayHello(); 

      String sayGoodbye(); 
}

But how do I know whether sayHello() or sayGoodbye() was called.  I suspect I could access the Message object in the interceptor and find out, but maybe I want more control than that.  That Message object is hanging around while my service is called and I can even place some of my own objects in it, however,  my service implementation does not have access to the Message object and I doubt I would ever want it to.

How then can I update the StopWatch with a 'tag' or 'message' for Perf4j to log?  A ThreadLocal will do.  Remember how we started the StopWatch in the in interceptor and stopped it in the out interceptor, we can use a ThreadLocal to place the StopWatch into that thread variable state and access the object across the thread without having to pass the object along the method calls in the stack.

Something like this:

public class ServiceTimer {

      private static final ThreadLocal<Slf4JStopWatch> stopWatch = new ThreadLocal<Slf4JStopWatch>() { 
              @Override
              public Slf4JStopWatch initialValue() {

                    return new Slf4JStopWatch();
              }

};

      // execute in the in interceptor, ServiceTimer.getStopWatch().start();
      // execute in the out interceptor, ServiceTimer.getStopWatch().stop();
      public static SLF4JStopWatch getStopWatch() {
            return stopWatch.get();
      }

      
      // for clean up in the out interceptor
      public static void removeWatch() {
            stopWatch.remove();
      }
}

Then in the service implementation of Hello interface:

@Service

public class HelloImpl implements Hello {

      public String sayHello() {
            ServiceTimer.getStopWatch().setTag("sayHello");

            return "Hello!";
      }

      public String sayGoodbye() {
            ServiceTimer.getStopWatch().setTag("sayGoodbye").setMessage("blah!");

            return "Goodbye!";
      }

}


In the end you'll get a two log records like this after the service is executed:

2013-07-27 10:45:45,328 INFO (http-8181-1) (TimingLogger) start[1374939945321] time[7] tag[sayGoodbye] message[blah!]
2013-07-27 10:46:03,565 INFO (http-8181-1) (TimingLogger) start[1374939963562] time[2] tag[sayHello]


See full code example here:
Github

Case # 123403984-1: JavaScript v. JSP

Opening: I've been a back-end developer (database, messaging, services, etc) all of my IT career and only done front-end (web page, scripts, graphics, etc) stuff on my own time. This week, I've exposed myself to more practical HTML, JavaScript and REST services with JSON delivery. I had previously been coding the viewing of the data in JSPs with an MVC format when needed. I've realized that the JSP / MVC model has it's uses, but the flexibility of JavaScript is what drew me in. I really liked how I could separate the presentation layer (what you see on the screen) from the data collection / back-end layer and make reusable services where you could effectively write new pages without disturbing the existing ones or the REST services behind them.

For JSP: I think the largest win here is when your page has a lot of manipulation to do and you want to run that on the server side instead of the client side. I'm sure your server cluster is more powerful and can deliver that page better than a client side rendering. The other argument I think is necessary here is hiding how the page was really built. When I write the JSP, it looks nothing like what is delivered to the consumer as all of the Java is replaced with HTML. I think that is a big positive for JSPs.

Against JSP: With JSPs, I've found that I've been a bit hard pressed to test my pages. To truly find out if my page is working, I have to start up my web app server and try to break it. When using MVC or just a servlet to deliver the page, I've found that I'm locking in the page to be delivered with the service that I just coded.
For JavaScript: In general, you can just do more with the manipulation of the page. This week, I've been able to prevent the default actions on buttons, make AJAX get and post calls, create new HTML and more. Further, with jQuery you can do a lot of JavaScript actions more simplistically. Since it's HTML and script code that is decoupled from the web app server, I can write the code in gedit/Notepad and test in the browser while my web app server is always up.

Against JavaScript: For me, the notation is a bit clunky to get started with. The use of functions compared to Java methods doesn't really match up where it's still called 'Java'. The other draw back is that you have to get used to how a browser processes a page to manipulate it. This is very different for a back-end developer.

Summation: JavaScript is another tool in my box now and I think I might have to use it more than I used JSPs. I do like how I can build those REST services and use them at will. I like how I can develop a new page to replace the old one without disturbing the existing one or writing a new service. Testing is a big win since I don't have to recycle the web app server when I make changes.