<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Alexey Aristov</title>
	
	<link>http://www.aristov.org</link>
	<description>ART IS FANATICISM THAT DEMANDS DIPLOMACY</description>
	<lastBuildDate>Mon, 21 Jun 2010 20:56:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/AlexeyAristov" /><feedburner:info uri="alexeyaristov" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Clojure + Flex</title>
		<link>http://feedproxy.google.com/~r/AlexeyAristov/~3/5QR7JaFppMg/</link>
		<comments>http://www.aristov.org/2010/06/clojure-flex/#comments</comments>
		<pubDate>Sun, 06 Jun 2010 20:14:25 +0000</pubDate>
		<dc:creator>aav</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.aristov.org/?p=16</guid>
		<description><![CDATA[Clojure can be used as back-end language for Adobe Flex applications. While evaluating this option I created a small example that shows how to implement clojure based services, that are exposed over AMF.  I used open source AMF implementation &#8211; GraniteDS, that appears to be solid and mature. 
Complete example can be downloaded here.
First [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clojure.org">Clojure</a> can be used as back-end language for Adobe Flex applications. While evaluating this option I created a small example that shows how to implement clojure based services, that are exposed over AMF.  I used open source AMF implementation &#8211; <a href="http://www.graniteds.org/">GraniteDS</a>, that appears to be solid and mature. </p>
<p>Complete example can be downloaded <b><a href="downloads/clojuregraniteds.zip">here</a></b>.</p>
<p>First of all we create GraniteDS configuration file (<i>services-config.xml</i>)</p>
<pre class="brush:xml">
<services-config>
    <services>
        <service
            id="myservice"
            class="flex.messaging.services.RemotingService"
            messageTypes="flex.messaging.messages.RemotingMessage">

            <destination id="mydestination">
<properties>
          			<factory>clojureFactory</factory>
        		</properties>
      		</destination>
        </service>
    </services>

	<factories>
	   <factory id="clojureFactory" class="org.aristov.blog.clojure.granite.ClojureServiceFactory"/>
	</factories>

	<channels>
        <channel-definition id="channel">
            <endpoint/>
        </channel-definition>
    </channels>
</services-config>
</pre>
<p>This configuration contains destination (mydestination) that refers to service factory implemented in Java (<i>org.aristov.blog.clojure.granite.ClojureServiceFactory</i>). Service factory simple method that creates and caches of <i>ClojureServiceInoker</i>.</p>
<pre class="brush:java">
public ServiceInvoker<?> getServiceInstance(RemotingMessage request)
			throws ServiceException
{
   if (invoker == null)
   {
       GraniteContext context = GraniteContext.getCurrentInstance();

       Destination destination = context.getServicesConfig()
		.findDestinationById(request.getClass().getName(),
					request.getDestination());

       invoker = new ClojureServiceInvoker(destination, this);
   }

   return invoker;
}
</pre>
<p><i>ClojureServiceInvoker</i> dispatches every invocation to predefined clojure function (<i>granite-dispatch</i>) that is defined in the granite namespace. Invocation parameters, prefixed with concatenated endpoint and method names are passed to the dispatch function as is.</p>
<pre class="brush:java">
protected Object adjustInvokee(RemotingMessage request, String methodName,
			Object[] args) throws ServiceException
{
     return this;
}

protected Object[] beforeMethodSearch(Object invokee, String methodName,
			Object[] args)
{
     Object[] params = new Object[args.length + 1];
     System.arraycopy(args, 0, params, 1, args.length);
     params[0] = destination.getId() + "/" + methodName;

     return new Object[] { "invoke", new Object[] { params } };
}

public Object invoke(Object[] params) throws Exception
{
	return dispatch.applyTo(ArraySeq.create(params));
}
</pre>
<p>Clojure invocation handler &#8211; <i>granite-dispatch</i> uses <i>convert-params</i> function converts Map based arguments, that a created by GraniteDS from ActionScript objects.</p>
<pre class="brush:clj">
(defn map-to-native [object]
	(into {}
		(map
			#(let [[k v] %]
				(cond
					(instance? java.util.Map v) (vector k (map-to-native v))
					:default %))
		 object)))

(defn convert-params [list]
	(map
		#(cond
			(instance? java.util.Map %) (map-to-native %)
			:default %)
	list))

(defn granite-dispatch [function &#038; params]
	(apply (resolve (symbol function))(convert-params params)))
</pre>
<p>Finally invocation is redirected to a user defined function in a namespace that matches destination id.</p>
<pre class="brush:clj">
(ns mydestination)

(defn doSomething [p1 p2 p3 p4 p5]
	(println p1 p2 p3 p4 p5))
</pre>
<p>On the Flex side it looks like this:</p>
<pre class="brush:js">
private var remoteObject: RemoteObject;

private function init() : void
{
  	remoteObject  = new RemoteObject();
	remoteObject.destination = "mydestination";

       	var cs:ChannelSet = new ChannelSet();
     	var c1:AMFChannel = new AMFChannel("channel", "http://localhost:9999/amf");
        cs.addChannel(c1);

        remoteObject.channelSet = cs;
}

private function doSomething()
{
       	remoteObject.doSomething(1, 2, 'Something',  new MyData(), 'More')
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.aristov.org/2010/06/clojure-flex/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.aristov.org/2010/06/clojure-flex/</feedburner:origLink></item>
	</channel>
</rss>

