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.

Friday, December 28, 2012

WD MyBook Essential in Linux

After some searches on Google, I found the best solution to mount the WD MyBook Essential to my Ubuntu 12.04. First, I'm using the drive over my Network. The drive is connected to my router via USB and accessible to all connecting computers. I'm not using a password to login to the drive.

Procedure:
1) Open a terminal
2) sudo mkdir /media/directory-you-want-to-mount-to
3) sudo gedit /etc/fstab
4) When the gedit window opens, add the following:
//router-ip-address/USB_Storage/directory-you-want-to-mount-from /media/directory-you-want-to-mount-to cifs guest,_netdev 0 0
5) Save
6) sudo mount -a
7) If successful, you should see the drive mounted on you desktop. If not successful, I'm guessing that you'll get a message from 'mount' command. I'd recommend that 'mount -a' works before restarting, you might have issues with logging in if you don't.

Notes:
- I read that '_netdev' is used to wait until the network connection is available to finalize the command.
- If you need a secured login, see http://opensuse.swerdna.org/susesambacifs.html#permsec
- I've recently had to include 'sec=ntlm' before 'guest' above in order to make the connection.  Without it, I was getting an input/output error.

Saturday, December 1, 2012

WAS 8.5

WAS 8.5 for Developers is 2.4 GIGABYTES installed on Ubuntu Linux. That's crazy! Tomcat is, what?, 50 MB.

Sunday, July 8, 2012

WebSphere and Logging

I've recently had some experience configuring WebSphere to use logging other than Jakarta Commons Logging (JCL) that is natively included in WAS.  I found a lot of blogs, forum posts, and tech write ups from IBM on the subject.  None were very satisfactory to me.  Therefore, I set out to find out how it worked.  I created an EAR with three different WARs in it.  Each WAR contained different types of logging that you might use in your application.

Environment
WAS 7.0.0.0 (it's actually WAS for Developers although that shouldn't matter)
Windows 7 64bit
Eclipse Java EE Indigo
Maven 2
Spring 3.0.0

Project Setup
was-logger
-> was-logger-ear
-> was-logger-jcl-war
-> was-logger-log4j-war
-> was-logger-slf4j-war (with log4j as the implementing logger)

I used the Maven project/module model to help build my resulting EAR file and dependency management.

was-logger-jcl-war
This WAR contains only the applicationContext.xml, web.xml, and Spring JARs.
I created a class called LogEvent.  The class is loaded by Spring as a bean and performs a simple loop to display 10 messages.  The point of the loop was to easily find those messages amongst others.


package org.foo.bar.jcl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LogEvent {

private static final Log log = LogFactory.getLog(LogEvent.class);

public void initialize() {

for (int i = 0; i < 10; i++) {
log.info("Testing commons logging #" + i);
}
}

}


The resulting log records will appear in the SystemOut.log file.  Like this:

