Lazy Programmer's Shortcut

Java, J2EE, Spring, OOAD, DDD & LIFE! …….all in one :)

Resolving Spring Circular Reference Problem with proxied class

Have you ever run into a problem like this ?

"Error creating bean with name 'beanA': Bean with name 'beanA' has been injected into other beans (beanB) in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."

Let me first explain why this happens:

You have a circular dependency between your BeanA & BeanB. In such cases, if one of your bean does not have any AOP applied to it (transaction / audit-trail etc) , spring behaves fine. However, if both of your beans are proxied or in other word, has AOP advice attached to it (mostly transaction advice) , you have a problem. This is because spring initially injects the raw version of your bean beanA in the other bean beanB but later adds Aspect into it. So If your beanA has any aspect (transaction / audit-trail ) , they will not be in action when beanB uses beanA. Spring does not allow this by default and gives you the exception.

In a perfect world and in a perfect project, you wouldn’t want circular dependency in your beans. But as we know, the world is not perfect and sometimes you just have to do it (obviously within same module).

How do I do it you ask? Fortunately you have a few options :

1. Set “allowEagerInit” to false in your application context.
2. Break the circular dependency for spring by not injecting one of the bean with application context and get the bean @ runtime by calling “applicationContext.getBean”
3. Write your own BeanFactory to allow circular dependency ( If you are ok with the side effects )

I am going to describe the 3rd method in details. With spring, its always very simple to add hook in necessary points. First write a class like this:

public class AllowRawInjectionDespiteWrappingXMLWebApplicationContext extends
		XmlWebApplicationContext {

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws IOException {
		beanFactory.setAllowRawInjectionDespiteWrapping(true);
		super.loadBeanDefinitions(beanFactory);
	}

}

All I am doing here is changing the default value “allowRawInjectionDespiteWrapping” to true to let spring know I am OK with raw injection of my AOP beans.

Next, Change your default contextClass “XmlWebApplicationContext” class name which spring uses by adding the following in your web.xml file.

	<context-param>
	        <param-name>contextClass</param-name>
	        <param-value>com.myapp.AllowRawInjectionDespiteWrappingXMLWebApplicationContext</param-value>
	</context-param>

All that trouble to break a design rule (avoid circular dependency)..Fair enough !!

February 9, 2010 Posted by sajid2045 | Uncategorized | | No Comments Yet

Exporting Spring Beans as JMX Mbeans

If you always want to stay on top of your production system and always want to know whats going on in your APP, you would want to configure JMX for your application.

First you need to start your JVM with the following parameters to enable any JMX client to connect to your system.

-Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

This is just done without any security but in production, you would want to add authentication.

Now, add these configuration for your spring APP to automatically expose your Spring Beans as MBeans if they have the right annotations.

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"
		lazy-init="false">
		<property name="autodetect" value="true"></property>
		<property name="namingStrategy" ref="namingStrategy"></property>
		<property name="assembler" ref="assembler"></property>
		<property name="server" ref="mbeanServer"></property>
	</bean>

	<bean id="assembler"
		class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
		<property name="attributeSource" ref="attributeSource" />
	</bean>

	<bean id="namingStrategy"
		class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
		<property name="attributeSource" ref="attributeSource" />
	</bean>

	<bean id="mbeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer"/>

The ‘exporter’ will inspect all your defined Spring Beans in your configuration and see if the have Spring JMX annotations. Now you need to define your beans with Annotations.

@ManagedResource(objectName = "yourapp:name=log4jLevelChanger", description = "LOG4j Level Changer")
public class Log4jLevelChanger  {
	private static final Log log = LogFactory.getLog(Log4jLevelChanger.class);

