5 Replies Latest reply on Apr 23, 2011 2:13 PM by Daniel Bevenius

    implementation.clojure

    Daniel Bevenius Master

      Hi,

       

      I've been playing around with Clojure and added some basic support for this in the form of an 'implemenation.clojure'.

      The topic branch for this can be found here.

       

      The configuration for this looks like this:

       

      <sd:switchyard 
          xmlns="urn:switchyard-component-clojure:config:1.0" 
          xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912" 
          xmlns:sd="urn:switchyard-config:switchyard:1.0"
          xmlns:bean="urn:switchyard-component-bean:config:1.0">
      
          <sca:composite>
      
              <sca:component name="CamelComponent">
                  <sca:service name="OrderService" >
                      <sca:interface.java interface="org.switchyard.component.clojure.deploy.support.OrderService"/>
                  </sca:service>
      
                  <implementation.clojure>
                      <script>
                          (ns org.switchyard 
                              (:import org.switchyard.Exchange))
                          (defn process [ex] (.setContent (.getMessage ex) "Fletch") (.getContent (.getMessage ex)))
                      </script>
                  </implementation.clojure>
              </sca:component>
      
          </sca:composite>
      
      </sd:switchyard>
      

      The Clojure function is passed the SwitchYard Exchange and is required to import that class. It then as access to the complete content of the Exchange to operate on.

      Calling this service is done in the same way as calling any other SwitchYard service, for example:

      String title = (String) newInvoker("OrderService").operation("getTitleForItem").sendInOut(10).getContent(String.class);
      
      
        • 1. Re: implementation.clojure
          Keith Babo Master

          Nice one!  Tom and I had actually been discussing some stuff that might be relevant to this area as well.

           

          First, what makes a good service interface for languages that run on the JVM, but are not Java?  In talking to the TorqueBox guys, it seems like most Rubyists would prefer data in a hash and the idea of a contract is a runtime concept with duck typing vs. a compile-time concept in Java.  I'm guessing that other languages such as Groovy, JavaScript, Pyhton, Scala, etc. will all have this kind of "similar but different" thing going w/r/t the service interface and data types.

           

          Next item on my mind would be what's the right type of invocation contract for these components.  Would it make sense to pass the message instead of the exchange?  Message + context?  Maybe it's an option and depends on the content of the script.

           

          Another thing to consider is whether the script is in-lined in the config or stored separately and referenced using a path value.  I imagine you might want both - in-line for easy stuff that's less than a handful of lines, path reference for bigger scripts.  Keeping the script outside the config also allows for editors to apply syntax highlighting and validation.

           

          Yet another interesting (at least to me) consideration is whether a scanner is of any use in terms of picking up these scripts and generating configuration off of them.  This could include setting up the component definition, deriving the interface, typing the request and response messages, etc.  This might be straightforward with some languages and might require annotation-like helpers with others.

          • 2. Re: implementation.clojure
            Daniel Bevenius Master

            Message + context?  Maybe it's an option and depends on the content of the script.

            Yeah, I think it would depend on the script and what it does. But making this configurable sounds like an option.

             

             

            Another thing to consider is whether the script is in-lined in the config or stored separately and referenced using a path value.  I imagine you might want both

            Yeah, both options would be nice to have.

             

             

            Yet another interesting (at least to me) consideration is whether a scanner is of any use in terms of picking up these scripts and generating configuration off of them.

            If this is possible that would be great.

            • 3. Re: implementation.clojure
              Daniel Bevenius Master

              Message + context?  Maybe it's an option and depends on the content of the script.

              I've added the following attribute to specify this:

               

              <implementation.clojure injectMessageContentOnly="true" scriptFile="file://sample.clj"/>
              

              So, by default if the injectMessageContentOnly is not specified the SwitchYardExchange will be injected.

               

               

              Another thing to consider is whether the script is in-lined in the config or stored separately and referenced using a path value.

              You can now specify a path to a fille as an option to having the script inline:

               

                          <implementation.clojure scriptFile="file://clojure.clj"/>
              

               

              I've pushed new commit with these changes that can be found here .

              • 4. implementation.clojure
                Keith Babo Master

                Do you want to submit a pull request to bring this into the components repository?  A few additional comments on the update:

                 

                • Should the default be to inject the message content with the override being to inject the exchange?  I guess the answer to this question depends on whether someone writing a clojure script will prefer to deal with native clojure data structures by default vs. an exchange instance which may be a bit foreign.  I dunno ... you know more about Clojure than I do. ;-)
                • Looks like the scriptFile URI is an absolute file path.  Will this work if the script is packaged up in a jar with the rest of the switchyard app?  The approach we've taken so far is that use of file:// in a config indicates an absolute file path reference where a "naked path" (e.g. scriptFile="scripts/sample.clj") indicates it's a classpath resource.
                • After you get this committed to the components repository I can show you how to write a Forge plugin for creating Clojure services!  :-)

                 

                cheers,

                keith

                • 5. Re: implementation.clojure
                  Daniel Bevenius Master

                  Do you want to submit a pull request to bring this into the components repository?

                   

                  I've added this jira with the pull request.

                   

                   

                  Should the default be to inject the message content with the override being to inject the exchange?

                  Yes I think so to and I've made the default to be to simply to inject the content of the message. The Excange can be injected with the injectExchange attribute now.

                   

                   

                  Looks like the scriptFile URI is an absolute file path.

                  Another good point:) I've made this a string now and using the Classes utils class to find the script file.

                   

                   

                  After you get this committed to the components repository I can show you how to write a Forge plugin for creating Clojure services

                  Cool, I just saw that new code and have to take a closer look at it. I'd like to add this feature to learn how this works as I've never used Forge before.

                   

                  Thanks for you feedback on this!