[7/8/12 8:12:14:701 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #0
[7/8/12 8:12:14:701 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #1
[7/8/12 8:12:14:716 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #2
[7/8/12 8:12:14:716 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #3
[7/8/12 8:12:14:716 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #4
[7/8/12 8:12:14:716 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #5
[7/8/12 8:12:14:732 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #6
[7/8/12 8:12:14:732 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #7
[7/8/12 8:12:14:732 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #8
[7/8/12 8:12:14:732 CDT] 0000000a LogEvent      I org.foo.bar.jcl.LogEvent initialize Testing commons logging #9


If you have one application in the environment this might be ok. If you want to customize or use different and better loggers, then you'll want to read further.

was-logger-log4j-war
This WAR contains the log4j.xml, commons-logging.properties, applicationContext.xml, web.xml, log4j JAR, and Spring JARs.  I basically created this WAR with the same class, LogEvent, but backed it up with log4j Logger instead of the commons-logging Log class.


commons-logging.properties file contains some information to route commons logging over to log4j.  In other words, Spring uses JCL and the point of the properties file in my WAR is get Spring to use log4j instead.  However, it didn't work from a Spring perspective.  The messages from LogEvent were routed to the file specified in my appender.


2012-07-07 22:04:13,712 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #0
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #1
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #2
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #3
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #4
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #5
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #6
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #7
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #8
2012-07-07 22:04:13,715 [WebContainer : 3] INFO  (LogEvent)  - Testing log4j logging #9


So why didn't it work?  I'm not sure. I think one thing that happens is that Spring attaches to the JCL logger before it gets a chance to hook up with log4j.  There is a part of the ContextLoaderListener to load log4j.  There is also a defined listener to load you log4j configuration.  I haven't played with that, but I fear that it is only really going to apply to Spring.  What about other frameworks (like CXF) that use JCL as well?  Read on.

was-logger-slf4j-war
This WAR contains the log4j.xml, commons-logging.properties, applicationContext.xml, web.xml, log4j JAR, slf4j JARs and Spring JARs.  There is also another JAR that seems to be key, jcl-over-slf4j-1.6.6.jar.


When the slf4j logging facade is used on top of log4j, Spring and my application information are routed to the file defined in my log4j.xml file.

2012-07-07 22:04:14,143 [WebContainer : 3] INFO  (ContextLoader)  - Root WebApplicationContext: initialization started
2012-07-07 22:04:14,291 [WebContainer : 3] INFO  (XmlWebApplicationContext)  - Refreshing Root WebApplicationContext: startup date [Sat Jul 07 22:04:14 CDT 2012]; root of context hierarchy
2012-07-07 22:04:14,486 [WebContainer : 3] INFO  (XmlBeanDefinitionReader)  - Loading XML bean definitions from class path resource [applicationContext.xml]
2012-07-07 22:04:14,778 [WebContainer : 3] INFO  (DefaultListableBeanFactory)  - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@56c556c5: defining beans [logEvent]; root of factory hierarchy
2012-07-07 22:04:14,863 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #0
2012-07-07 22:04:14,863 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #1
2012-07-07 22:04:14,863 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #2
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #3
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #4
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #5
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #6
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #7
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #8
2012-07-07 22:04:14,864 [WebContainer : 3] INFO  (LogEvent)  - Testing slf4j logging #9
2012-07-07 22:04:14,886 [WebContainer : 3] INFO  (ContextLoader)  - Root WebApplicationContext: initialization completed in 740 ms


Conclusions
I like my logging configurable outside of the WAS Admin Console.  In most production environments, you're not going to have any kind of permissions to change items in the Admin Console.  Then you would have to engage someone in a support area who does have access and they might not be as up to date on your application and what your request is.  Log4j and slf4j give you greater flexibility in defining your logging solution.  I like the slf4js ability to route any framework over to the log4j configuration.

Appendix - Class Loading
This discussion wouldn't be complete with some mention of class loading.  A lot of posts I saw mentioned that setting the class loader to PARENT_LAST,  I have done that for another application for the purposes of CXF, but for this test application, I did not.  Therefore, you can get different logging without changing the classloading order.

I've posted the code at the following link. was-logger

Wednesday, July 4, 2012

DSL

I've been an AT&T DSL customer since 2001. At that time it was with SBC in the Kansas City area. I have a @swbell.net email address to this day. When it was initially rolled out it was $49.95 1 year contact for 1.5 Mbps down. Over time that price went down. I think it took 3 years to get a price break.

Now, it's $43 for existing customers on 6 Mbps no contract. They've raised the price the past couple of year's a dollar here and two dollars there. The reason they give is the same. Something to do with keeping up with market conditions.

To be fair they do include WI-FI at Starbucks, McDonald's, etc for when you use a laptop. For me though that doesn't happen often enough to pay for it included in the $43. Further, you can't separate the two  features.  I suppose that's because most people would separate the two and no one would pay for it.  Then they'd have to drop the feature.

I'm leaving you, AT&T, for Comcast.  I can't ignore the short term deals and the chance to compete for my business with deal negotiation.  I found a two-year contract @ $39.99 for the first 12 months and $56.99 for the second 12 months for phone and internet.  In the end, with taxes, I'll still end up paying less for faster internet (max 20 Mbps!) and the same phone features.  Install is on 7/10.  My wife has put me in charge of this task to switch over.  Which means that not only do I have to monitor the install and make sure everything works just as it does currently, I'll also be the complaint department when it doesn't work right.

Monday, July 2, 2012

iPhone and Gmail

I use my iPhone to manage personal appointments much as one would use their corporate mail server to manage meetings.

My wife and I have Gmail accounts. Our phones are both set to use gmail as an Outlook Exchange server. What that extra distinction allows for is the ability to send and receive calendar entries and accept or deny them as you would within an outlook client on your computer.

When my wife has an appointment she invites me to it and it appears in my calendar after I accept it, for example.

The limitations are that 1) your mail server (e.g. Hotmail, Yahoo, etc) has to support Microsoft Exchange and 2) the scheduler has to know that ahead of time. It's works really well with my wife and I though.