Tuesday, May 29, 2012

MVEL 2.1.0.drool8 and up is not compatible with Spring 3.1

MVEL version:2.1.0.drool8 +
Spring version:3.1 +
Issue:Error invoking getBean method in mvel code

Description

If you are using mvel version 2.1.0.drool8 and up and Spring 3.1 and up, you are likely getting the following error message when you invoke the getBean(String) method in your mvel code.

Caused by: org.springframework.beans.factory.BeanDefinitionStoreException:
 Can only specify arguments for the getBean method when referring to a prototype bean definition
 at org.springframework.beans.factory.support.AbstractBeanFactory.checkMergedBeanDefinition(AbstractBeanFactory.java:1215) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE]
 at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105) ~[spring-context-3.1.1.RELEASE.jar:3.1.1.RELEASE]
 ... 87 common frames omitted

Causes:

After some digging into the mvel source code, it shows that ReflectiveAccessorOptimizer class is calling ParseTools.getBestCandidate method to find the matching method. The way the method finds the matching candidate is by assigning a score to each candidate. The method that score highest is the best candidate. If there there are more than one methods score the same, the first one wins.
Here is the problem: Spring's ApplicationContext class has multiple getBean methods and two of them score the same:
getBean(String)
getBean(String, Object[]).
If you invoke getBean("myBeanId"), you will want the first method to be invoked. However, in mvel 2.1.0.drool8 and up, the ApplicationContext instance mvel retrieved is XMLApplicationContext, in which getBean(String, Object[]) is before getBean(String) in the list. So the best candidate becomes getBean(String, Object[ ]) and so on the Spring will throw the exception above.

Solutions

Solution 1

The easy fix is to use mvel version 2.1.0.drool7

Solution 2

In order to use use the latest mvel library, create a wrapper class around the applicationContext, i.e. ApplicationContextWrapper. Then implement a helper method called getBean(String) that calls getBean(String) method in ApplicationContext class. Then use this helper method in your mvel code. e.g. applicationContextWrapper.getBean("myBeanId"); This way, there is only one method named getBean in the new wrapper class.

Solution 3

Wait for MVEL team to come up with a resolution to this issue. Maybe a better scoring system. getBean(String) and getBean(String, Object[]) should score differently. [Edit] I created a JIRA entry for MVEL team: MVEL-276

Thursday, March 1, 2012

How to: Use Time Machine To Backup Multiple Mac Computers On A Single Hard Disk

Requirements:
  • I have three mac computers (one iMac, one MacBook Pro and a Mini) that needs to be back up using Time Machine.
  • I want to use one hard drive to back up all three computers wirelessly over WiFi

Solutions:
  1. Make sure all macs are within the same WiFi network
  2. Connect one 1 TB external harddrive to my Mac Mini because the mini is up 24/7 as server
  3. Share the external drive and grant proper permission so that all other Mac can access the drive
  4. On each Mac, go to Terminal and enter the following command:
    sudo defaults write com.apple.systempreferences TMShowUnsupportedNetworkVolumes 1
  5. Go to Time Machine Preference and select the network drive just shared and use it as back up disk 

The key here is set the Time Machine to use Network attached harddrive by type the command above. I got this tip from this post

Mission Completed!! All my macs are now being backup on the same drive wirelessly. Hope this tip can help you too.

Edit 1: Because multiple machine is being backup onto a single drive, you might want to reduce the frequency of backup so that your network won't be jammed.  By default, Time machine does not let you adjust the frequency and do it manually in the system launch file is not easy for normal user.  I found a tool that's build for just doing that.  I will share the link later.

Edit 2: Friend of mine just point out that if you have vmware running and the images are stored in your main drive which is being backup by Time Machine, you'd better exclude the images because Time Machine does not do incremental backup on disk images.  It does whole backup every time when it sees image is changed.   That will eat your backup hard drive storage very quickly especially if you use default Time Machine backup schedule which is every hour...

Wednesday, February 22, 2012

Setup Remote Access to Local MySQL Server

Do Following:
  1. open /etc/my.cnf for edit
    If my.cnf does not exist, copy a sample from /usr/local/mysql/support-files.
    >sudo cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf 
  2. In my.cnf file
    Comment out skip-networking
    If the server has dedicated IP, Add
    bind-address = server.ip.address //i.e. 34.23.115.234
    If the server is connected within the local network, this line is not required
  3. Restart MySQL server
    >sudo /usr/local/mysql/support-files/mysql.server restart
  4. Grant remote access to user and remote IP
    >mysql -u root -p
    >create database mydb
    >grant all on mydb.* to leo@11.22.33.44 identified by 'password'
  5. Now you can connect remotely to mydb from 11.22.33.44 using 'leo'

Tuesday, January 17, 2012

JQuery UI Dialog Auto Width and Height Cross Browser (Fixed IE issue)

JQuery Dialog is one of my most used UI components.  However, the width: 'auto'; and height: 'auto'; options are not supported in IE, which means if you set them to 'auto', the dialog will expand to take the full window width and height will be undetermined.
I have searched around the web and see many people having the same issue but no solutions. Luckily, I was able to find a way to make it work.  Here is how:

1. Create a wrapper element (i.e. div) around your dialog content.

....Actual Dialog Contents....

2. Add the following style on the page

 
This is the key part. IE does not calculate the actual width if you don't specify a width value initially, it will use the browser window width instead. By giving IE an initial width value, it will set it to the proper value. The IE check here is necessary, because this should only be applied to IE. If you do not do IE check, FF and Chrome will use the width and height value as the result dialog width and heigth.

3. Finally, add the following javascript code on the page.

if($.browser.msie){
   //Get the acutal width and height and add some margin
   var w = $("#my_dialog #wrapper")[0].clientWidth + 20;
   var h = $("#my_dialog #wrapper")[0].clientHeight + 20; 
   $("#my_dialog").dialog('option', {'width':w,'height':h});
}
This piece of code will find the actual width and height and update the dialog to the current width and height.

Let me know if you encounter any issue with this solution. :)