Tuesday, November 03, 2009

ASF Big Feather Birthday Bash at Aeturnum

According to the "Raise a Glass to Apache" open invitation we wanted to have a event within our office. In Aeturnum we use number of Apache software within our development cycle, also some of our people already contributing to Apache projects in various ways.

So we take this moment to join with ASF to celebrate 10th anniversary and also to encourage people to contribute for ASF projects . With the support of our management we have ordered some ASF contributor badges to distribute among our people , In addition to that we got specially designed birthday cake.

Other than the party we had two presentation called " Revolution of FOSS" and "Apache -Community over code" to give some introduction about FOSS and ASF.

You can find "Apache -Community over code" presentation from here

[ Note - Above presentation is created using several resources and slides available with Apache and ApacheCon web sites and I just modified them according the the event]


Friday, October 30, 2009

Apache Asia Roadshow 2009 - Call For Presentations

The Apache Software Foundation together with Sri Lankan FOSS community invites you to submit a proposal for a presentation at APACHE ASIA ROADSHOW 2009. If you are a community member of any Apache projects or If you have worked with Apache projects or have a revolutionary idea on the use of an Apache project, then we would like to hear from you!

Please use the following link for submissions http://www.foss.lk/events/apacheasia09/cfp and the due date for submission is November 8th. APACHE ASIA ROADSHOW 2009 (Colombo) will be held in Colombo, Sri Lanka from December 3rd to 5th, 2009. For more details please visit FOSS.lk

Tuesday, October 27, 2009

Axis2 on embedded Jetty

In this week I tried to finalize the Axis2m Spring extension module by writing some integration test cases. For above purpose I used embedded Jetty server with Axis2 , this gave enough flexibility within test cases. There can be many possible approaches to use Axis2 with embedded Jetty server , here I have mentioned some of the approaches.

Using Jetty WebAppContext

One possible option is to use Jetty WebAppContext with Axis2 WAR based deployment approach.
        Server server = new Server(8080);
WebAppContext root = new WebAppContext();
root.setContextPath("/");
root.setResourceBase("/work/workspace/Jetty_Axis2/webapp1" );
server.setHandler(root);
server.start();

In here , webapp1/WEB-INF directory contains the repository for Axis2 and also have to define the AxisServlet in the web.xml file. The web.xml file should come under the webapp1/WEB-INF directory.


<servlet>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

Another possible approach is define AxisServlet in the code level instead of web.xml file as shown below.
        Server server = new Server(8080);
WebAppContext root = new WebAppContext();
root.setContextPath("/");
root.addServlet( "org.apache.axis2.transport.http.AxisServlet","/services/*");
root.setResourceBase("/work/workspace/Jetty_Axis2/webapp2" );
server.setHandler(root);
server.start();

Here in the directory structure only noticeable change is you don't need to have web.xml file.

Using Jetty ServletHolder
Only required step for this approach is provide a Axis2 repository as an InitParameter for AxisServlet.
        Server server = new Server(8080);
Context root = new Context(server,"/",Context.SESSIONS);
ServletHolder holder=new ServletHolder(new AxisServlet());
root.addServlet(holder,"/services/*");
holder.setInitParameter("axis2.repository.path", "/work/workspace/Jetty_Axis2/webapp3");
server.start();

Further it is possible to set Axis2.xml also as an input parameter.

holder.setInitParameter("axis2.xml.path", "/work/workspace/Jetty_Axis2/webapp3/axis2.xml");

Since my test cases dependent of Spring ,It was a requirement to add ContextLoaderListener as a ServletListener. It's again required only few lines of codes for this enhancement.
        Server server = new Server(8080);
Context root = new Context(server,"/",Context.SESSIONS);
ServletHolder holder=new ServletHolder(new AxisServlet());
root.addServlet(holder,"/services/*");
holder.setInitParameter("axis2.repository.path", "/work/workspace/Jetty_Axis2/webapp3");
root.getInitParams().put("contextConfigLocation","Module-app-test.xml");
root.setResourceBase("/work/workspace/Jetty_Axis2/webapp3");
root.addEventListener(new ContextLoaderListener());
server.start();

Monday, September 28, 2009

Camel Castor component

