I'm writing a web app using Noir and clojure, which uses Jetty. Jetty has two ways of using gzip, one for static, and one for dynamic, they are described in https://stackoverflow.com/a/9113129/104021. I want to turn on both static and dynamic gzipping, but our project doesn't use web.xml files, and doesn't want to start.
How do I programmatically set jetty to use gzip (ie without having a web.xml)?
In a Compojure app I'm working on, I have a Ring/Jetty adapter based on ring-jetty-adapter which programmatically configures Jetty to use a GzipHandler to gzip content dynamically.
(defn- configurator [server ring-handler]
(.setHandler server
(doto (new HandlerCollection)
(.addHandler (doto (new GzipHandler)
(.setHandler (proxy-handler ring-handler))
(.setMimeTypes "text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,text/javascript,image/svg+xml")))
(.addHandler (doto (new RequestLogHandler) (.setRequestLog (NCSARequestLog.)))))))
This function takes a Server instance and my Ring handler and sets it up with some handlers. Note that the GzipHandler is a HandlerWrapper, so it takes my (proxied) Ring handler and delegates to it. I also add a logging handler which will be executed after the (gzip-wrapped) Ring handler.
Check out the complete working version.
See the startServer method in here:
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java
jetty uses itself extensively for testing so most embedded scenarios people need already exist in the unit tests somewhere, course finding them can be a bit of an issue :)
Related
I'd like to use figwheel to reload the frontend of an all-clojure project I'm playing with.
The backend serves a REST api and is organized as a bunch of components from which I create a system in my main function (I use duct to create the handler component). I want to pass state to my handlers using closures, but the only means of configuring figwheel to use my handler seems to be setting the ring-handler key in project.clj, and this requires that I pass a handler that is defined in a namespace at lein startup time.
So - is there a way to configure figwheel when I am doing my component startup? I'm still very new at Closure so it's likely I'm missing something in plain sight.
Passing state as parameter to a ring handler? is a similar question, but the answer there involves binding the handler a var at the top-level of a namespace, which I'm trying to avoid.
Figwheel doesn't need to be a handler. You can wrap a component that autobuilds while your server is up and running by dissecting this code into a component, a dependency to your server component so that it starts first. Note that this isn't officially supported. Running lein figwheel from the shell to boot a seperate JVM is the conventional usage.
If you are using Stuarts component lib I'd recommend to wrapping the ring handler from within a server component rather than via project.clj. Use this project or adapt the code snippet for a jetty component.
Notice that figwheel is devtooling, so in production you most likely want to serve a compiled js file built with e. g. lein-cljsbuild.
James Reeves made a component for figwheel here
Duct-Figwheel-Component
A component for the Figwheel development tool, designed to be used in the Duct framework (but can be used in any component-based system).
Installation
Add the following dependency to your project.clj:
[duct/figwheel-component "0.3.3"]
My Clojure app needs to log through Java.Util.Logging (JUL) because custom log rotation is no supported at the moment with Elastic Beanstalk. I'm using clojure.tools.logging to write the log files, but the library keeps auto-selecting log4j as the logging engine.
How can I force clojure.tools.logging to use JUL?
I found a thread online that has a solution using alter-var-root to permanently bind the selected factory to logger-factory:
(alter-var-root (var log/*logger-factory*) (constantly (impl/jul-factory)))
...but it's an older thread and didn't know if there was a better way.
I use this one every day:
(alter-var-root
#'clojure.tools.logging/*logger-factory*
(constantly (clojure.tools.logging.slf4j/load-factory))
switching slf4j for impl/jul-factory should be reliable and at least mostly sane.
Assume I have a Clojurescript namespace called main with a atom within it called state.
(ns main)
(atom state nil)
I compile my Clojurescript app, run it on a server, fire up the Clojurescript repl and then connect to my server using a browser. Everything works dandy.
In the Clojurescript repl, I can comfirm the usual
> (+ 1 1)
2
> (js/alert "Hey there") //shows an alert dialog with "Hey there" in the browser
nil
> main.state
(atom nil)
The Clojurescript repl is great for development. So, clearly I can get and (using swap! or reset!) set the value of a Clojurescript atom from a Clojure application. I was wondering if there was a way to have a connection between the value of an atom in my Clojurescript project and a running Clojure application. Perhaps the Clojurescript client connects to a specified port and sends the result to some Clojure server waiting on that port. Simply stated, I was wondering if it might be possible to have a running server application share the value of the state client atom.
Why, you might ask? Well, I was thinking it would be nice to write the value of the state atom to a actual file (state.clj) whenever state is modified in the running Clojurescript application. This way, I could always have a view of the current value of state. I could use something like emacs (global-auto-revert-mode t) to make sure that state.clj buffer was always fairly recent. This is a little like having a debugger.
Beyond that, my real desire is to then make it so that the running Clojure application would also periodically poll state.clj itself. When the server detects that I modified state.clj, it would accept the modification as the new value of the Clojurescript state atom. It would then do something like what the Clojurescript repl does, illustrated in the following pseudo code:
(send-to-client-for-evaluation
(compile-into-js
(reset!
main.state
the-read-string-value-of-the-content-of-state.clj)))
Basically, I want the ability for the server to have something akin to a shared atom between the client and the server. I want the value of state to be bidirectionally shared between the client and the server. Is any of this possible, or am I just dreaming?
Sure, just make requests to a rest API sending data in EDN format, and voila! If you want to avoid polling, consider running your Jetty or Tomcat behind an Nginx instance to make use of the Nginx HTTP Push Module. I have a somewhat cobwebby example here (this was pre-ClojureScript, so I wrote the client in plain JS). And there is also gifsockets.
I used to be able to start a web server in compojure like this:
(run-server {:port 8080} "/*" (servlet my-app))
Does anyone know where this function has gone in the latest compojure? (0.6.2)
The docs say I'm supposed to run it from the command line and use some freaky auto-reloading thing, at which point I might as well be using python.
You're looking at some seriously out-dated documentation.
For jetty, use
(use 'ring.adapter.jetty)
(defn start-web []
(run-jetty (var my-site) {:port 8080 :join? false}))
Where my-site is your top-level handler function.
You can call that function anywhere, including from the REPL in SLIME. Recompiling/redefining my-site will work on a running server, so there's no need for auto-reloading if you're already using an interactive environment.
EDIT: compojure has been split into ring & clout, with compojure itself remaining as a small selection of higher-level abstractions on top. Most of the actual server stuff and design documentation is now in ring. See https://github.com/mmcgrana/ring/wiki
I am trying to use clojure to implement a "plugin" for some vendor
supplied software.
Here is a little background on the vendor supplied software. It
expects me to implement a particular interface and then put the jar
file containing that implementation into a directory on its server.
Then when a client runs the software, my implemented class gets "sent"
to the client from the server via RMI and then my implementation of
the interface runs on the client. The client doesn't have my jar file
(or the clojure jar file) in it's classpath. Only the server has
those jar files. RMI seems to be smart enough to upload whatever
dependencies are necessary.
I have successfully built a very simple implementation in clojure and
it seems to work. The problem is, I would like to be able to update my
implementation on the client on the fly. I embedded a repl-server in
my class and I can successfully connect to it. Just to be clear, the
repl-server is running on the client and I am able to connect to the
repl getting a prompt "clojure.core=>". However, the repl seems to be
quite crippled. If I enter (+ 1 1) I get the following error:
"java.lang.ClassNotFoundException: clojure.lang.Numbers". If enter
(str "kent") I get "java.lang.NoClassDefFoundError: clojure/lang/
AFunction". Most things I enter produce something similar. I can
however do a simple def such as (def x 3) and x does get defined so
the REPL does seem to be running in some sense.
It seems like it might be a classpath problem, but I'm not sure why my
"compiled" code, running on the client would not have a classpath
problem while the repl, running on the same client cant find core
classes.
Any ideas?
Thanks.
Kent.
First of all, would it be possible to distribute clojure.jar as part of your RMI client? Based on your description of the vendor software, I'm guessing the answer is no.
Second, is the contents of clojure.jar and your RMI object in the same jar file on the server, or are both in their own jar files?
It seems very likely that it's a classloader issue. In Clojure each defined function generates its own class file that Clojure then load via a specific class loader. IIRC each function is loaded by its own classloader instance in order to allow that function to be garbage collected in case it is redefined. Similarly, I think, RMI uses its own class loader to load remote RMI objects over the network. So possibly the two class loaders interact badly.
Sorry I can't be of more help...
-- Lauri