	public void init() throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {
		ArrayList<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
		for(MBeanServer server : servers) {
			String name = (String) server.getAttribute(MBeanServerDelegate.DELEGATE_NAME,
            "MBeanServerId");	

			log.info("found  server: " + name);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.vantage.callcenter.web.utils.Log4jLevelChanger#setLogLevel(java.lang
	 * .String, java.lang.String)
	 */
	@ManagedOperation
	@ManagedOperationParameters({
	@ManagedOperationParameter(description="Name of the Logger to configure", name="loggerName"),
	@ManagedOperationParameter(description="Level ofthe Logger to set", name="level")
	})
	public void setLogLevel(

			String loggerName, 

			String level) {
		if ("debug".equalsIgnoreCase(level)) {
			Logger.getLogger(loggerName).setLevel(Level.DEBUG);
		} else if ("info".equalsIgnoreCase(level)) {
			Logger.getLogger(loggerName).setLevel(Level.INFO);
		} else if ("error".equalsIgnoreCase(level)) {
			Logger.getLogger(loggerName).setLevel(Level.ERROR);
		} else if ("fatal".equalsIgnoreCase(level)) {
			Logger.getLogger(loggerName).setLevel(Level.FATAL);
		} else if ("warn".equalsIgnoreCase(level)) {
			Logger.getLogger(loggerName).setLevel(Level.WARN);
		}
	}

        //Read the log4j.properties to reconfigure the logging levels.
	@ManagedOperation
	public boolean refreshLogging() {
		try {
			Log4jConfigurer.initLogging("classpath:log4j.properties");
			return true;
		} catch (FileNotFoundException e) {
			return false;
		}
	}

	@ManagedOperation
	@ManagedOperationParameters ({
		@ManagedOperationParameter(description="Name of the Logger to get the Level", name="loggerName")
	})
	public String getLogLevel(

			String loggerName) {
		log.debug("getLogLevel -> loggerName: " + loggerName);
		Logger logger = Logger.getLogger(loggerName);

		if(logger != null) {
			if(logger.getLevel() != null) {
				return logger.getLevel().toString();
			}
		}

		return Logger.getRootLogger().getLevel().toString();
	}
}

and define it in your application-context.xml as a regular bean

<bean id="log4jLevelChanger"  class="com.test.Log4jLevelChanger"></bean>

Thats it! Now you can open any Standard JMX client (JConsole / VisualVM / JManage) to inspect the bean and changing log levels!

You can also add Mbean Annotations to any regular Bean that you wish to inspect at runtime. For example, you can add it to the bean that manages your threadpool to see its utilization at runtime, you can add it to any in memory cache to find out memory leaks. If you think closely, the possibilities can be endless!

February 2, 2010 Posted by sajid2045 | JVM, java, spring, tomcat | | No Comments Yet

Pragmatic Thinking & Learning

I just started reading the book “Pragmatic Thinking & Learning” published from the Pragmatic Programmers. Although I only read only the first few chapters so far, I am so excited about it that I thought I should write a line or two about it. If you are in Software development and want to learn the dynamics of software development and software development teams, you must read this book. This is by far the most impressive non technical book I have read so far.

Here is a snippet to give you some test:


Dreyfus at Work: Herding Racehorses and Racing Sheep :

In one of the Dreyfus studies, the researchers did exactly that. They took seasoned airline pilots and had them draw up a set of rules for the novices, representing their best practices. They did, and the novices were able to improve their performance based on those rules. But then they made the experts follow their own rules. It degraded their measured performance significantly.

– How true! Can you have the same set of rules for your top developer who is at “Expert/Proficient” level and the average developer who is @ “Novice/Beginner” level ? How can you explain intuition to the developer who needs a recipe? (If you don’t know what I am talking about, go read the book). This is one of the top challenges I have faced adopting SCRUM coming from a strict hierarchical team management. In SCRUM everyone from Novice to Expert seems to have the same “voice” and sometimes it just holds you back. But hey, the efficiency of a SCRUM team is often measured by the efficiency of the weakest node of the team! So thats fair enough :)

December 31, 2009 Posted by sajid2045 | productivity, programming, scrum | | No Comments Yet

Where was I ???

Ok, its been long since I had my last blog post. Where was I? Well, I have been busy! Last few months have been the most happening months of my life.

First of all, I am a proud father of my 1 month old son now. Although I haven’t managed to stop watching cartoons and start acting like a dad yet, its really amazing how you feel!

Again, the product “Vantage Contact Center” that I have been working for last 1.5 years is in market now!

