the .bqh[container] then .bqh[injects] those .bqh[dependencies] when it creates the bean.
]
.rcc[
.sdesign[
## design is based on .rcch[stateful components talking] to each other]
]
.oop-solid[
.jsf-ms[
Java + Spring......... [makes sense .check[✔]]
]]]]
---
class: inverse, middle, center
.cfa[
,
created timestamp,
PRIMARY KEY (nick));")
```
]
.es5[
```clojure
(alia/execute session (select :speakers
(where {:nick "tolitius"})
(columns :emails)))
```
]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > .current[data stores] > messaging > portability
.demo[
`<demo/>`
]
.demo-link[
### hazelcast: [github.com/tolitius/chazel](https://github.com/tolitius/chazel)
]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.intro[
.msg-meta[
# sending / receiving [events]()
.lleft[
.same-needs[
.ev-l[
### - message brokers
### - zeromq
### - message passing
### - etc.
]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.mheader[
.mh-t[
.msgb[
### brokers
| | |
|-------------:|:-------------|
| aws sqs | [github.com/aws/aws-sdk-java](https://github.com/aws/aws-sdk-java) |
| kafka | [github.com/ccann/gregor](https://github.com/ccann/gregor) |
| rabbitmq | [github.com/michaelklishin/langohr](https://github.com/michaelklishin/langohr) |
]
.ipc[
### brokerless
| | |
|-------------:|:-------------|
| zeromq | [github.com/zeromq/jeromq](https://github.com/zeromq/jeromq) |
]
.mpass[
### csp
| | |
|-------------:|:-------------|
| core.async | [github.com/clojure/core.async](https://github.com/clojure/core.async) |
]]
## ... .mhl[|] push, pull .mhl[|] publish, subscribe .mhl[|] produce, consume .mhl[|] put, take .mhl[|] ...
]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.aws1[
.csql[
.mass[
# AWS SQS (Java Interop)
.es5[
.cblock[
```clojure
(:import [com.amazonaws ClientConfiguration Protocol]
[com.amazonaws.auth BasicAWSCredentials]
[com.amazonaws.regions Region Regions]
[com.amazonaws.services.sqs AmazonSQSClient]
[com.amazonaws.services.sqs.model Message
DeleteMessageRequest
ReceiveMessageRequest
GetQueueAttributesRequest]))
```
.es5[
```clojure
(defn create-sqs-client [{:keys [access-key secret-key region]}
configs]
(let [creds (BasicAWSCredentials. access-key secret-key)]
(doto (AmazonSQSClient. creds configs)
(.setRegion (Region/getRegion (Regions/fromName region))))))
```
]]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.aws2[
.csql[
.mass[
# AWS SQS (Java Interop)
.es5[
```clojure
(defn receive-messages [{:keys [sqs-client
queue-url
max-msg
visibility-timeout-sec]
:or {visibility-timeout-sec 15
max-msg 10}}]
(let [msg-req (doto (ReceiveMessageRequest. queue-url)
(.setMaxNumberOfMessages max-msg)
(.setVisibilityTimeout visibility-timeout-sec))]
(mapv message-to-map (.. sqs-client (receiveMessage msg-req)
(getMessages)))))
```
]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.kafka1[
.csql[
.mass[
# Kafka
.es5[
.cblock[
```clojure
(defstate consumer :start (gregor/consumer "localhost:9092"
"testgroup"
["test-topic"]
{"auto.offset.reset" "earliest"
"enable.auto.commit" "false"})
:stop (gregor/close consumer))
(defstate producer :start (gregor/producer "localhost:9092")
:stop (gregor/close producer))
```
.es5[
```clojure
(let [consumer-records (gregor/poll consumer)
values (process-records consumer-records)]
(doseq [v values]
(gregor/send producer "other-topic" v))
(gregor/commit-offsets! consumer)))
```
]]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.zero1[
.csql[
.mass[
# zeromq (Java Interop)
.es5[
.cblock[
```clojure
(:import [org.zeromq ZMQ ZMQ$Context ZMQ$Socket ZMQQueue])
(defonce single-context (ZMQ/context 1))
(defn bind [socket url]
(doto socket
(.bind url)))
(defn socket [context type]
(.socket context type))
```
.es5[
```clojure
(defn zsocket [queue]
(let [sock (-> mq/single-context
(mq/socket mq/pub)
(mq/bind queue))]
(log/info "producer is bound to [" queue "], let's rock'n'roll")
sock))
```
]]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.zero2[
.csql[
.mass[
# zeromq (Java Interop)
.es5[
.cblock[
.es5[
```clojure
(defn subscribe
([socket topic]
(doto socket
(.subscribe (.getBytes topic))))
([socket]
(subscribe socket "")))
```
]
.es5[
```clojure
(defn send-bytes [^ZMQ$Socket socket ^bytes message]
(.send socket message 0))
(defn recv-bytes [socket]
(.recv socket 0))
```
]
]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > .current[messaging] > portability]
.coreas[
.csql[
.mass[
# Communicating Sequential Processes
.es5[
.cblock[
.es5[
```clojure
(defn GET [url]
(let [ch (chan)]
(xhr/send url
(fn [event]
(let [res (-> event .-target .getResponseText)]
(go (>! ch res))))
"GET")
ch))
```
]
.es5[
```clojure
(defn race [q]
(let [t (timeout timeout-ms)
start (now)]
(go
(alt!
(GET (str "/yahoo?q=" q)) ([v] (winner :.yahoo v (took start)))
(GET (str "/bing?q=" q)) ([v] (winner :.bing v (took start)))
(GET (str "/google?q=" q)) ([v] (winner :.google v (took start)))
t ([v] (show-timeout timeout-ms))))))
```
]
]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.intro[
.msg-meta[
# communication [across languages]()
.port-t[
### Clojure .chl[<=>] Java .chl[<=>] Go .chl[<=>] Rust .chl[<=>] C.chl[<=>] Fortran
]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.mheader[
.ph-t[
.portb[
### binary
| | |
|-------------:|:-------------|
| avro | [github.com/damballa/abracad](https://github.com/damballa/abracad)
| protocol buffers | [github.com/clojusc/protobuf](https://github.com/clojusc/protobuf)
| nippy | [github.com/ptaoussanis/nippy](https://github.com/ptaoussanis/nippy)
| kryo | [github.com/sritchie/carbonite](https://github.com/sritchie/carbonite)
| message pack | [github.com/edma2/clojure-msgpack](https://github.com/edma2/clojure-msgpack)
| transit | [github.com/cognitect/transit-clj](https://github.com/cognitect/transit-clj)
]
.porth[
### human readable
| | |
|-------------:|:-------------|
| json | [github.com/dakrone/cheshire](https://github.com/dakrone/cheshire)
| xml | [github.com/clojure/data.xml](https://github.com/clojure/data.xml)
| yaml | [github.com/owainlewis/yaml](https://github.com/owainlewis/yaml)
]
]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.mheader[
.ph-t[
.port-fade[
.portb[
### binary
| | |
|-------------:|:-------------|
| avro | [github.com/damballa/abracad](https://github.com/damballa/abracad)
| protocol buffers | [github.com/clojusc/protobuf](https://github.com/clojusc/protobuf)
| .pwhite[nippy] | [github.com/ptaoussanis/nippy](https://github.com/ptaoussanis/nippy)
| kryo | [github.com/sritchie/carbonite](https://github.com/sritchie/carbonite)
| message pack | [github.com/edma2/clojure-msgpack](https://github.com/edma2/clojure-msgpack)
| .pwhite[transit] | [github.com/cognitect/transit-clj](https://github.com/cognitect/transit-clj)
]
.porth[
### human readable
| | |
|-------------:|:-------------|
| json | [github.com/dakrone/cheshire](https://github.com/dakrone/cheshire)
| xml | [github.com/clojure/data.xml](https://github.com/clojure/data.xml)
| yaml | [github.com/owainlewis/yaml](https://github.com/owainlewis/yaml)
]
]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.jtport[
.portas[
.csql[
.mass[
# protobuf [| Clojure]()
github.com/clojusc/protobuf
.es5[
.cblock[
.es5[
```proto
package your.namespace.person;
option java_outer_classname = "Example";
message Person {
required int32 id = 1;
required string name = 2;
optional string email = 3;
repeated string likes = 4;
}
```
]
.es5[
```clojure
(require '[protobuf.core :as protobuf])
(import (your.namespace.person Example$Person)
(def alice (protobuf/create Example$Person
{:id 108
:name "Alice"
:email "alice@example.com"}))
```
]
]]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.prport[
.portas[
.csql[
.mass[
# protobuf [| Clojure]()
github.com/clojusc/protobuf
.es5[
.cblock[
.es5[
```clojure
;; to bytes
(def a-bytes (-> alice
(assoc :name "Alice B. Carol")
(assoc :likes ["climbing" "running" "jumping"])
(protobuf/->bytes)))
```
]
.es5[
```clojure
;; and back
(protobuf/bytes-> alice a-bytes)
```
]
.es5[
```clojure
{:id 108,
:name "Alice B. Carol",
:email "alice@example.com",
:likes ["climbing" "running" "jumping"]}
```
]
]]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.portas[
.csql[
.mass[
# transit [| Clojure]()
.es5[
.cblock[
.es5[
```clojure
(defn transit-out [data format opts]
(let [baos (ByteArrayOutputStream.)
w (transit/writer baos format opts)
_ (transit/write w data)
ret (.toByteArray baos)]
(.reset baos)
ret))
```
]
.es5[
```clojure
(defn transit-in [data format opts]
(if (bytes? data)
(let [bais (ByteArrayInputStream. data)
r (transit/reader bais format opts)]
(transit/read r))
(log/error "can't deserialize ...")))
```
]
]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.jport[
.portas[
.csql[
.mass[
# transit [| Java]()
.es5[
.cblock[
.es5[
```java
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import com.cognitect.transit.TransitFactory;
import com.cognitect.transit.Reader;
import com.cognitect.transit.Writer;
```
]
.es5[
```java
// Write the data to a stream
OutputStream out = new ByteArrayOutputStream();
Writer writer = TransitFactory.writer(TransitFactory.Format.MSGPACK, out);
writer.write(data);
```
]
.es5[
```java
// Read the data from a stream
InputStream in = new ByteArrayInputStream(out.toByteArray());
Reader reader = TransitFactory.reader(TransitFactory.Format.MSGPACK, in);
Object data = reader.read();
```
]
]]]]]]
---
class: inverse, middle, center, clojure-dark
.fff[
## state > configuration > aop > data stores > messaging > .current[portability]]
.jtport[
.portas[
.csql[
.mass[
# transit [| Java]()
github.com/danboykis/trava
.es5[
.cblock[
.es5[
```clojure
{:a {:b {:c 10}}}
```
]
.es5[
```java
List path = Arrays.asList(new KeywordImpl("a"),
new KeywordImpl("b"),
new KeywordImpl("c"));
Assert.assertEquals(10, Navigator.getIn(nestedMap, path));
```
]
.es5[
```java
// transform this map to {:a {:b {:c 10 :d 1}}}
List newPath = Arrays.asList(new KeywordImpl("a"),
new KeywordImpl("b"),
new KeywordImpl("d"));
Map nestedMap = Navigator.assocIn(nestedMap, newPath, 1);
Assert.assertEquals(1, Navigator.getIn(nestedMap, newPath));
```
]
]]]]]]
---
class: inverse, middle, center
# Clojure [+]() Java
## simple [&]() powerful
---
name: inverse
class: first-slide, center, middle, inverse
#Thank you,
##[@tolitius](https://twitter.com/tolitius)