Clojure CLR - Implement interface that contains properties - clojure

I'm trying to implement an interface that has properties but can't quite seem to get it to work and I also have not found any relevant examples via Google (yet). I'm sure I'm doing something completely wrong here but have no idea how to fix it.
(System.Reflection.Assembly/LoadWithPartialName "System.Web")
; naive, just trying to figure out how to implement the IHttpHandler interface in Clojure
(defn foo-handler []
(reify System.Web.IHttpHandler
(IsReusable [] false)
(ProcessRequest [context] ())))
IsReusable is a property and I don't know how to tell reify that it is not a traditional function.
CompilerException clojure.lang.CljCompiler.Ast.ParseException: Must supply at least one argument for 'this' in: IsReusable
Okay, I supply 'this' for IsReusable
CompilerException clojure.lang.CljCompiler.Ast.ParseException: Can't define method not in interfaces: IsReusable
I've also tried proxy but I get similar results.
I've also tried naming IsReusable to get_IsReusable which doesn't actually make a difference and I get the same compiler errors as above.
I've also tried deftype but I get a completely different error:
(deftype foo-handler []
System.Web.IHttpHandler
(get_IsReusable [this] false)
(ProcessRequest [this context] ()))
Compiler error:
InvalidCastException Unable to cast object of type 'clojure.lang.Var' to type 'System.Type'. clojure.lang.Namespace.ReferenceClass
Update:
The code posted for deftype works, I cannot reproduce the error that I posted above. I have no idea now what I was doing wrong at the time.

This took me a few hours of research and trial and error but I finally have success!
user=> (def foo-handler
(reify System.Web.IHttpHandler
(get_IsReusable [this] false)
(ProcessRequest [this context] ())))
#'user/foo-handler
user=>
Success!
user=> (instance? System.Web.IHttpHandler foo-handler)
true
This way is better and works fine from an ASP.NET application:
(deftype foo-handler []
System.Web.IHttpHandler
(get_IsReusable [this] false)
(ProcessRequest [this context]
(.Write (.Response context) "Hello, From Clojure CLR!")))

Related

Clojure om next multiple print-method exception

I am trying to build server-side rendering for om.next (1.0.0-alpha47). At some point I have to create a reconciler from Clojure:
(om/reconciler {})
(om/reconciler
{:state (atom {})
:normalize true
:parser (om/parser {})})
However evaluating any of these in my REPL gives:
Unhandled java.lang.IllegalArgumentException Multiple methods in
multimethod 'print-method' match dispatch value: class
om.next.Reconciler -> interface clojure.lang.IDeref and interface
clojure.lang.IRecord, and neither is preferred
How do I fix that?
I came to this solution via trial and error:
(prefer-method print-method clojure.lang.IPersistentMap clojure.lang.IDeref)
This seems to solve the conflict, sorry that I can't explain any details.

NullPointerException in Storm when running topology

