Monday, November 3, 2008

Asterisk-java + Spring

Those who don't know about Asterisk Java, its a wonderful java library to talk to a asterisk server through AGI & AMI. We are using it heavily to control our Asterisk box from our "main application". Our main application is a full fledged spring application running on tomcat. At first we were running the asterisk java components (AGIServer , AgiScripts etc) as a normal java application but soon we wanted our AgiScripts to talk to our spring beans Or even better, we want our agi scripts to be Spring beans.

The beauty of the spring and asterisk-java library is that they were made for each other! Asterisk java library was written in wonderful object-oriented way with clear separation on dependencies. So it was very easy to define the AGIServer and all its dependencies as Spring Bean. So We can inject the MappingStrategy with our own implementation of "BeanNameAwareAGIMappingStrategy" which implements ApplicationContextAware looks like this

@Override
protected AgiScript createAgiScriptInstance(String beanName) {
Object bean = applicationContext.getBean(beanName)
if(bean == null)
{
throw new IllegalArgumentException("No bean with name: [" + beanName +"] found. Make sure that you have all beans defined which are there in your fastagi-mapping.properties");
}
if(!(bean instanceof AgiScript))
{
throw new IllegalArgumentException("spring bean : " + beanName + " must implement org.asteriskjava.fastagi.AgiScript interface");
}
return (AgiScript) bean;
}
So now, instead of defining fully qualified classnames in your "fastagi-mapping.properties", you only give the bean name and our mapping strategy looks it up from the application context. So your plain agi scripts can talk to your dao, services and do all sort of fancy things! Isn't that wonderful!

3 comments:

Unknown said...

We've been using similar approach for almost two years, with beans defined in XML files. It proved itself very convenient. Anyway, we implemented it in a slightly different way.

A brief example:

<bean id="agiServer" class="org.asteriskjava.fastagi.DefaultAgiServer" >
<property name="port" value="${server.callManager.port}"/>
<property name="mappingStrategy" ref="mappingStrategy"/>
</bean>

<bean id="mappingStrategy" class="ua.cv.usl.ice.agimanager.BasicMappingStrategy">
<property name="mappings">
<map>
<entry key="extension" value="ua.cv.usl.ice.callmanager.entryPoint.InternalCallEntryPoint"/>
<entry key="e164_outgoing" value="ua.cv.usl.ice.callmanager.entryPoint.PstnEntryPoint"/>
</map>
</property>
</bean>


Here BasicMappingStrategy extends AbstractMappingStrategy, implementing determineScript(AgiRequest request) method of MappingStrategy interface, so that createAgiScriptInstance(String className) is not overridden. Instead, createAgiScriptInstance is used only once - on BasicMappingStrategy initialization, to create instances of all Agi scripts and put them in a map, which can be accessed fast later, while calling to determineScript()

Unknown said...

We have using Asterisk-java for 3 years now. Now the number of call has increased. So, we have to manage the access to DB via connection pool.
Any clue are welcome.

Unknown said...

Do you mean Asterisk's DB or your application's DB? If you mean application's DB you can simply implement DB access layer that uses a technology which allows connections pooling, like Hibernate or something.