How to use figwheel with a ring-handler that's a component? - clojure

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"]

Related

mocking a class used by a Gradle plugin when testing

I'm writing a Gradle plugin that interacts with an external HTTP API. This interaction is handled by a single class (let's call it ApiClient). I'm writing some high-level tests that use Gradle TestKit to simulate an entire build that uses the plugin, but I obviously don't want them to actually hit the API. Instead, I'd like to mock ApiClient and check that its methods have been called with the appropriate arguments, but I'm not sure how to actually inject the mocked version into the plugin. The plugin is instantiated somewhere deep within Gradle, and gets applied to the project being executed using its void apply(Project project) method, so there doesn't appear to be a way to inject a MockApiClient object.
Perhaps one way is to manually instantiate a Project, apply() the plugin to it (at which point, I can inject the mocked object because I have control over plugin instantiation), and then programmatically execute a task on the project, but how can I do that? I've read the Gradle API documentation and haven't seen an obvious way.
A worst-case solution will be to pass in a debug flag through the plugin extension configuration, which the plugin will then use to determine whether it should use the real ApiClient or a mock (which would print some easily grep-able messages to the STDOUT). This isn't ideal, though, since it's more fuzzy than checking the arguments actually passed to the ApiClient methods.
Perhaps you could split your plugin into a few different plugins
my-plugin-common - All the common stuff
my-plugin-real-services - Adds the "real" services to the model (eg RealApiClient)
my-plugin-mock-services - Adds "mock" services to the model (eg MockApiClient)
my-plugin - Applies my-plugin-real-services and my-plugin-common
my-plugin-mock - Applies my-plugin-mock-services and my-plugin-common
In the real world, people will only ever apply: 'my-plugin'
For testing you could apply: 'my-plugin-mock'

Clojure Light Table client-server approach riddle

How can I set it up, so that I can use Light Table on the Mac, connected to a Ubuntu-hosted nREPL, and create a new program/project.clj? Can anybody help me to understand what my approach should be, and where I'm going wrong?
I have a Ubuntu server, in VirtualBox, along with Leiningen, Pedestal, and a pedestal 'helloworld' sample program, that displays in a browser. I just can't connect to the same REPL that runs the helloworld program. I don't have client-side access or control to the server-side object.
I want to do client-server Clojure development from my Mac host LT, creating server-side programs, that I can view in a REPL.
I don't find LT to be intuitive in this area, and the advice I've read only suggests that LT will connect to an existing project/REPL. I want to create new objects, from the client
Assuming you are talking mostly about the server side of things (don't know much yet about ClojureScript), here is how you would setup a new project and code interactively against a remote repl.
lein new project-name in your VM.
Setup your project.clj the way you want it. You must include dependencies!
Start the REPL in your VM and note the port number
Commit your code to version control (git).
Checkout the same codebase for editing in LightTable in Mac OSX.
Connect to the remote REPL.
Open core.clj or create a new namespace file and start hacking.
Evaluate your code snippets or the entire file.
There are a couple of potential problems I foresee with this. First is that whenever you add a dependency, you will need to commit the change to version control, synchronize your VM working copy, restart your REPL, and reconnect LightTable to the remote REPL.
Second, you may have problems as the project grows beyond a few namespaces. I believe if your namespace requires another namespace from your project, the remote REPL process will (I think) try to load it off it's local classpath. If the dependency is not there or has changed, I don't think LightTable is smart enough to send the required namespaces over the wire. Try it out and let us know what the actual behavior is.

Load OSGi class from JNI

I am calling some C++ code that tries to load a Java class, e.g.
JNIEnv *jenv = ...
jclass cls = jenv->FindClass("org/some/bundle/SomeClass");
Now, the problem is that this class resides in an OSGi bundle, and the code above cannot find my class.
This problem only arise when running unit tests (Tycho-surefire headless tests). Is there a simple way to force the OSGi framework to find my class from JNI? On the Java side, I suspect something like Dynamic-ImportPackage could have fixed my problem. I am unwilling to change the third party C++ library just to get it working with the test framework, so I prefer a solution on the Java test setup / configuration side, if possible.
The FindClass method of JNIEnv only searches the contents of the system ClassLoader as defined by the global application classpath. Since OSGi does not use the global classpath, it is no surprise that this doesn't work.
In general whenever loading a class, you need to specify not just the class name but also the classloader that should load it. This is an inevitable requirement of modularity. So your code needs to be able to find the bundle that you expect to contain the class, and then call its loadClass method. You can do this directly in C++ code, but it may be easier to write a Java utility method to do it and then just call that method from C++.
Well, I am not 100% sure that your case is like mine.
In my RCP I used to get the exception:
ClassNotFoundException: com.tool.packageA.IWantToLoadThisClass cannot be found by com.tool.packageB_1.0.0.qualifier
A simple solution was to:
Add com.tool.packageA to com.tool.packageB MANIFEST.MF Require-Bundle.
I though wanted to avoid that solution, because I was able to load other classes found in other packages normally com.tool.packageC, com.tool.packageD (This wasn't done by me though so I didn't know how it worked).
Searching around I came to find the other solution which I ended up using to keep things similar to the current working packages (com.tool.packageC, com.tool.packageD).
The solution was:
Using Eclipse-BuddyPolicy and Eclipse-RegisterBuddy see here for detailed info
This is how to get it to work:
Add Eclipse-BuddyPolicy: registered to com.tool.packageB MANIFEST.MF
Add Eclipse-RegisterBuddy: com.tool.packageB to com.tool.packageA MANIFEST.MF
Add Require-Bundle: com.tool.packageB to com.tool.packageA MANIFEST.MF
Now com.tool.packageA.IWantToLoadThisClass will be visible from com.tool.packageB and you will be able to find it when jenv->FindClass("com/tool/packageA/IWantToLoadThisClass");.
I hope this helps.

How do I programmatically set gzip in Jetty?

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 :)

clojure rmi classpath problem

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