/thrift-clj

Thrift and Clojure!

Primary LanguageClojure

thrift-clj

Using Thrift from Clojure as if it was Clojure.

Build Status endorse

Usage

thrift-clj is available via Clojars.

Leiningen

[thrift-clj "0.2.0"]

Make sure to additionally include a slf4j-compatible logger - e.g. logback via:

[ch.qos.logback/logback-classic "1.0.13"]

Note: Tested with the Thrift 0.9.0 compiler. Since this depends massively on the generated code, make sure to use that version (or any other one that was tested with this library).

Automatic Thrift Compilation

I recommend lein-thriftc for automatic compilation of Thrift IDL files to Java class files.

Example

A working example demonstrating Service and Client implementation should always be available as thrift-clj-example. A small peek follows.

Accessing Types

Thrift

namespace java org.example

struct Person {
  1: optional string firstName,
  2: string lastName,
  3: byte age
}

Compile to Java using Thrift and add to Leiningen's classpath. (see :java-source-paths)

Clojure

(require '[thrift-clj.core :as thrift])
(thrift/import 
  (:types [org.example Person]))
  
(def clj-p (Person. "Some" "One" 99)) 
;; => #ns_1071852349.Person{:firstName "Some", :lastName "One", :age 99}

(def thr-p (thrift/->thrift clj-p))   
;; => #<Person Person(firstName:Some, lastName:One, age:99)>

(class clj-p) ;; => ns_1071852349.Person
(class thr-p) ;; => org.example.Person

Implementing a Service

Thrift

namespace java org.example

// ... 'Person' struct from above ...

service PersonIndex {
    bool storePerson(1:i32 id, 2:Person p),
    Person getPerson(1:i32 id)
}

Clojure

(require '[thrift-clj.core :as thrift])
(thrift/import 
  (:types [org.example Person])
  (:services org.example.PersonIndex))

(defonce person-db (atom {}))
(thrift/defservice person-index-service
  PersonIndex
  (storePerson [id p]
    (boolean
      (when-not (@person-db id)
        (info "Storing Person:" p)
        (swap! person-db assoc id p)
        true)))
  (getPerson [id]
    (info "Retrieving Person for ID:" id)
    (@person-db id))) 
    
(thrift/serve-and-block!
  (thrift/multi-threaded-server
    person-index-service 7007
    :bind "localhost"
    :protocol :compact))

Running a Client

(require '[thrift-clj.core :as thrift])
(thrift/import 
  (:types [org.example Person])
  (:clients org.example.PersonIndex))
  
(with-open [c (thrift/connect! PersonIndex ["localhost" 7007])]
  (PersonIndex/storePerson c 1 (Person. "Some" "One" 99))
  (PersonIndex/getPerson c 1))

Tests

You can run Midje tests using the following Leiningen command:

lein midje-all

Make sure that the Apache Thrift compiler is installed.

Roadmap

  • asynchronous client/server
  • union?
  • exceptions
  • tests & documentation
  • ...

Related Work/Inspiration

License

Copyright © 2013 Yannick Scherer and Contributors

Distributed under the Eclipse Public License, the same as Clojure.