Note: my knowledge of soap is not very deep, but I have done the following 
in a production system.

If you have a WSDL available, a good approach is to generate the (Java) 
client code and then use it via Java interop.  You can smooth out the rough 
edges and shed the extra java types by using the clojure.java.data library 
to define to-java and from-java 
methods. https://github.com/clojure/java.data


The state-of-the-art in java code generation from a WSDL seems to be Apache 
cxf http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html 
 Below is a mini-tutorial of its use.

In the project.clj, add the configuration and dependencies that cxf needs. 
We'll be using cxf through a maven plugin that wraps it 
(cxf-codegen-plugin).  The maven plugin
is configured via a pom, so we'll use leinigen's :pom-additions and 
:pom-plugins keys to inject stuff into the pom it generates.


(defproject my-soap-client "0.0.1-SNAPSHOT"
  :description "Example of using leinigen to generate a pom to generate Java 
from WSDLs using maven and cxf-codegen-plugin"

  :source-paths [] ;; NOTE: No Clojure code!
  :java-source-paths ["src"] ;; NOTE: Where the *generated* java will go!
  ;; NOTE: Adding source path to clean targets because it is generated code!
  :clean-targets ^{:protect false} [:target-path :compile-path 
:java-source-paths]

  :pom-addition [:properties [:project.build.sourceEncoding "UTF-8"]]

;; This is all Maven stuff, documented here: 
https://maven.apache.org/guides/mini/guide-configuring-plugins.html#Configuring_Build_Plugins
;; What you see below is serialized as XML in the generated pom.xml
  :pom-plugins
  [[org.apache.maven.plugins/maven-source-plugin "2.4"
    {:executions
     [:execution
      [:id "bundle-sources"]
      [:goals
       [:goal "jar-no-fork"]]]}]
   [org.apache.cxf/cxf-codegen-plugin "3.1.1"
    {:executions
     [:execution
      [:id "my-execution-id"]
      [:phase "generate-sources"]
      [:configuration
       [:sourceRoot "${project.basedir}/src"]
;; NOTE: Options documented here: http://cxf.apache.org/docs/wsdl-to-java.html
;; Some WSDLs may need more or fewer options than shown here.
       [:wsdlOptions
        [:wsdlOption
;; NOTE: Consider downloading the wsdl to a file.
         [:wsdl "https://example.org/mywsdl";]
         [:extraargs
          [:extraarg "-verbose"]
          [:extraarg "-mark-generated"]
          [:extraarg "-exsh"] [:extraarg "true"]
          [:extraarg "-autoNameResolution"]]]]]
      [:goals [:goal "wsdl2java"]]]}]])



Then with this project.clj in place, you build your java code like so:

#!/bin/sh

lein do clean, pom && mvn package

# This will define variables used below.
source target/maven-archiver/pom.properties

BUILT_JAR=target/${artifactId}-${version}.jar
SRC_JAR=target/${artifactId}-${version}-sources.jar

# You can then use the "full" form of lein deploy to create a maven-compatible 
release artifact
# Include this in your *real* clojure project as a dependency!
# TODO: I don't know how (or if it is possible) to get leinigen to deploy 
separate
# java/maven source or javadoc jars too.

lein deploy releases "${groupId}/${artifactId}" "${version}" "${BUILT_JAR}" 
pom.xml



Up until now we have done nothing that really involves Clojure. This could 
have been a plain Java maven project with a handcrafted pom.xml. The jar 
itself is just compiled java class files. I just used leinigen because it 
was more familiar.


In your actual Clojure project, require this java-soap-client project you 
deployed:

[my-soap-client "0.0.1-SNAPSHOT"]

Then use it via Java interop. Details may vary (see your WSDL or the SOAP 
service documentation), but usually there's a Service object you need to 
instantiate somehow, and then call getSoapXX on it to get a Port object 
which has methods on it corresponding to the SOAP methods the service 
provides.  I think both of these are stateless and long-lived and can be 
shared by threads.

(import '(my.soap.service ServiceClass))

(let [service (ServiceClass.)
      port    (.getSoap12 service)]

;; Sometimes the WSDL does not include the url of the soap service and you 
have to set it manually
(import '(javax.xml.ws BindingProvider))

  (.. ^BindingProvider port (getRequestContext) (put 
BindingProvider/ENDPOINT_ADDRESS_PROPERTY endpoint))


  ;; Now call your SOAP methods!
  (.mySoapMethod port)

)


Depending on the SOAP service and its WSDL, probably have a huge jumble of 
Java types to deal with in requests and responses, and you may even have 
raw XML to contend with, too. Your life will be much easier if you 
immediately convert instances from the Java client into plain Clojure data 
structures, and convert those data structures into the proper types right 
before you call the SOAP methods. clojure.data.java makes doing this much 
easier: you define a to-java and a from-java multimethod for the SOAP types 
you care about. It is also generic enough to handle many Java-bean like 
objects automatically. Example:

(require '[clojure.java.data :refer [to-java from-java]])


(defmethod from-java WeirdSoapType [^WeirdSoapType x]
;; Contrived example: default to-java implementation will turn Bean-like 
things into maps automatically via reflection.
   {:a (.getA x) :b (.getB x}})


;; You can make custom to-java also.




(from-java (.getWeirdType port))


(.sendBeanyThing port (to-java TypeSoapWants {:c 1 :d 2}))



I hope there is a better way to use SOAP from Clojure than all this, but 
it's hard to use SOAP services easily in *any* programming language!



On Wednesday, July 29, 2015 at 9:47:21 PM UTC-5, Mike wrote:
>
> Hello,
>
> I have decided what my first Clojure project will be, but I could use some 
> guidiance.  I would like to be able to make SOAP calls to a webservice on 
> another machine.
>
> I have done some searching, and there is an old clj-soap library which 
> Sean Corfield has mostly abandoned.  How are people doing this?  WOuld 
> someone be so kind as to post a small example?
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to