I have mentioned several times in this blog that Castor is one of my favorites option for java OXM. Recently I have contributed to create a castor component for Apacahe Camel project, this will enable to use Camel's powerful routing features together with Castor framework.

  1. Camel-castor data format simplify development work and reduce required time and effort. You can use OXM features without writing any Castor Specific codes with a mapping file or in a simple case without any mapping files.
  2. You have extra advantage to use powerful features of Camel. As an example you can convert your XML data into Java bean using camel-castor component and then possible to convert the same bean into a JMS or a Mail message using other existing fetures of Camel very easily.
This component is officially available with Camel 2.1 version but if you want it is possible to try out using 2.1 snapshots , you can download them from here or simply use Maven.

Also this wiki page describe some of the example scenarios and configuration options. I will plan to publish a full detail example to illustrate usage of this component in near future.

Tuesday, September 08, 2009

Testing Spring injected Servlets

Writing unit test cases is a really necessary step with the agile practices, but writing test cases for Servlets is little bit hard; because those are intend to run inside a container. There are few test frameworks such as Apache Cactus , HttpUnit, XMLUnit to facilitate to these requirements, specially ServletUnit provided by HttpUnit is a very smart and easy way to test Servlets.

But ServletUnit does not facilitate to inject Spring ApplicationContext into Servlet Context and hence testing Spring injected Servlets is not possible with ServletUnit (AFAIK).

But Spring-mock package provide some of the mock web component such as MockHttpServletRequest , MockHttpServletResponse and MockServletContext ..etc to test web applications. Also Spring test package provide features like auto-wiring, transactional supports etc. It is possible to use those two packages to test Spring injected Servlets.

Spring Test class such as AbstractDependencyInjectionSpringContextTests
Can be used to retrieve ApplicationContext for our test cases then we can set it in to a MockServletContext object as a attribute with key value WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE so that the Spring context is available to our servlet.

Normally in a container WebApplicationContextUtil is used to retrieve WebAplicationContext through the ServletContext using above WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE attribute.


One of the basic problem with this approach is WebApplicationContextUtils only accepts ApplicationContext classes that implement the WebApplicationContext interface, here AbstractDependencyInjectionSpringContextTests returns a org.springframework.context.support.GenericApplicationContext object as the ApplicationContext . Since GenericApplicationContext doesn’t implement the WebApplicationContext interface we can’t use this ApplicatioContext.

There are few remedies here.

1. Instead of Spring test package use kind of a WebApplicationContext class to load the test configuration. I tried with XmlWebApplicationContext but after several attempts I gave up.


String[] ctx= new String[]{"/WEB-INF/app.xml"};
webApplicationContext = new XmlWebApplicationContext();
webApplicationContext.setConfigLocations( ctx);
webApplicationContext.setServletContext(
new MockServletContext(
new FileSystemResourceLoader() ) );
webApplicationContext.refresh();


2. Use Spring test package to load the ApplicationContext (e.g – AbstractDependencyInjectionSpringContextTests ) and manually copy the bean definitions in to a WebApplicationContext object and set it in to the ServletContext.


Above second approach is worked with me and I used GenericWebApplicationContext as my WebApplicationContext. If you are interested in go through the following code segments.


This is a simple servlet I used to test, it utilize Spring bean called “helloService”.


public class SimpleService extends HttpServlet {

private HelloService helloService;

public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
// retrieve Spring AppContext through the ServletContext.
ServletContext servletContext = servletConfig.getServletContext();
ApplicationContext applicationContext = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
// retrieve Spring service
helloService = (HelloService) applicationContext.getBean("helloService");
}

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/xml");
PrintWriter pr = resp.getWriter();
String text = req.getParameter("text");
System.out.println(" recived : " + text);
pr.println(helloService.doService(text));
pr.flush();
pr.close();

}

}


Now we can create a reusable abstract Test class for our approach.

public abstract class AbstractSpringServeletTest extends
AbstractDependencyInjectionSpringContextTests {

private ServletConfig servletConfig;

protected abstract void init() throws Exception;

protected void onSetUp() throws Exception {

ServletContext sctx = new MockServletContext();
servletConfig = new MockServletConfig(sctx, "simple");
sctx.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
getWebApplicationContext());
init();

}

