Extending ConduitThere are several strategies for extending Conduit to do whatever you need it to do for Flex remoting Before attempting to extend Conduit, please read: Conduit Architecture, so that you understand the core architecture of Conduit, and how Invokers, Serialisers and Deserialisers work. It may also be useful to review the API documentation which is bundled with Conduit. There are some BlazeDS Java objects that gets passed into and utilised by Conduit, reference for which can be found in the BlazeDS JavaDoc. Implementing your own Invoker, Serialiser or DeserialiserWhile not the easiest way to extend Conduit, you can implement your own Invoker, Serialiser or Deserialiser within Conduit, and then configure your remoting destination to use your own implementation. E.g, if I was to create my own Invoker, mystuff.doMyThingInvoker: <destination id="MyOwnConduit">
<channels>
<channel ref="my-cfamf" />
</channels>
<adapter ref="conduit" />
<properties>
<source>*</source>
<cfcs>
<!--
Whether or not reload the CFCs below on each request.
Useful for debugging when building new invokers,serialisers
or deserialisers
-->
<reloadcfcs>false</reloadcfcs>
<!--
The CFC that invokes the remote method call
-->
<invoker>mystuff.doMyThingInvoker</invoker>
<!--
Translates CF=>AS3
-->
<serialiser>conduit.core.CFSerialiser</serialiser>
<!--
Translates AS3=>CF
-->
<deserialiser>conduit.core.CFDeserialiser</deserialiser>
</cfcs>
</properties>
</destination>
This would configure Conduit to use mystuff.doMyThingInvoker as the CFC invoker, when remote requests came to the MyOwnConduit destination. It is highly recommended that if you write your own Invoker, Serialiser or Deserialiser, that you extend the core.conduit.AbstractComponent, as it contains all the in built functionality for enabling filters, and gives you base methods for initialize(), and validate(). Extending the core Invoker, Serialiser or DeserialiserYou can also extend the core Invoker, Serialiser and Deserialiser objects that ship with Conduit, and overwrite the necessary parts to add in the extra features or modifications that you would like, and then configure them in your own remoting destination. For example, when we send information from ColdFusion to Flex, we may want to reverse every Simple value (String, date, numeric) that we come across. So I create a new component, under /myObjects/reverse, and call in CFReverseSerialiser.cfc, and make it extend conduit.core.CFSerialiser. We will now overwrite the translate method, which handles what data gets converted, and how, depending on its data type. The code would look something like this: <cfcomponent output="false" extends="conduit.core.CFSeriaiser" hint="Component for serialising CF=>AS3, in reverse">
<cffunction name="translate" hint="translation function for objects,reverses simple values" access="private" returntype="any"output="false">
<cfargument name="object" hint="the object to serialise" type="any" required="no">
<cfargument name="cache" hint="local reference cache for cyclic graphs" type="any" required="Yes">
<cfscript>
if(isSimpleValue(arguments.object)
{
//if it's simple, then reverse it!
return reverse(arguments.object);
}
else
{
return super.translate(argumentCollection=arguments);
}
</cfscript>
</cffunction>
</cfcomponent>
And we can configure a special 'ConduitReverse' destination for anyone who wants reversed Strings in their code: <destination id="ConduitReverse">
<channels>
<channel ref="my-cfamf" />
</channels>
<adapter ref="conduit" />
<properties>
<source>*</source>
<cfcs>
<reloadcfcs>false</reloadcfcs>
<invoker>conduit.core.CFCInvoker</invoker>
<serialiser>myObjects.reverse.CFReverseSerialiser</serialiser>
<deserialiser>conduit.core.CFDeserialiser</deserialiser>
</cfcs>
</properties>
</destination>
Now, every remoting call that comes though the ConduitReverse destination, will have its simple data reversed. Implementing a FilterFilters are an easily way to change aspects of the Conduit Invoker, Serialiser and Deserialiser process, without having to change, or extend core code. Filters occur both before and after each of the execute() actions within each of the Conduit component types. To configure a filter, the following configuration is used: <destination id="Conduit">
<channels>
<channel ref="my-cfamf" />
</channels>
<adapter ref="conduit" />
<properties>
<source>*</source>
<cfcs>
<!-- ..config .. -->
</cfcs>
<!-- Filter -->
<filters>
<filter>
<path>{CFC Path to the filter}</path>
<apply-before>serialiser|deserialiser|invoker</apply-before> (This is optional, and can be applied multiple times)
<apply-after>serialiser|deserialiser|invoker</apply-after> (This is optional, and can be applied multiple times)
<args>{arguments, as string, or XML nodes}</args> (Optional)
</filter>
</filters>
</properties>
</destination>
A filter CFC is one that matches the following method signatures: <cffunction name="init" hint="Constructor" access="public" output="false">
<cfargument name="args" hint="the argument flex.messaging.config.ConfigMap, from <args>" type="struct" required="Yes">
<cfscript>
//do initialisation;
return this;
</cfscript>
</cffunction>
<cffunction name="doFilter" hint="does the filtering" access="public" returntype="void" output="false">
<cfargument name="filterData" hint="the data for the filter" type="struct" required="Yes">
<cfargument name="filterChain" hint="the filter chain" type="conduit.core.filter.FilterChain" required="Yes">
<cfscript>
//do filter processing
//push on to the next filter
arguments.filterChain.next();
</cfscript>
</cffunction>
In the Conduit download, there is an example ReverseFilter, with accompanying configuration to show how to build a simple Filter that reverses simple values. |