The product is built on top of Broadwork’s 3rd party call control api (OCI-P / CCC2) and Broadworks SIP stack.This is the biggest project that I know of built on top of broadworks 3rd party api. We had a product owner who had spent last 10 year with callcenter solutions. So you can say it was a smooth sail. Once again It proves that for any successful software, most important thing is ‘Domain Knowledge’. We emphasized heavily on Domain Driven Design, unit testing , functional automation testing and we didn’t forget that none of these can replace the manual testing. At the end, it all paid off. Except for some minor integration issues at deployment time (which is natural because the solution depends on a number of servers talking to each other, a typical pattern for telephony apps) , we didn’t have a single major bug that is a showstopper! We had to change some labels on customer demand and add some more validation, but thats about it!

So here I am , feeling all good about the year 2009 and praying it would go the same for year 2010! And hoping I will update my blog regularly! Wish me luck!

December 22, 2009 Posted by sajid2045 | broadsoft, productivity, sip, sip stack | | 2 Comments

What I liked most about Erlang as a functional language

Erlang comes with all the built-in concurrency and distributed programming support which will blow you away if you are familiar with distributed systems. However, I will save that talk for some other day. If you see erlang as a pure functional language, it is really powerful! And among all functional languages I’v played with (javascript, php, ruby), one thing I looooooved about erlang is that it is a compiled language! Coming from java background, I become really pissed when program fails for silly syntax error!

I have this feeling that the future languages will become more and more like erlang. With all the multi-core processors, thats the way to go! Only thing I don’t like about it is that the syntax is more like mathematics and less like a language. Again, coming from java background, I might have become too comfortable with more descriptive language. Time to get out of the comfort zone!

June 23, 2009 Posted by sajid2045 | Uncategorized | | No Comments Yet

How to setup Emacs as Erlang IDE on Windows XP

There are a dozens of links in the web for setting up erlang as an emacs IDE with syntax highlighting, indentation, compilation , debugging support. However, none of them is as straight forward as this one HERE. However, this was written for linux boxes. You can replace the linux relative paths with your windows relative paths. Just keep the following points in mind.

  • Erlang default installation path “C:\Program Files\erl5.6.3″ is not supported by Distel (because of the whitespace in ‘Program Files’). You can either install erlang in a different location (C:\erl5.6.3), or use shortcut path location : “C:/progra~1/erl5.6.3″
  • You don’t have to checkout the distel code with svn if you don’t have svn client. You can download it directly from HERE.

Just in case, I am pasting my .emacs file here

