We have 2 apps sitting on our server. One is a Java app that pulls out important blocks of information from sentences written in normal English. It should only talk to other apps on our server (though we have not yet put up a firewall to protect it). It should not talk to the public (though at the moment that is possible). It has some very simple Java code that opens up a Socket on port 8080 and then listens. It expects to receive a string that it can convert to JSON. It sends back a string that can be converted to JSON. It does not send back any HTTP headers, it is just the simplest Socket code you can imagine, not even 30 full lines of code.
We have another app, written in Clojure, that speaks to the wide world, via a RESTful API.
The basic idea is that requests come to our server from the outside world, and interact with the Clojure app. The Clojure app is suppose to interact with the Java app, and then the Clojure app sends back a response to whoever queried it.
I've had trouble figuring out how to call the Java app from the Clojure app. I tried to use a library such as clj-http, but it relies on the Apache HttpClient, which makes the assumption that the response will contain correct HTTP headers. Apache HttpClient threw exceptions when interacting with the Java app, since the Java app only sends back a string (no HTTP headers). I don't want to write full HTTP code in the Java app, as that gets redundant with the work we did in the Clojure app.
So, I switched tactics, and wrote some raw Socket code from the Clojure side. That code looks like:
(def conn (ref {:in nil :out nil}))
(defn connect []
(let [socket (Socket. "localhost" 8080)
in (BufferedReader. (InputStreamReader. (.getInputStream socket)))
out (PrintWriter. (.getOutputStream socket))]
(dosync
(alter conn
(fn [old-value] (assoc old-value :in in)))
(alter conn
(fn [old-value] (assoc old-value :out out))))))
The write function was basic:
(defn write-message [msg]
(doto (:out @conn)
(.println (str msg "\r"))
(.flush)))
This worked once, but most of the time when I try it (from the browser, which uses Javascript to ping the API, which then calls the Java app) I get:
Connection reset stack trace:
{:class java.net.SocketException,
:message "Connection reset",
:trace-elems ({:method "read",
:class "java.net.SocketInputStream",
As I do this, I have several terminal windows open. The terminal for the Java app shows no activity at all, whereas the Clojure app shows the above error.
If I use this curl (which hits the Java app directly), then everything works:
curl --verbose "http://localhost:8080" -d ' { "transaction-id" : "99393920", "report" : "Allie Hanther of IBM responded to our proposal and said her company is ready to move forward. The deal is worth $400,000 annually. I will meet with her tomorrow and we will sign the contract." } ' -X POST --header "Content-Type:application/json"
I realize that stuff like "POST" and "content type" are meaningless in this context, since we are not talking to an HTTP server. Still, they don't seem to do any harm. This curl request gets back the correct response.
But the Clojure app only gets an error.
I could believe that the 2 apps are having a conflict over port 8080, but I don't understand the nature of that conflict.
Any suggestions?
In the future, we are thinking we will give up on the Socket and instead use either Redis or a jobs queue for communication, but for now we are using the Socket, and I'd like to get it working.
For now I only need the Clojure app to work like curl.