protected WebApplicationContext getWebApplicationContext() {
ApplicationContext ctx = getApplicationContext();
System.out.println(ctx.getClass().getName());
GenericWebApplicationContext wac = (GenericWebApplicationContext) BeanUtils
.instantiateClass(GenericWebApplicationContext.class);

String[] defNames = ctx.getBeanDefinitionNames();
for (String defName : defNames) {
wac.getBeanFactory().registerSingleton(defName,
ctx.getBean(defName));
}
return wac;

}

protected ServletConfig getServletConfig() {
return servletConfig;
}

protected ServletContext getServletContext() {
return servletConfig.getServletContext();
}

}


Here I derived AbstractSpringServeletTest class from AbstractDependencyInjectionSpringContextTests but it is possible to derive from any other test classes according to the requirements. Finally we can write concrete TestCase for out SimpleServlet as follows.


public class ServletTest extends AbstractSpringServeletTest {

private SimpleService simpleServlet;

protected String[] getConfigLocations() {
return new String[] { "classpath:app.xml" };
}

public void init() throws Exception {
simpleServlet = new SimpleService();
simpleServlet.init(getServletConfig());

}

public void testDoGet() throws Exception, IOException {
MockHttpServletRequest request = new MockHttpServletRequest(
getServletContext(), "GET", "/service");
request.addParameter("text", "sagara");
MockHttpServletResponse response = new MockHttpServletResponse();
simpleServlet.doGet(request, response);
String res = response.getContentAsString();
System.out.println(res);
assertEquals("Hello : sagara", res.trim());

}

}

Friday, May 29, 2009

Acegi Clustering on JBoss

Again about Acegi ....... Acegi does not support for clustering , but in many ceases it is not a necessary feature . but one of my current project requirement is to limit the concurrent session creation in the cluster environment. One way to achieve this is implement a Acegi "SessionRegistry" based on JGroup , i found this blog entry by Mert Akkan and tried for the proposed solution based on Jgroup DistributedHashtable . Unfortunately in our JBoss 4.2.1.GA (JGroup 2.4.1-sp3) environment gave a method not found exception for DistributedHashtable , I guess this is a version mismatch issue. so only remaining solution was dig in to JGroup framework for alternative solution , After several attempts i could able to get the successful results with ReplicatedHashtable .

This is the modified "DistributableSessionRegistryImpl" class based on JGroup ReplicatedHashtable.



public class DistributableSessionRegistryImpl
implements SessionRegistry,
ApplicationListener {


private Map sessionIds = new HashMap();
String channelName = "Acegi Cluster";
private String clusterOptions = null;
private static final int TIME_OUT = 0;

private boolean distributable=false;

public void setDistributable(boolean distributable) {
this.distributable = distributable;
}

public void setClusterOptions(String clusterOptions) {
this.clusterOptions = clusterOptions;
}


public void setChannelName(String channelName) {
this.channelName = channelName;
}

public Object[] getAllPrincipals() {
Collection collection = sessionIds.values();
Set principals = new HashSet();
for (Iterator iterator = collection.iterator();
iterator.hasNext();) {
DistributableSessionInformation sessionInformation = (DistributableSessionInformation) iterator.next();
principals.add(sessionInformation.getPrincipal());
}
return principals.toArray(new String[principals.size()]);
}

public SessionInformation[] getAllSessions(Object principal,
boolean includeExpiredSessions) {
Set sessionsUsedByPrincipal = getSessionIds(principal);

List list = new ArrayList();
Iterator iter = sessionsUsedByPrincipal.iterator();

while (iter.hasNext()) {
synchronized (sessionsUsedByPrincipal) {
String sessionId = (String) iter.next();
SessionInformation sessionInformation = getSessionInformation(sessionId);

if (includeExpiredSessions || !sessionInformation.isExpired()) {
list.add(sessionInformation);
}
}
}

return (SessionInformation[]) list.toArray(new SessionInformation[]{});
}

public SessionInformation getSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");

DistributableSessionInformation sessionInformation = ((DistributableSessionInformation) sessionIds.get(sessionId));
if(sessionInformation==null)return null;
return sessionInformation.sessionInformation(this);
}

public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof HttpSessionDestroyedEvent) {
String sessionId = ((HttpSession) event.getSource()).getId();
removeSessionInformation(sessionId);
}
}