;; This is needed for Erlang mode setup
(setq erlang-root-dir "c:/progra~1/")
(setq load-path (cons "C:/progra~1/erl5.6.3/lib/tools-2.6.1/emacs" load-path))
(setq exec-path (cons "c:/progra~1/erl5.6.3/bin" exec-path))
(require 'erlang-start)

;; This is needed for Distel setup
(let ((distel-dir "C:/dev/erlang/distel/elisp"))
  (unless (member distel-dir load-path)
    ;; Add distel-dir to the end of load-path
    (setq load-path (append load-path (list distel-dir)))))

(require 'distel)
(distel-setup)

;; Some Erlang customizations
(add-hook 'erlang-mode-hook
	  (lambda ()
	    ;; when starting an Erlang shell in Emacs, default in the node name
	    (setq inferior-erlang-machine-options '("-sname" "emacs"))
	    ;; add Erlang functions to an imenu menu
	    (imenu-add-to-menubar "imenu")))

;; A number of the erlang-extended-mode key bindings are useful in the shell too
(defconst distel-shell-keys
  '(("\C-\M-i"   erl-complete)
    ("\M-?"      erl-complete)
    ("\M-."      erl-find-source-under-point)
    ("\M-,"      erl-find-source-unwind)
    ("\M-*"      erl-find-source-unwind)
    )
  "Additional keys to bind when in Erlang shell.")

(add-hook 'erlang-shell-mode-hook
	  (lambda ()
	    ;; add some Distel bindings to the Erlang shell
	    (dolist (spec distel-shell-keys)
	      (define-key erlang-shell-mode-map (car spec) (cadr spec)))))

June 23, 2009 Posted by sajid2045 | erlang | | No Comments Yet

Sun’s Garbage First Collector : do I have to buy it!

Those of you who are involved in real time application development surely have suffered from the unexpected GC pause time. I have spent quite a bit of time trying to tune my Heap generation spaces, playing with new generation / old generation size , GC algorithms etc. I had my eye on the Sun’s Garbage First Collector. Basically it is the replacement of the old CMS (Concurrent mark sweep) collectors and can be extremely useful for large heap low latency applications. I just read this article which suggests sun is going to make this commercial !!! I wonder whether the Oracle acquisition is revealing its true nature! One of the main reason why Java is still my favorite platform (I am falling in love slowly with dynamic languages like Ruby, Erlang, PHP..man! you can do magic with them !l!) is because of its solid and open VM. If sun moves away from its open policies, I wonder if Java will become the legacy language in near future????!!!.

June 7, 2009 Posted by sajid2045 | Uncategorized | | No Comments Yet

Lessons learned in Software Development (2) – Abstraction

Long ago during our weekly tech meeting @ Therap, we had this intriguing discussion, “What is the most crucial skill for a software developer?”. It was quite interesting to see how different people at different skill level had different opinion about the topic. I remember my answer was “Algorithm” (Back then I was into solving ACM style problem). Other inputs were “Language”, “Communication”, “Optimization”, “Clean Code” etc. However, we all agreed finally that it was “Design skills” that matters most.

My view on this topic also changed from time to time as I grew older and played different roles. I tried to master java (with two java certification under my belt) when I thought language was the most important, I memorized all design patterns from GOF books and tried to apply them when I thought design was the most important one.

Well now a days, I feel like I got the bigger picture. I think it is the power of “Abstraction” that can turn you from a good Software engineer to a Great one. You can find the importance of abstraction everywhere. When we were tought object oriented design at our schools, we first relate the word “Abstraction” as one of the three attributes of Object Oriented Programming. Well, it has much bigger meaning than that. Abstraction is not only part of  detailed design or Object design, Its the most important part when you want to architect big systems.

When I started my career, I used to get overwhelmed by big problems, big tasks, big projects. I tried to address them all together and made a mess of things. Now a days, I try to apply abstraction in such scenarios. Whenever I get big problems, I try to divide them into smaller pieces. “Divide and conquer”–Thats the trick. If you can abstract away the smaller problems and focus on the big picture, at the end of the day, you are going to achieve the big goal. If you are working in a team, you can put your team members to work with each of the abstractions.

I am not going to talk about the Abstraction @ code level. There are enough materials on them. But here is the key, If you can abstract away the components/responsibility/code, you will always be safe from big disaster and achieve the bigger goal.

May 28, 2009 Posted by sajid2045 | OOAD, design, productivity, programming | | 1 Comment

Automate SIP Flow testing with Sipper

If you are into VOIP development and want to automate your sip call flows for testing, you might be interested in this project SIPr.

I have been involved in a project for a few months now which provides an advanced callcenter service leveraging the Broadworks Platform. Like any callcenter, the customer calls the CallCenter , Callcenter Queues the Call and Selects an agent and delivers the Call to the Agent. The agent is a registered user of Broadworks.

I have been looking for the right tool to automate the SIP Call Flows. After playing a while with sippr, I end up writing these test cases:

The CUSTOMER controller:
It justs sends the INVITE to a broadworks number which is the QUEUE. After the call gets received, it waits and sends BYE to terminate the call.

require 'sip_test_driver_controller'

class CustomerController < SIP::SipTestDriverController

  transaction_usage :use_transactions=>false
  start_on_load false

  def initialize
    logd('Controller created')
  end

  def on_provisional_res(session)
  end

  def start
    session = create_udp_session(SipperConfigurator[:DefaultRIP], SipperConfigurator[:DefaultRP])
    session.request_with('INVITE', 'sip:sajidqueue1@bwas.broadworkslab.com')
    puts 'Sending INVITE Dest: ',  'sip:sajidqueue1@bwas.broadworkslab.com';
 end

 def on_invite(session)
 puts 'customer got re-invite : '
 session.respond_with(200)
 session.schedule_timer_for("send 200!", 15000)
 end

 def on_timer(session , task)
 puts 'sending bye'
 session.request_with('BYE')
 session.invalidate(true)
 end

 def on_success_res(session)
 puts 'customer ---> on_success_res'
 session.request_with('ACK')
 end
end

Here is the Agent Controller:
It registers with Broadworks and waits for calls from the queue and receives it after 10 sec Ring and then waits for the BYE from the customer.

require 'sip_test_driver_controller'

class AgentController < SIP::SipTestDriverController

  transaction_usage :use_transactions=>false

  # change the directive below to true to start after loading.
  start_on_load false

  def specified_transport
    [SipperConfigurator[:LocalSipperIP],SipperConfigurator[:LocalSipperPort][1]]
  end   

  def initialize
    logd('Controller created')
  end

  def on_invite(session)

    if !session['invite']
      puts 'Agent got call from Queue '
      session.respond_with(100)
      session.respond_with(180)
      session['invite']=1
      session.schedule_timer_for("send 200!", 5000)
    else
      puts 'agent got re-invite'
      session.respond_with(200)
    end

  end

  def on_timer(session , task)
    puts 'Agent is going to accept the call from customer!', task
    session.respond_with(200)
  end

  def on_bye(session)
    puts 'Agent received BYE from Customer!'
    session.respond_with(200)
    session.invalidate(true)
    session.flow_completed_for("CustomerAgentTest")
  end

  def on_provisional_res(session)
  end

  def start
    contact = SipperConfigurator[:LocalSipperIP]+":"
    r = Request.create_initial("REGISTER", "sip:" + "bwas.broadworkslab.com'",
         :from=>"sip:2401120075@bwas.dhaka.vantage.com", :to=>"sip:2401120075@bwas.broadworkslab.com'",
         :contact=>"sip:sajidagent1@"+ SipperConfigurator[:LocalSipperIP]+":"+SipperConfigurator[:LocalSipperPort][1].to_s(),
         :expires=>"300",
         :cseq=>"1 REGISTER",
         :p_session_record=>"msg-info")
    r.contact.q="0.9"
    session = create_udp_session(SipperConfigurator[:DefaultRIP], SipperConfigurator[:DefaultRP])
    #session.create_register_request('sip:bwas.dhaka.vantage.com', '<sip:sajidagent1@bwas.broadworkslab.com'>')
    session.send(r)
    #print "Sent a new REGISTER from "+name+"\n"
  end

  def on_success_res_for_register(s)
    s.invalidate(true);
  end

  def on_success_res(session)
    puts 'on_success_res->'
  end

  def on_ack(session)
  end

  def on_failure_res(session)
    if session.iresponse.code == 401
     r = session.create_request_with_response_to_challenge(session.iresponse.www_authenticate, false,"a", "b")
     session.send r
     session[:auth] = r.authorization
    end
  end
end

And Here is the Test Case that runs both controller and performs Validation/Assertion for the call flow.

$:.unshift File.join(ENV['SIPPER_HOME'],'sipper_test')
require 'driven_sip_test_case'

class CustomerAgentTest < DrivenSipTestCase
  def setup
    super
    SipperConfigurator[:SessionRecord]='msg-info'
    puts '------------------------------------'
  end

  def test_case1
    start_named_controller_non_blocking("AgentController")
    sleep 1
    start_named_controller_non_blocking("CustomerController")    

    #it waits for Agent & Customer flow complete. The agent controller triggers the completion with session.flow_completed_for invocation.
    wait_for_signaling()

    self.expected_flow = ['< INVITE', '> 100', '> 180', '> 200', '< ACK ' , '< INVITE', '> 200', '< ACK',  '< INVITE', '> 200', '< ACK' , '< BYE', '> 200']
    verify_call_flow(:in,0)

    self.expected_flow = ['> INVITE', '< 100 {0,}', '< 200', '> ACK', '< INVITE', '> 200', '< ACK', '< INVITE', '> 200', '< ACK', '> BYE'  ]
    verify_call_flow(:out, 1)
    puts "done tests"
  end
end

Ain’t this cool! Just a few lines of Code and you get a test case with Both UAC & UAS simulation!. I wish the Sipper Guys posted some more examples. We are planning to integrate this testcases with Watir & FunFX to automate the Full VOICE + WEB Mash up.

May 28, 2009 Posted by sajid2045 | sip, sip stack, sip user agent emulation | | 1 Comment

Designers design, Coders Code

Taken from the famous book “Domain Driven Design” —

Manufacturing is a popular metaphor for software development. One inference from this metaphor: highly skilled engineers design; less skilled laborers assemble the products. This metaphor has messed up a lot of projects for one simple reason—software development is all design.

How true! I have heard of organizations where designers design and coders code! I would hate to work with such organization either as a Designer or as a coder.

April 29, 2009 Posted by sajid2045 | books, design | | No Comments Yet