Immutant (Part I): How To Install And Use With Noir
Immutant is the new player in the Clojure web development; not a framework but the first Clojure'esque application server. Let's see how well it fits in the Clojure ecosystem.
But there's this new kid in town and he's one tough kid: Immutant. It's basically JBoss AS7 along with clustering, caching, XA transactions, scheduled jobs and daemons packaged for Clojure web applications through an easy to use API. And I should say that JBosss AS7 (unlike AS6/5/4) is extremely fast and lightweight compared to its heavyweight contenders like Glassfissh and Geronimo.
So you may ask how well does it integrate into Clojure ecosystem? That, I'll attempt to show you in the "Immutant series".
Then install the latest version of Immutant like below (at the time of this writing, the latest version is 0.7.0):
Stop Immutant by pressing
Besides these, you can see that there are minor bugs in the Leiningen integration part which makes sense considering that the project is young. However, the Immutant folks who can be reached on #immutant on freenode are so friendly and responsive that it took me almost no time to overcome these bugs; so you need not to worry about those bugs.
Introduction
If you have ever done any web project in Clojure, you certainly know about the dominance of Jetty in Clojure web development realm as almost all Clojure web frameworks (Compojure, Noir, Moustache, ...) rely on Jetty to deliver their promises. This is not bad at all: Jetty is a lightweight servlet container with a small memory footprint which serves you well for a usual CMS like website. But if you need to use services like messaging or need to deploy your application to a context other than root or you want profiling, resource management and such, then Jetty may not be your best choice.But there's this new kid in town and he's one tough kid: Immutant. It's basically JBoss AS7 along with clustering, caching, XA transactions, scheduled jobs and daemons packaged for Clojure web applications through an easy to use API. And I should say that JBosss AS7 (unlike AS6/5/4) is extremely fast and lightweight compared to its heavyweight contenders like Glassfissh and Geronimo.
So you may ask how well does it integrate into Clojure ecosystem? That, I'll attempt to show you in the "Immutant series".
Installation
Assuming you're using Leiningen 2.x, it's pretty straight forward. Open up~/.lein/profiles.clj
(create it if it doesn't exist yet) and add Immutant to the list of plugins. For example, my profiles.clj
looks like this: {:user
{:plugins [[lein-swank "1.4.4"]
[lein-immutant "0.14.1"]]}}
Note: You can always check for the latest lein-immutant version, by visiting clojars.org.Then install the latest version of Immutant like below (at the time of this writing, the latest version is 0.7.0):
lein immutant install 0.7.0
If you have a shaky or slow connection like me, your download might get corrupted. You can download and set it up like below. Of course putting it inside ~/Programs/Immutant
is completely a matter of personal choice. $ cd ~/Programs
$ mkdir Immutant
$ cd Immutant
$ wget -c http://repository-projectodd.forge.cloudbees.com/release/org/immutant/immutant-dist/0.7.0/immutant-dist-0.7.0-bin.zip
$ unzip immutant-dist-0.7.0-bin.zip
$ echo "IMMUTANT_HOME=`pwd`" >> ~/.bashrc
To check whether everything is in place run Immutant. $ lein immutant run
Starting Immutant: /home/bahman/Programs/Immutant/0.7.0/jboss/bin/standalone.sh
=========================================================================
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd
JBoss Bootstrap Environment
JBOSS_HOME: /home/bahman/Programs/Immutant/0.7.0/jboss
JAVA: /home/bahman/Programs/Java/1.6.0_37/bin/java
JAVA_OPTS: -server -XX:+UseCompressedOops -Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Djboss.server.default.config=standalone.xml
=========================================================================
12:41:03,821 INFO [org.jboss.modules] JBoss Modules version 1.1.3.GA
12:41:04,064 INFO [org.jboss.msc] JBoss MSC version 1.0.2.GA
12:41:04,140 INFO [org.jboss.as] JBAS015899: JBoss AS 7.1.x.incremental.129 "Arges" starting
12:41:05,389 INFO [org.projectodd.polyglot.hasingleton.as] Initializing HA-Singleton Subsystem
12:41:05,393 INFO [org.immutant.daemons.as] Initializing Immutant Daemons Subsystem
12:41:05,401 INFO [org.immutant.jobs.as] Initializing Immutant Jobs Subsystem
12:41:05,401 INFO [org.immutant.xa.as] Initializing Immutant XA Subsystem
12:41:05,403 INFO [org.immutant.cache.as] Initializing Immutant Cache Subsystem
12:41:05,400 INFO [org.immutant.messaging.as] Initializing Immutant Messaging Subsystem
12:41:05,413 INFO [org.immutant.core.as] Initializing Immutant Core Subsystem
12:41:05,415 INFO [org.immutant.web.as] Initializing Immutant Web Subsystem
12:41:05,449 INFO [org.immutant.core.as] Welcome to Immutant AS - http://immutant.org/
12:41:05,449 INFO [org.immutant.core.as] version........... 0.7.0
12:41:05,449 INFO [org.immutant.core.as] build............. 36
12:41:05,450 INFO [org.immutant.core.as] revision.......... 5ef334c8198bdfa80bea8e0b20cf253a33b49c69
12:41:05,450 INFO [org.immutant.core.as] built with:
12:41:05,450 INFO [org.immutant.core.as] HornetQ......... 2.2.21.SNAPSHOT (HQ_2_2_21_final, 122)
12:41:05,450 INFO [org.immutant.core.as] JBossAS......... 7.1.x.incremental.129
12:41:05,476 INFO [org.immutant.core.as] Clojure......... 1.4.0
12:41:05,476 INFO [org.immutant.core.as] Infinispan...... 5.1.8.Final
12:41:05,476 INFO [org.immutant.core.as] Quartz.......... 2.1.5
12:41:05,699 WARN [org.jboss.as.server] JBAS015883: No security realm defined for native management service; all access will be unrestricted.
12:41:05,702 INFO [org.xnio] XNIO Version 3.0.7.GA
12:41:05,708 INFO [org.jboss.as.server] JBAS015888: Creating http management service using socket-binding (management-http)
12:41:05,709 WARN [org.jboss.as.server] JBAS015884: No security realm defined for http management service; all access will be unrestricted.
12:41:05,717 INFO [org.xnio.nio] XNIO NIO Implementation Version 3.0.7.GA
12:41:05,737 INFO [org.jboss.remoting] JBoss Remoting version 3.2.12.GA
12:41:05,796 INFO [org.jboss.as.logging] JBAS011502: Removing bootstrap log handlers
12:41:05,818 INFO [org.jboss.as.configadmin] (ServerService Thread Pool -- 39) JBAS016200: Activating ConfigAdmin Subsystem
12:41:05,834 INFO [org.jboss.as.remoting] (MSC service thread 1-1) JBAS017100: Listening on 127.0.0.1:9999
12:41:05,851 INFO [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 44) JBAS010280: Activating Infinispan subsystem.
12:41:05,869 INFO [org.jboss.as.jacorb] (ServerService Thread Pool -- 45) JBAS016300: Activating JacORB Subsystem
12:41:05,948 INFO [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 40) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
12:41:05,966 INFO [org.jboss.as.connector.logging] (MSC service thread 1-4) JBAS010408: Starting JCA Subsystem (JBoss IronJacamar 1.0.13.Final)
12:41:06,067 INFO [org.jboss.as.osgi] (ServerService Thread Pool -- 56) JBAS011906: Activating OSGi Subsystem
12:41:06,128 INFO [org.jboss.as.security] (ServerService Thread Pool -- 60) JBAS013171: Activating Security Subsystem
12:41:06,076 INFO [org.jboss.as.naming] (ServerService Thread Pool -- 55) JBAS011800: Activating Naming Subsystem
12:41:06,144 INFO [org.jboss.as.security] (MSC service thread 1-3) JBAS013170: Current PicketBox version=4.0.14.Final
12:41:06,150 INFO [org.jboss.as.webservices] (ServerService Thread Pool -- 64) JBAS015537: Activating WebServices Extension
12:41:06,207 INFO [org.jboss.as.naming] (MSC service thread 1-2) JBAS011802: Starting Naming Service
12:41:06,361 INFO [org.jboss.jaxr] (MSC service thread 1-3) JBAS014000: Started JAXR subsystem, binding JAXR connection factory into JNDI as: java:jboss/jaxr/ConnectionFactory
12:41:06,390 INFO [org.jboss.as.mail.extension] (MSC service thread 1-3) JBAS015400: Bound mail session [java:jboss/mail/Default]
12:41:06,557 INFO [org.jboss.ws.common.management.AbstractServerConfig] (MSC service thread 1-4) JBoss Web Services - Stack CXF Server 4.0.5.GA
12:41:06,757 WARN [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011600: AIO wasn't located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal
12:41:06,913 INFO [org.jboss.as.jacorb] (MSC service thread 1-1) JBAS016330: CORBA ORB Service started
12:41:06,914 INFO [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-4) Starting Coyote HTTP/1.1 on http-localhost/127.0.0.1:8080
12:41:07,028 INFO [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-3) live server is starting with configuration HornetQ Configuration (clustered=false,backup=false,sharedStore=true,journalDirectory=/home/bahman/Programs/Immutant/0.7.0/jboss/standalone/data/messagingjournal,bindingsDirectory=/home/bahman/Programs/Immutant/0.7.0/jboss/standalone/data/messagingbindings,largeMessagesDirectory=/home/bahman/Programs/Immutant/0.7.0/jboss/standalone/data/messaginglargemessages,pagingDirectory=/home/bahman/Programs/Immutant/0.7.0/jboss/standalone/data/messagingpaging)
12:41:07,031 INFO [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-3) Waiting to obtain live lock
12:41:07,156 INFO [org.hornetq.core.persistence.impl.journal.JournalStorageManager] (MSC service thread 1-3) Using NIO Journal
12:41:07,334 INFO [org.jboss.as.jacorb] (MSC service thread 1-1) JBAS016328: CORBA Naming Service started
12:41:07,526 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-4) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
12:41:07,572 INFO [org.hornetq.core.server.impl.FileLockNodeManager] (MSC service thread 1-3) Waiting to obtain live lock
12:41:07,573 INFO [org.hornetq.core.server.impl.FileLockNodeManager] (MSC service thread 1-3) Live Server Obtained live lock
12:41:07,755 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-2) JBAS015012: Started FileSystemDeploymentService for directory /home/bahman/Programs/Immutant/0.7.0/jboss/standalone/deployments
12:41:07,764 INFO [org.jboss.as.remoting] (MSC service thread 1-4) JBAS017100: Listening on 127.0.0.1:4447
12:41:08,323 INFO [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-3) Started Netty Acceptor version 3.2.6.Final-20df069 127.0.0.1:5445 for CORE protocol
12:41:08,331 INFO [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-3) Started Netty Acceptor version 3.2.6.Final-20df069 127.0.0.1:5455 for CORE protocol
12:41:08,339 INFO [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-3) Server is now live
12:41:08,339 INFO [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-3) HornetQ Server version 2.2.21.SNAPSHOT (HQ_2_2_21_final, 122) [629ea0db-4394-11e2-9206-77895f5be59f]) started
12:41:08,407 INFO [org.jboss.as.messaging] (ServerService Thread Pool -- 74) JBAS011601: Bound messaging object to jndi name java:/ConnectionFactory
12:41:08,416 INFO [org.jboss.as.messaging] (ServerService Thread Pool -- 75) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory
12:41:08,456 INFO [org.jboss.as.deployment.connector] (MSC service thread 1-1) JBAS010406: Registered connection factory java:/JmsXA
12:41:08,591 INFO [org.hornetq.ra.HornetQResourceAdapter] (MSC service thread 1-1) HornetQ resource adaptor started
12:41:08,591 INFO [org.jboss.as.connector.services.resourceadapters.ResourceAdapterActivatorService$ResourceAdapterActivator] (MSC service thread 1-1) IJ020002: Deployed: file://RaActivatorhornetq-ra
12:41:08,611 INFO [org.jboss.as.deployment.connector] (MSC service thread 1-1) JBAS010401: Bound JCA ConnectionFactory [java:/JmsXA]
12:41:08,757 INFO [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management
12:41:08,761 INFO [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990
12:41:08,761 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.x.incremental.129 "Arges" started in 5289ms - Started 168 of 256 services (87 services are passive or on-demand)
On the last line of the ever-bloated JBoss log above, you can see that JBoss AS7 has started in less than 5.5 seconds which to me is as wonderful as seeing a sphinx fishing! JBoss has done an excellent job in cleaning up its act.Stop Immutant by pressing
CTRL+C
.First Noir Project
Create a new Noir project as usual.$ lein new noir immoir
Generating a lovely new Noir project named immoir...
At the time of this writing, Noir 1.3.0 has just been released. We need to change the Noir version to avoid a minor bug in resource paths. ;; project.clj
;;
(defproject immoir "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:dependencies [[org.clojure/clojure "1.4.0"]
[noir "1.3.0"]] ;; ** changed to final version
:main immoir.server)
Now tell Immutant to take care of this project. $ lein immutant init
Wrote sample src/immutant/init.clj
Currently lein-immutant doesn't require noir.server
by default. We're going to fix that manually. ;; init.clj
;
(ns immutant.init
;(:use .core)
; ** uncommented the following clause
(:require [noir.server :as server] ; ** added this
[immutant.messaging :as messaging]
[immutant.web :as web]
[immutant.util :as util]))
;; This file will be loaded when the application is deployed to Immutant, and
;; can be used to start services your app needs. Examples:
;; Web endpoints need a context-path and ring handler function. The context
;; path given here is a sub-path to the global context-path for the app
;; if any.
; (web/start "/" my-ring-handler)
; (web/start "/foo" a-different-ring-handler)
;; To start a Noir app:
; ** uncommented the following two clauses
(server/load-views (util/app-relative "src//views"))
(web/start "/" (server/gen-handler {:mode :dev :ns 'immoir}))
;; Messaging allows for starting (and stopping) destinations (queues & topics)
;; and listening for messages on a destination.
; (messaging/start "/queue/a-queue")
; (messaging/listen "/queue/a-queue" #(println "received: " %))
Now let's deploy our tiny application to Immutant. Run lein immutant run
and in a new terminal (after switching to the project directory) run lein immutant deploy
. Check the terminal in which Immutant is running and if everything goes fine you can see something like this: 13:19:28,768 INFO [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "immoir.clj"
13:19:40,733 INFO [immutant.web] (MSC service thread 1-3) Registering ring handler at sub-context path: /*
13:19:40,775 INFO [org.jboss.as.osgi] (MSC service thread 1-4) JBAS011907: Register module: Module "deployment.immoir.clj:main" from Service Module Loader
13:19:40,975 INFO [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /immoir
13:19:41,215 INFO [org.jboss.as.server] (DeploymentScanner-threads - 1) JBAS018559: Deployed "immoir.clj"
Your brand new web project is available at http://localhost:8080/immoir So far so good; where's the REPL?!
Well, as the ancient saying goes: “REPL is King”. So our next trick (which is by the way a very easy one) is to launch a REPL for our project on Immutant. First of all runlein immutant undeploy
as we are going to edit project.clj
to add REPL support. Open project.clj
and edit as below: (defproject immoir "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:dependencies [[org.clojure/clojure "1.4.0"]
[noir "1.3.0"]]
:main immoir.server
:profiles {:dev ; ** added this
{:immutant
{:swank-port 4242}}})
This tells Immutant to launch a Swank server on port 4242 on localhost so that we connect to it from Emacs. Deploy your project (lein immutant deploy
) and if all goes fine inside Emacs type M-x slime-connect
and voila!
Comments
Post a Comment