public void refreshLastRequest(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");

SessionInformation info = getSessionInformation(sessionId);

if (info != null) {
sessionIds.put(sessionId, new DistributableSessionInformation(info,new Date()) );

}
}
public void expireSession(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");

SessionInformation info = getSessionInformation(sessionId);

if (info != null) {
sessionIds.put(sessionId, new DistributableSessionInformation(info,new Date(),true) );

}
}

public synchronized void registerNewSession(String sessionId, Object principal) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
Assert.notNull(principal, "Principal required as per interface contract");

if (getSessionInformation(sessionId) != null) {
removeSessionInformation(sessionId);
}

sessionIds.put(sessionId,new DistributableSessionInformation(principal, sessionId, new Date()));


}

private Set getSessionIds(Object principal) {
Collection collection = sessionIds.values();
Set principals = new HashSet();
for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
DistributableSessionInformation sessionInformation = (DistributableSessionInformation) iterator.next();
if (sessionInformation.getPrincipal().equals(principal))
principals.add(sessionInformation.getSessionId());
}
return principals;

}

public void removeSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");

SessionInformation info = getSessionInformation(sessionId);

if (info != null) {
sessionIds.remove(sessionId);


}
}

public void init() throws ChannelException {

if(!distributable)return;
JChannel jChannel;
ReplicatedHashtable hashtable;

if (clusterOptions == null) {
jChannel = new JChannel();

} else {
jChannel = new JChannel(Thread.currentThread().getContextClassLoader().getResource(clusterOptions));
}

jChannel.connect(channelName);
hashtable=new ReplicatedHashtable(jChannel,TIME_OUT);
System.out.println(" Members are "+ jChannel.getView().getMembers());
sessionIds = hashtable;




}

public void destroy() throws ChannelException {
if (sessionIds instanceof ReplicatedHashtable) {
ReplicatedHashtable o = (ReplicatedHashtable) sessionIds;
o.getChannel().close();


}
}
}
download the source code from here

Acegi (Spring Security) and Rampart integration

If you involved to any Spring based web application project, Acegi or Spring Security is not a new thing for you. Acegi is a grate framework that simplifies lot of security headache related to web application. I wrote several blog posts about some of the useful features of Aceigi .

Meanwhile Apache Rampart is a very efficient web service security module for Apache Axis2 that based on Apache WSS4J. I have used Axis2 as a part of Spring J2EE web application rojects, for all those projects I had one common challenge for security integration. Our user/role/access management modules were developed based on Acegi , when a user access to a web page ,Acegi invoke its“AuthenticationManager” to authorize the page access rights based on the provided user credentials . In web service context, same user send a web service request along with same credentials (as an example user name name /password) as a security headers and it is required to invoke “AuthenticationManager” through Rampart to authorize the access rights.

“CallbackHandler” is the underline Rampart mechanism to inject our security logic in to the Rampart module. But one of the critical problem here is there is no way to access to Axis2 MessageContext within the CallbackHandler and hence not possible to access either Spring security context or Spring AppicationContext.

Recently I saw number of post on the mailing list pointing out same requirement without having proper answer. In those days with our tide schedule I end up with a simple but little ugly solution for this.
I used same database table (that contains user security information) for both Acegi and Rampart, in Acegi I injected my user information using “UserDetailService” and for Rampart I wrote small JDBC based DAO service and injected into “CallbackHandler”. But later I could come up with a smart approach for this, in this approach the same acegi AuthenticationManager will used by the Rampart also without reloading. Following steps will help out to any one facing to similar problems.

Step -1
Create a class called “Axis2AwareContextLoaderListener” that extend from Spring ContextLoaderListener . Then in the contextInitialized method set Spring ApplicationContext in to Axis2 ApplicationContextHolder as follows.


