Saturday, February 18, 2006

A prototype of Jython ScriptFactory for Spring Framework

SpringFramework 2.0 M2 does not include Jython support for its scripting framework. I don't know the reason. So I decide to create a prototype to prove it is doable.

Suppose we have a Java interface Messenger:

package org.yweng.spike.Spring;

public interface Messenger {
String getMessage();
}

And we have a Jython Script, Messenger.py, which implementes this interface:

from org.yweng.spike.Spring import Messenger

class PythonMessenger(Messenger):
def getMessage(self):
return 'Message from Python Messenger'

def getInstance():
return PythonMessenger()

Notice the getInstance method in the Jython module. The idea is using "naming convention" to help the Jython ScriptFactory instantiate Jython object.

The Spring xml configuration:

<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="PyMessenger" class="org.yweng.spike.Spring.JythonScriptFactory">
<constructor-arg
value="classpath:org/yweng/spike/Spring/Messenger.py" />
<constructor-arg
value="org.yweng.spike.Spring.Messenger" />
</bean>
</beans>

The JythonScriptFactory class looks like this:


package org.yweng.spike.Spring;

import java.io.IOException;

import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.ScriptFactory;
import org.springframework.scripting.ScriptSource;
import org.springframework.util.Assert;
import org.apache.log4j.Logger;

import org.python.util.PythonInterpreter;


public class JythonScriptFactory implements ScriptFactory {
private static Logger logger =
Logger.getLogger(JythonScriptFactory.class);

private final String scriptSourceLocator;
private final Class[] scriptInterfaces;

public JythonScriptFactory(String scriptSourceLocator,
Class[] scriptInterfaces) {
Assert.hasText(scriptSourceLocator);
Assert.notEmpty(scriptInterfaces);
this.scriptSourceLocator = scriptSourceLocator;
this.scriptInterfaces = scriptInterfaces;
}

public String getScriptSourceLocator() {
return this.scriptSourceLocator;
}

public Class[] getScriptInterfaces() {
return this.scriptInterfaces;
}

public boolean requiresConfigInterface() {
return true;
}

public Object getScriptedObject(ScriptSource scriptSourceLocator,
Class[] scriptInterfaces)
throws IOException, ScriptCompilationException {
String strScript = scriptSourceLocator.getScriptAsString();

if (scriptInterfaces.length > 0) {
try {
PythonInterpreter interp = new PythonInterpreter();
interp.exec(strScript);
interp.exec("this = getInstance()");
return interp.get("this", scriptInterfaces[0]);
} catch (Exception ex) {
throw new ScriptCompilationException(ex.getMessage());
}
}
logger.error("No scriptInterfaces provided. ");
return null;
}
}


Junit Test case:

package org.yweng.spike.Spring;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.log4j.Logger;

public class TestJythonScriptFactory extends TestCase {
private static Logger logger = Logger.getLogger(TestJythonScriptFactory.class);

private ApplicationContext ctx =
new ClassPathXmlApplicationContext("org/yweng/spike/Spring/ApplicationContext.xml");

public void testPyMessenger() {
Messenger messenger = (Messenger)ctx.getBean("PyMessenger");
assertNotNull(messenger);
String msg = messenger.getMessage();
logger.info(msg);
}
}



It's not pretty but it works. :)

Saturday, February 11, 2006

The new Perforce Eclipse plugin

We had a lot of trouble with the "stable" version of the Perforce Eclipse Plugin (P4WSAD) in the past weeks. It mainly dues to the heavy load of our perforce servers and the "keep connected" nature of the perforce plugin. We were facing very long response time when we refactored our java code base. Because Eclipse's built-in refactoring does not do "p4 edit" on the files it modifies, we also have to spend some time to make sure all the modified files are in the change list. The experience is so painful that we almost decide to switch to subversion and use svk to sync between subversion and perforce repositories.

Today, I decided to give the beta version of perforce plugin a try. And I am happy I did. The new plugin introduces "unmanage" mode. The Eclipse project is disconnected with the Perforce server under this mode. Sweet!

Besides the "unmanage" feature, I have found two other features were very useful. One of them is "check consistency". The plugin can find out which files should be "edited" or "added" and put them in default change list after the refactoring. So you don't need to figure it out by yourself. Another one is "exclude from source control". You can exclude some generated artifacts from the version control so that "check consistency" won't always put them in your default change list. (This feature might be in the old version already. )

It looks like the new plugin solves most of our problems. However, there is one more thing. :) Merge is still difficult inside the perfoce plugin. P4V is still better than the plug-in in this area.

Thursday, February 09, 2006

Borland is going to sell its most valuable product line

Borland made another interesting decision: selling its famous development tools product line. Without Delphi, C++ builder, JBuilder and Interbase, is Borland "the Borland" we were talking about?