Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Alfresco the clojure way -- Slides from the Alfresco DevCon2011
1. Alfresco
The Clojure way Carlo Sciolla, Sr R&D Developer at Backbase
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
2. I would like, if I may, to take you on a strange journey.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
3. public void printAllNames(repo) {
AuthenticationUtil.runAs(new RunAsWork () {
public Object doWork(){
for (NodeRef node : getAllNodes(repo)) {
String name = getName(node);
System.out.println(name);
}
}
}, AuthenticationUtil.getAdminUserNAme())
}
Sample user story
As admin,
I want to loop through all the nodes from the Alfresco repository,
So that I can print their names
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
4. (defn print-all-names [repo]
(run-as (admin)
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
#LOC < 1/2
Sample user story
As admin,
I want to loop through all the nodes from the Alfresco repository,
So that I can print their names
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
5. (defn print-all-names [repo] Java interop
(AuthenticationUtil/runAs
(reify AuthenticationUtil$RunAsWork
(doWork [this]
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
(admin)))
How to get there
Having only moved parenthesis around and tweaked it a bit, we
eventually translated our code into Clojure. We still have to get rid of
the anonymous class.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
6. (defmacro run-as
[user f]
`(let [work# (reify AuthenticationUtil$RunAsWork
(~'doWork [~'this]
~f))]
(AuthenticationUtil/runAs work# ~user)))
Reflection on massive steroids
Macros are “special” functions that, at compile time, shuffle the
pieces they receive in input and return a function. They’re misterious
and powerful: don’t try to decode it now, young jedi.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
7. (defn print-all-names [repo]
(run-as (admin)
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
Straight to the point
Clojure, as any Lisp, allows you to easily create clear and concise
DSLs. New functions to enhance expressivity to your programs.
Fewer lines to maintain.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
8. (defn print-all-names [repo]
(run-as (admin)
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
https://github.com/skuro/lambdalf
Here be Lambdalf
While Clojure allows direct access to Java classes and instances,
lambdalf provides a more idiomatic access to the core Alfresco API.
You’ll see some examples along the way.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
9. (defn print-all-names [repo]
(run-as (admin)
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
Lost In Superfluous Parenthesis?
It is usually perceived that Lisp code has an overwhelming amount of
parenthesis.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
10. Parenthesis count
VS
26
18 24 w/expanded macro
Lost In Superfluous Parenthesis?
It is usually perceived that Lisp code has an overwhelming amount of
parenthesis. Itʼs usually unfair.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
11. the sexp and the city
or: How I learned to stop worrying and love the parens
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
12. sexp = | primitive-elem
| list of s-expression
Symbolic Expressions
List based data structures. They may be a nested list of smaller S-
expressions. Best known for their use in Lisp.
(Wikipedia)
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
13. Symbols: ns/foo Keywords: :key
odd? ::qualified
+ :ns/qualified
this!is_a+single*symbol-42 :can+be!weird
Literals: “string”
c space tab
42 3.14 42/11 36r16
true false
#”^[a-zA-Z]*”
nil
Primitive data types
Basic building blocks. Most of them should look familiar, or meaningful.
Hopefully.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
14. list (c “list” :something)
vector [“vector” 42 :foobar]
map {:question “life, universe and everything”
:answer 42}
set #{“foo” 42 :bar}
Collections or sequences
All aggregate data types can be encapsulated under the same
interface: ISeq. Use the powerful Clojure sequence processing library
to rule them all, but beware: they are all immutable!
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
15. list (quote (c “list” :something))
list ‘(c “list” :something)
(defn print-all-names [repo]
(run-as (admin)
function calls
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
LISt Processing
Lists are king among data structures in any Lisp: they also happen to
be code (homoiconicity). Lists are executed by evaluating the first
symbol to a function, then calling it with the others as parameters.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
16. immutability
and the art of motorcycle maintenance
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
17. Horse horse = new Horse(14);
horse.getPosition();
??
t
Where is the horse?
The same “thing” such as a variable or an Object, can be completely
different at different moments in time. We call such things identities,
and they relate to a sequence of values.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
18. (defn move [h]
{:pos (inc (:pos h))})
(def horse
{:pos 14})
(:pos horse) ; 14
(move horse) ; {:pos 15}
Persistent data structures
All data structures are immutable after their creation. As such, you
never change them, but rather create new versions of it. We call them
values, and are effectively easier to handle than Objects.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
19. Structural sharing
When creating a new version of a value, Clojure runtime optimizes the
process and allows different version of the same data structure to
share parts in memory.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
20. concurrency
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
21. private HashMap _map = new HashMap();
public void oneMore(Object k, Object v) {
#fail _map.put(k, v);
}
Shared mutable state
It’s sometimes desirable to access the same identity from different
threads. When going concurrent, several tasks that used to be trivial
are now extremely hard. OO makes it even harder.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
22. Software Transactional Memory
Similarly to databases, Clojure runtime uses transactions to handle
concurrent access to shared mutable state. Every thread gets the
current value, if changes occur outside, the transaction rolls back.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
23. (def _shared (ref {}))
(defn update
[old k v]
(assoc old k v))
(defn one-more
[k v]
(dosync
(alter _shared update k v)))
Concurrency IS rocket science
Sorting out concurrency is an extremely difficult task. Clojure provides
language level barriers against poorly designed concurrent access to
shared mutable state.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
24. sync coord
clojure.core/ref
([x] [x & options])
clojure.core/atom
([x] [x & options])
clojure.core/agent
([state & options])
Thereʼs no silver bullet
Different concurrent access patterns require different constructs.
Programmers still have to pay attention to which kind of concurrency
control to use.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
25. the seq library
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
26. clojure.core/seq
([coll])
Returns a seq on the collection.
If the collection is empty, returns nil.
(seq nil) returns nil. seq also works on
Strings, native Java arrays (of reference
types) and any objects that implement
Iterable.
seq to rule them all
Quite intentionally, you can reduce all Clojure data structures and
Java collections, iterables, Strings and arrays to the very same
interface.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
27. distinct filter remove for keep keep-indexed cons concat
lazy-cat mapcat cycle interleave interpose
rest next fnext nnext drop drop-while nthnext for take
take-nth take-while butlast drop-last for
flatten reverse sort sort-by shuffle split-at split-with
partition partition-all partition-by
map pmap mapcat for replace reductions map-indexed seque
first ffirst nfirst second nth when-first
last rand-nth zipmap into reduce set vec into-array to-
array-2d frequencies group-by apply
not-empty some reduce seq? every? not-every? not-any?
empty? some filter doseq dorun doall seq vals
keys rseq subseq rsubseq lazy-seq repeatedly iterate
repeat replicate range line-seq resultset-seq
re-seq tree-seq file-seq xml-seq iterator-seq
enumeration-seq
One-stop shop
Dealing with a single abstraction allows for the same functions to be
applicable to an incredible number of problems. The richness of the
seq library is the only swiss army knife you need.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
28. fully functional
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
29. (defn print-all-names [repo]
(run-as (admin)
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
Sequencing Alfresco
Nodes in Alfresco are stored as a tree. Surely enough, trees can be
represented as nested sequences, allowing for the seq library to
disclose its power.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
30. distinct filter remove for keep keep-indexed cons concat
lazy-cat mapcat cycle interleave interpose
rest next fnext nnext drop drop-while nthnext for take
take-nth take-while butlast drop-last for
flatten reverse sort sort-by shuffle split-at split-with
partition partition-all partition-by
map pmap mapcat for replace reductions map-indexed seque
first ffirst nfirst second nth when-first
last rand-nth zipmap into reduce set vec into-array to-
array-2d frequencies group-by apply
not-empty some reduce seq? every? not-every? not-any?
empty? some filter doseq dorun doall seq vals
keys rseq subseq rsubseq lazy-seq repeatedly iterate
repeat replicate range line-seq resultset-seq
re-seq tree-seq file-seq xml-seq iterator-seq
enumeration-seq
Depth first traversal
Using the standard seq library, you can compose a linear sequence
out of a tree structure (of nested sequences).
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
31. clojure.core/tree-seq
([branch? children root])
Returns a lazy sequence of the nodes in a
tree, via a depth-first walk. branch? must be
a fn of one arg that returns true if passed a
node that can have children (but may not).
children must be a fn of one arg that returns
a sequence of the children. Will only be
called on nodes for which branch? returns
true. root is the root node of the
tree.
Anatomy of a tree-seq
Functions are first class, and tree-seq is a higher order fn that takes
two functions and a data structure to create a flat sequence.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
32. clojure.core/tree-seq
([branch? children root])
Returns a lazy sequence of the nodes in a
tree, via a depth-first walk. branch? must be
a fn of one arg that returns true if passed a
node that can have children (but may not).
children must be a fn of one arg that returns
a sequence of the children. Will only be
called on nodes for which branch? returns
true. root is the root node of the
tree.
Thinking Alfresco
Peer to peer associations allow you to create logical trees regardless
of files and folders structure. For the time being, let’s assume we’re
only interested into parent child assocs between nodes.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
33. (defn type-qname [node]
(m/qname (.getType (node-service) (c/c2j node))))
(defn branch? [node]
(qname-isa? (type-qname node)
(qname "cm:folder")))
(defn qname-isa? [child parent]
(.isSubClass (dictionary-service)
(qname child) (defn qname [qname-str]
(qname parent))) (let [[prefix name] (QName/splitPrefixedQName qname-str)]
(QName/createQName prefix name (namespace-service))))
First step
We know that cm:contains is provided as part of cm:folder
definition. We check that the given node is of a compatible type.
Lambdalf provides here some Clojure/Java type conversion.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
34. clojure.core/tree-seq
([branch? children root])
Returns a lazy sequence of the nodes in a
tree, via a depth-first walk. branch? must be
a fn of one arg that returns true if passed a
node that can have children (but may not).
children must be a fn of one arg that returns
a sequence of the children. Will only be
called on nodes for which branch? returns
true. root is the root node of the
tree.
Populate the seq
Navigating the tree means getting the children of the traversed node,
if any. This is food for the NodeService.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
35. (defn children [node]
(n/children node)))
(defn children [node]
(into #{}
(doall
(map #(c/j2c (.getChildRef %))
(.getChildAssocs (node-service)
(c/c2j node))))))
API bridge
Lambdalf tries to shave the yak for you, and despite its code doesn’t
shine by beauty, it allows for a clean user code. Again, Java and
Clojure interact seamlessly here.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
36. (defn print-all-names [repo] (defn to-seq [node]
(run-as (admin) (tree-seq branch? children node))
(doseq [node (to-seq repo)]
(println (property node “cm:name”)))))
Wrapping it up
Most of the mystery is now gone, the core of print-all-names has been
demystified. While run-as is still magic, it’s easy to tell what’s for.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
37. the lord of the repl
one repl to bring them all and in the lexical scope, bind them
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
38. read R prompt
user> (defn Y [r]
eval E ((fn [f] (f f))
(fn [f]
(r (fn [x] ((f f) x))))))
print P #'user/Y
user> result
loop L
Live coding
Similarly to scripted languages, your code is parsed and compiled
into bytecode as soon as you enter it. In facts, you are altering the
current runtime state.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
39. +
$ curl -X POST -u admin:admin
http://localhost:8080/alfresco/service/swank
{port : 4005}
Swank server
Opening a REPL server is just one web script call away. You’ll need a
client to connect, major IDE and editors have one. As usual, Emacs is
superior :-P
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
40. the clojure way
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
41. (map #(property % name) (query “@cm:name:”Sites””))
(defn query
"Returns all the results of a search"
([q]
(query StoreRef/STORE_REF_WORKSPACE_SPACESSTORE
SearchService/LANGUAGE_LUCENE q))
([store lang q]
(with-open [rs (.query (search-service) store lang q)]
(doall (map c/j2c (.getNodeRefs rs))))))
Warning: alpha code
Lambdalf and Clojure webscripts have a long way ahead in terms of
API maturity and usability, but the basic pieces are out there for you to
start your journey into this new, fancy Lisp.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
42. (write! “new content” node)
(write!
[^String src node]
(let [noderef (c/c2j node)
w (.getWriter (content-service)
noderef
ContentModel/PROP_CONTENT true)]
(.putContent w (ByteArrayInputStream.
(.getBytes src "UTF-8")))))
Warning: alpha code
Lambdalf and Clojure webscripts have a long way ahead in terms of
API maturity and usability, but the basic pieces are out there for you to
start your journey into this new, fancy Lisp.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
43. (to-seq (company-home))
(defn to-seq
[root]
(let [user (a/whoami)
branch? (fn [x] (a/run-as user
(m/qname-isa? (n/type-qname x)
(m/qname "cm:folder"))))
children (fn [x] (a/run-as user (n/children x)))]
(tree-seq branch? children root)))
Warning: alpha code
Lambdalf and Clojure webscripts have a long way ahead in terms of
API maturity and usability, but the basic pieces are out there for you to
start your journey into this new, fancy Lisp called Clojure.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
44. John
McCarthy
4 September 1927 - 24 October 2011
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
45. Q/A
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011
46. Carlo Sciolla
sr. R&D Developer
http://skuro.tk
@skuro
http://backbase.com
Thank you! “A language that doesn't affect the way you think about programming, is not worth knowing”
Alan J. Perlis
About me
Content specialist, Clojurian, biker.
ALFRESCO THE CLOJURE WAY | November 8, 2011 | @skuro
Thursday, November 10, 2011