public class Axis2AwareContextLoaderListener
extends ContextLoaderListener {

/** The holder. */
ApplicationContextHolder holder;

public void contextInitialized(ServletContextEvent event) {
super.contextInitialized(event);
ApplicationContext appCtx = (ApplicationContext) event
.getServletContext()
.getAttribute(
WebApplicationContext.
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
holder = new ApplicationContextHolder();
holder.setApplicationContext(appCtx);

}

public void contextDestroyed(ServletContextEvent event) {
super.contextDestroyed(event);
holder = null;
}

}

Step -2
Now in the CallbackHandler implmentaion class we can access to Spring ApllicationContext as follows through the getContext() method of ApplicationContextHolder.

ApplicationContext secCtx = ApplicationContextHolder.getContext();
AuthenticationManager am = (AuthenticationManager) secCtx
.getBean(AUTHENTICATION_MANAGER_BEAN_NAME);


Step -3
Create an instance of Acegi Authentication object with credentials values of Rampart Callbacks object.


public class ServerPWCBHandler
implements CallbackHandler {

/** The Constant AUTHENTICATIONMANAGER_BEAN_NAME. */
public static final String
AUTHENTICATIONMANAGER_BEAN_NAME =
"authenticationManager";

public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {

ApplicationContext secCtx = ApplicationContextHolder.getContext();
AuthenticationManager am = (AuthenticationManager) secCtx
.getBean(AUTHENTICATIONMANAGER_BEAN_NAME);

for (int i = 0; i < callbacks.length; i++) {

// When the server side need to authenticate the user
WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[i];

if (pwcb.getUsage() == WSPasswordCallback.
USERNAME_TOKEN_UNKNOWN) {
try {
Authentication aut =
new UsernamePasswordAuthenticationToken(
pwcb.getIdentifier(), pwcb.getPassword());
am.authenticate(aut);

} catch (Exception e) {
throw new UnsupportedCallbackException(callbacks[i], e
.getMessage());
}

}

}
}

}



If you want to look at any sample you can download it from here, this sample is a combination of Spring/Acegi/Tapestry5 web application and a Axis2 /Rampart based web service, both web application and web service use values of users.properties file for user authentication.

Monday, May 25, 2009

Guice Axis2 integration

Google Guice is a dependency injection (DI) framework, it provides somewhat different configuration option than spring. Axis2’s spring support is already proven, in this post I will explain how to integrate Guice beans in to Axis2 services.

To integrate Guice with axis2 we have to fulfill flowing two requirements,
  1. Load the relevant Guice “Module “(similar to ApplicationContext in Spring) at the service start up time.
  2. Above Guice beans should be accessible by Axis2 services during the run time.
We can achieve above two requirements as follows.
  1. It is possible to use an implementation of ServletContextListener interface to load the Guice module at the start-up time.
  2. Axis2 provide a interface called ServiceObjectSupplier, it is possible to use this interface to provide a custom beans for axis2 web services. Axis2 – Spring support is already based on this concept.
You can access to source code form here or possible to download binary JAR file directly from here.

Please see the following simple example.

I have following interface to expose as a Axis2 web service, but the actual implementation will provide by the Guice framework.

public interface SimpleService {

public String sayHello();
}

This is our Guice module class..

public class SimpleModule extends AbstractModule {

protected void configure() {
bind(SimpleLogger.class).to(SimpleLoggerImpl.class);
bind(SimpleService.class).to(SimpleServiceImpl.class);

}

}

Next step is to configure our service.xml file for Guice integration, in this case I used a new parameter name called “GuiceBeanName” to define the Guice service bean.



Actually we don’t need to have this parameter "GuiceBeanName" , “ServiceClass” parameter can be used for Guice integration too ,but I used two parameters to clearly separate each task we assign for each parameters, “ServiceClass” Is only used as the service interface to generate WSDL definition for our service where “GuiceBeanName” is used to define Guice bean name for “ServiceObjectSupplier” implementation.

<parameter name="ServiceObjectSupplier" locked="false">
org.apache.axis2.integration.guice.GuiceContextObjectSupplier<
/parameter>
<parameter name="GuiceBeanName" locked="false">org.google.guice.sample.SimpleService<
/parameter>
<parameter name="ServiceClass" locked="false">org.google.guice.sample.SimpleService</parameter>

Final step is to define our “GuiceServletContextListener” in the web.xml as follows.

<context-param>
<param-name>module</param-name>
<param-value>org.google.guice.sample.SimpleModule
</param-value>
</context-param>

<listener>
<listener-class>
org.apache.axis2.integration.guice.
GuiceServletContextListener
</listener-class>
</listener>

here, context parameter called “module” is used to provide the Guice module name , GuiceServletContextListener will try to load this “module” within it’s contextInitialized method.


You can download the complete example from here.