I am getting NullPointerExceptions in backtype.storm.utils.DisruptorQueue.consumeBatchToCursor method when running my topology, specifically in a bolt. Spouts are duly executed.
Storm's troubleshooting page says that it might be due to multiple threads issuing methods on the OutputCollector. However, i cannot see where does it relate to my case.
Here's the code for the spout:
(defspout stub-spout ["stub-spout"]
[conf context collector]
(spout
(nextTuple []
(let [channel-value (<!! storm-async-channel)]
(emit-spout! collector [channel-value])))
(ack [id]
))))
and for the bolt:
(defbolt stub-bolt ["stub-bolt"] [tuple collector]
(println "Invocation!")
(let [obj (get tuple "object")
do-some-calculations (resolve 'calclib/do-some-calculations)
new-obj (do-some-calculations obj)]
(emit-bolt! collector new-obj)))
After some investigation it turned out that the call to resolve returns null (i need to resolve during runtime as some calculation occurs in a macro located in calclib).
The code runs properly in local cluster though. Why is this happening?
Will be grateful for any suggestions.
Thanks!
I think i've found a solution. The bolt definition is changed to a prepared bolt:
(defbolt stub-bolt ["stub-bolt"]
{:prepare true}
[conf context collector]
(let [f (load "/calclib/core")
do-some-calculations (resolve 'calclib/do-some-calculations)]
(bolt
(execute [tuple]
(let [obj (get tuple "object")
new-obj (do-some-calculations obj)]
(emit-bolt! collector new-obj))))))
Key is the call to load. I wonder if there's a more elegant approach though.

Clojure - test a Pedestal route

I would like to write tests for a Pedestal web-service.
If I have :
(defn pong
[request]
(ring-resp/response "pong"))
(defroutes routes[[["/" {:get pong}]]])
How would I write a test for that ?
(deftest alive-system
(testing "ping-pong route"
;; How do I test my route ?
;; If possible :
;; - I would like to have direct access to it
;; ie. no need to bind pedestal to a port would be nice
;; - The ability to omit some interceptors would be nice also,
;; as it would allow me to receive plain Clojure data structures
;; instead of, for instance, JSON which I would have to parse.
...)
Edit:
Here is what I tried :
(deftest alive-system
(testing "ping-pong route"
(let [response (my-other.ns/routes (mock/request :get "/ping"))]
(is (= (:status response) 200))
(is (= (:body response) "pong")))))
But I get an exception :
ERROR in (alive-system) (service_test.clj:13)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
So after asking on the issue I linked ohpaulez replied :
#nha - Thanks for using Pedestal! Sorry your question didn't get an
answer on StackOverflow - I don't think anyone monitors SO for
Pedestal questions. The best place to ask those kinds of questions is
on the mailing list.
Pedestal ships with its own utility for making requests directly to
the servlet (similar to ring/mock, although I've never used mock
myself) called response-for. The Pedestal Service template produces a
test automatically for you. Check out one of the samples for an
example.
Also note that said response-for doesn't yet support asynchronous responses (so my routes that uses asynchronous interceptors with core.async failed - I had to make them synchronous).

Why can't I call seq functions in a sequence generated by js->clj?

Although I can get turn a simple js object into a clojure object with something like;
(-> "{a: 2, b: 3}" js* js->clj)
I'm apparently not being able to do so with a particular object, goog.events.BrowserEvent, in a handler function like:
(defn handle-click [e]
...
(-> e .-evt js->clj keys) ;; <-------------
...
The function does get applied, but the resulting object doesn't respond to sequence functions like countor first, although I can fetch items using aget. The error message I get, in chrome's console, is;
Uncaught Error: No protocol
method ISeqable.-seq defined for type object: [object Object]
Why is this happening? Shouldn't js->clj work with all objects?
How can I fix this?
Thanks!
The js->clj only changes something that is exactly a JavaScript object (it is implemented using instance? instead of isa?, and with good reasons), when you pass a descendant of js\Object js->clj returns the same object. aget (and aset) works because it compiles down to the object[field-name] syntax on JavaScript.
You can extend the ISeq protocol (or any other protocol) to the goog.events.BrowserEvent and all functions that works with ISeq will work with goog.events.BrowserEvent. There is a talk by Chris Houser where he showed how to extend a bunch of protocols to a goog Map. I recommend watching the whole talk, but the part that are relevant to your question begins at approximately 14 minutes.
First, I found out functions in google closure to get the keys and values of an object:
(defn goog-hash-map [object]
(zipmap (goog.object/getKeys object) (goog.object/getValues object)))
Then, by studying the source of cljs.core, I realized all I had to do was to extend the IEncodeClojure interface with it:
(extend-protocol IEncodeClojure
goog.events.BrowserEvent
(-js->clj
([x {:keys [keywordize-keys] :as options}]
(let [keyfn (if keywordize-keys keyword str)]
(zipmap (map keyfn (gobj/getKeys x)) (gobj/getValues x))))
([x] (-js->cljs x {:keywordize-keys false}))))
The original code doesn't work on this object, because its type must be exactly Object. I tried to change the comparison function to instance?, ie,
(instance? x js/Object) (into {} (for [k (js-keys x)]
[(keyfn k) (thisfn (aget x k))]))
but that didn't work either, wielding the following error, which made me settle for the previous approach.
Uncaught TypeError: Expecting a function in instanceof check,
but got function Object() { [native code] }`.

Clojure: How do I factor proxy method code out of a long proxy statement?

I have a Clojure proxy statement that was getting large and messy, so I decided to try factoring the code of the beginDrag method redefinition out of the proxy statement, like this:
(defn enhanced-start-drag
""
[pie]
(let [pobj (. pie getPickedNode)
pobj-coll (seq (.. pie getInputManager
getKeyboardFocus getSelection))]
(println pobj)
(println pobj-coll)
(println "----------")
(proxy-super startDrag pie))) ; THIS IS LINE 94 (SEE ERROR MSG)
(defn custom-selection-event-handler [marqueeParent selectableParent]
(proxy [PSelectionEventHandler] [marqueeParent selectableParent]
(decorateSelectedNode [node]
(let [stroke-color (Color/red)]
(.setStrokePaint node stroke-color)))
(undecorateSelectedNode [node]
(let [stroke-color (Color/black)]
(.setStrokePaint node stroke-color)))
(startDrag [pie] ; pie is a PInputEvent
(enhanced-start-drag pie))
(endStandardSelection [pie] ; pie is a PInputEvent
(let [pobj (.getPickedNode pie)
slip (. pobj getAttribute "slip")
]
(swap! *last-slip-clicked*
(fn [x] slip))))))
I get the following compile error:
cd /Users/gw/tech/clojurestuff/cljprojects/infwb/src/infwb/
1 compiler notes:
Unknown location:
error: java.lang.Exception: Unable to resolve symbol: this in this context
core.clj:94:5:
error: java.lang.Exception: Unable to resolve symbol: this in this context
(core.clj:94)
Compilation failed.
As soon as I restore the body of enhanced-start-drag into the body of the proxy statement, everything works.
My question: Is there a way to move the messy details out to a separate function to improve the readability of my code?
Thanks for all your ideas and solutions.
UPDATE, 10/27/11: See the comments below. Arthur Ulfeldt was sharp in pointing out that the issue is captured references, and Dave Ray is also correct in saying that all you have to do is add this as a parameter to enhanced-start-drag and then proxy-super will work correctly. When I made the following two changes (without any changes to the body of enhanced-start-drag), my code was working again:
(defn enhanced-start-drag
""
[pie this]
and
(startDrag [pie] ; IN THE PROXY STMT IN custom-selection-event-handler
(enhanced-start-drag pie this))
BTW, my project uses Dave Ray's seesaw project to get a Java Swing UI. seesaw is awesome, as are its docstrings and sample code (which are much better than most commercial software). I highly recommend it! And thank you, Dave!
You have been bitten by symbol capture. In this case it is intentaional though you need to stay aware of it. From the doc for proxy-super
Use to call a superclass method in the body of a proxy method.
Note, expansion captures 'this`
proxy is creating a class that calls a function, when the call gets into enhanced-start-drag the value of this is not where proxy-super expects
you may needs to pass this as another argument into enhanced-start-drag and then call (. saved-this ...) instead of using proxy-super.