Browse Source

Merge pull request #1591 from yogthos/master

Clojure: Update Luminus to 2.x
Hamilton Turner 10 years ago
parent
commit
92f2beaa79
24 changed files with 408 additions and 394 deletions
  1. 10 29
      frameworks/Clojure/luminus/benchmark_config.json
  2. 3 4
      frameworks/Clojure/luminus/hello/.gitignore
  3. 1 0
      frameworks/Clojure/luminus/hello/Procfile
  4. 1 1
      frameworks/Clojure/luminus/hello/README.md
  5. 34 0
      frameworks/Clojure/luminus/hello/env/dev/clj/hello/repl.clj
  6. 48 39
      frameworks/Clojure/luminus/hello/project.clj
  7. 5 54
      frameworks/Clojure/luminus/hello/resources/public/css/screen.css
  8. 20 0
      frameworks/Clojure/luminus/hello/resources/sql/queries.sql
  9. 0 0
      frameworks/Clojure/luminus/hello/resources/templates/base.html
  10. 3 3
      frameworks/Clojure/luminus/hello/resources/templates/home.html
  11. 30 0
      frameworks/Clojure/luminus/hello/src/hello/core.clj
  12. 69 0
      frameworks/Clojure/luminus/hello/src/hello/db/core.clj
  13. 34 34
      frameworks/Clojure/luminus/hello/src/hello/handler.clj
  14. 37 0
      frameworks/Clojure/luminus/hello/src/hello/layout.clj
  15. 37 0
      frameworks/Clojure/luminus/hello/src/hello/middleware.clj
  16. 0 94
      frameworks/Clojure/luminus/hello/src/hello/models/db.clj
  17. 0 39
      frameworks/Clojure/luminus/hello/src/hello/models/schema.clj
  18. 24 50
      frameworks/Clojure/luminus/hello/src/hello/routes/home.clj
  19. 21 0
      frameworks/Clojure/luminus/hello/src/hello/session.clj
  20. 0 10
      frameworks/Clojure/luminus/hello/src/hello/views/layout.clj
  21. 0 7
      frameworks/Clojure/luminus/hello/src/log4j.xml
  22. 2 4
      frameworks/Clojure/luminus/hello/test/hello/test/handler.clj
  23. 6 12
      frameworks/Clojure/luminus/setup.sh
  24. 23 14
      frameworks/Clojure/luminus/source_code

+ 10 - 29
frameworks/Clojure/luminus/benchmark_config.json

@@ -3,45 +3,26 @@
   "tests": [{
     "default": {
       "setup_file": "setup",
-      "json_url": "/luminus/json",
-      "db_url": "/luminus/db",
-      "query_url": "/luminus/db/",
-      "fortune_url": "/luminus/fortune",
-      "update_url": "/luminus/update/",
-      "plaintext_url": "/luminus/plaintext",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates/",
+      "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
-      "classification": "Micro",
-      "database": "MySQL",
-      "framework": "luminus",
-      "language": "Clojure",
-      "orm": "Full",
-      "platform": "Servlet",
-      "webserver": "Resin",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "luminus",
-      "notes": "",
-      "versus": "servlet"
-    },
-    "raw": {
-      "setup_file": "setup",
-      "db_url": "/luminus/dbraw",
-      "query_url": "/luminus/dbraw/",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
+      "classification": "Platform",
       "database": "MySQL",
       "framework": "luminus",
       "language": "Clojure",
       "orm": "Raw",
-      "platform": "Servlet",
-      "webserver": "Resin",
+      "platform": "http-kit",
+      "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "luminus",
       "notes": "",
-      "versus": "servlet"
+      "versus": ""
     }
   }]
 }

+ 3 - 4
frameworks/Clojure/luminus/hello/.gitignore

@@ -5,7 +5,6 @@
 pom.xml
 *.jar
 *.class
-.lein-deps-sum
-.lein-failures
-.lein-plugins
-.lein-env
+/.lein-*
+/.env
+*.log

+ 1 - 0
frameworks/Clojure/luminus/hello/Procfile

@@ -0,0 +1 @@
+web: java $JVM_OPTS -cp target/hello.jar clojure.main -m hello.core

+ 1 - 1
frameworks/Clojure/luminus/hello/README.md

@@ -16,4 +16,4 @@ To start a web server for the application, run:
 
 ## License
 
-Copyright © 2013 FIXME
+Copyright © 2015 FIXME

+ 34 - 0
frameworks/Clojure/luminus/hello/env/dev/clj/hello/repl.clj

@@ -0,0 +1,34 @@
+(ns hello.repl
+  (:use hello.handler
+    ring.server.standalone
+    [ring.middleware file-info file]))
+
+(defonce server (atom nil))
+
+(defn get-handler []
+  ;; #'app expands to (var app) so that when we reload our code,
+  ;; the server is forced to re-resolve the symbol in the var
+  ;; rather than having its own copy. When the root binding
+  ;; changes, the server picks it up without having to restart.
+  (-> #'app
+      ; Makes static assets in $PROJECT_DIR/resources/public/ available.
+      (wrap-file "resources")
+      ; Content-Type, Content-Length, and Last Modified headers for files in body
+      (wrap-file-info)))
+
+(defn start-server
+  "used for starting the server in development mode from REPL"
+  [& [port]]
+  (let [port (if port (Integer/parseInt port) 3000)]
+    (reset! server
+            (serve (get-handler)
+                   {:port port
+                    :init init
+                    :auto-reload? true
+                    :destroy destroy
+                    :join? false}))
+    (println (str "You can view the site at http://localhost:" port))))
+
+(defn stop-server []
+  (.stop @server)
+  (reset! server nil))

+ 48 - 39
frameworks/Clojure/luminus/hello/project.clj

@@ -1,40 +1,49 @@
-(defproject
-  hello
-  "luminus"
-  :dependencies
-  [[org.clojure/clojure "1.5.1"]
-   [lib-noir "0.8.2"]
-   [compojure "1.1.6"]
-   [ring-server "0.3.1"]
-   [selmer "0.5.7"]
-   [com.taoensso/timbre "2.7.1"]
-   [com.postspectacular/rotor "0.1.0"]
-   [com.taoensso/tower "2.0.2"]
-   [mysql/mysql-connector-java "5.1.28"]
-   [korma "0.3.0-RC6"]
-   [c3p0/c3p0 "0.9.1.2"]
-   [log4j
-    "1.2.17"
-    :exclusions
-    [javax.mail/mail
-     javax.jms/jms
-     com.sun.jdmk/jmxtools
-     com.sun.jmx/jmxri]]]
-  :ring
-  {:handler hello.handler/app,
-   :init hello.handler/init,
-   :destroy hello.handler/destroy}
+(defproject hello "luminus"
+
+  :description "Luminus framework benchmarks"
+  :url "https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Clojure/luminus"
+
+  :dependencies [[org.clojure/clojure "1.6.0"]
+                 [ring-server "0.4.0"]
+                 [selmer "0.8.2"]
+                 [com.taoensso/timbre "3.4.0"]
+                 [com.taoensso/tower "3.0.2"]
+                 [markdown-clj "0.9.65"]
+                 [environ "1.0.0"]
+                 [im.chit/cronj "1.4.3"]
+                 [compojure "1.3.3"]
+                 [ring/ring-defaults "0.1.4"]
+                 [ring/ring-session-timeout "0.1.0"]
+                 [ring-middleware-format "0.5.0"]
+                 [noir-exception "0.2.3"]
+                 [bouncer "0.3.2"]
+                 [prone "0.8.1"]
+                 [org.clojure/tools.nrepl "0.2.8"]
+                 [yesql "0.5.0-rc2"]
+                 [mysql/mysql-connector-java "5.1.6"]
+                 [c3p0/c3p0 "0.9.1.2"]
+                 [http-kit "2.1.19"]
+                 [org.clojure/tools.cli "0.2.1"]]
+
+  :min-lein-version "2.0.0"
+  :uberjar-name "hello.jar"
+  :jvm-opts ["-server"]
+
+  :main hello.core
+
+  :plugins [[lein-ring "0.9.1"]
+            [lein-environ "1.0.0"]]
+
   :profiles
-  {:uberjar {:aot :all}
-   :production
-   {:ring
-    {:open-browser? false, :stacktraces? false, :auto-reload? false}},
-   :dev
-   {:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.2.2"]]}}
-  :url
-  "http://example.com/FIXME"
-  :plugins
-  [[lein-ring "0.8.10"]]
-  :description
-  "FIXME: write description"
-  :min-lein-version "2.0.0")
+  {:uberjar {:omit-source true
+             :env {:production true}
+             :aot :all}
+   :dev {:dependencies [[ring-mock "0.1.5"]
+                        [ring/ring-devel "1.3.2"]
+                        [pjstadig/humane-test-output "0.7.0"]]
+         :source-paths ["env/dev/clj"]
+
+         :repl-options {:init-ns hello.repl}
+         :injections [(require 'pjstadig.humane-test-output)
+                      (pjstadig.humane-test-output/activate!)]
+         :env {:dev true}}})

+ 5 - 54
frameworks/Clojure/luminus/hello/resources/public/css/screen.css

@@ -1,55 +1,6 @@
-body {	
-    background-color: #fff;
-    color: #333;
-    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+html,
+body {
+	font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+    height: 100%;
+    padding-top: 40px;
 }
-
-#register {
-    float: left;
-    display: inline-block;
-}
-
-h1 {
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-	background-color: #E9E9E9;
-	border: 1px solid #CFCFCF;
-	border-radius: 4px;
-}
-
-.nav li {
-    float: left;
-    list-style: none;
-    padding: 5px;
-}
-
-.navbar {
-    text-align: right;
-    padding: 5px;
-    margin-bottom: 10px;
-}
-
-#container {
-    height: auto;
-    margin-bottom: 10px;
-}
-
-#footer {    
-    width: 95%;
-    margin-left: 1%;
-    margin-right: 1%;
-    position:absolute;
-    bottom:0;
-    font-size: 11px;
-    font-weight: bold;
-    height: auto;    
-    text-align: center;
-    
-	padding-top: 10px;
-	
-	-webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-	background-color: #E9E9E9;
-	border: 1px solid #CFCFCF;
-	border-radius: 4px;
-}

+ 20 - 0
frameworks/Clojure/luminus/hello/resources/sql/queries.sql

@@ -0,0 +1,20 @@
+--name: get-world
+-- Query a World record from the database
+SELECT * FROM world
+WHERE id = :id
+
+--name: get-all-fortunes
+-- select all records from the fortune table
+SELECT * FROM fortune
+
+--name: update-world<!
+-- update an existing world record
+UPDATE world
+SET randomNumber = :randomNumber
+WHERE id = :id
+
+--name: get-all-fortunes
+-- query all fortune records
+SELECT id, message FROM fortune
+
+

+ 0 - 0
frameworks/Clojure/luminus/hello/src/hello/views/templates/base.html → frameworks/Clojure/luminus/hello/resources/templates/base.html


+ 3 - 3
frameworks/Clojure/luminus/hello/src/hello/views/templates/home.html → frameworks/Clojure/luminus/hello/resources/templates/home.html

@@ -1,4 +1,4 @@
-{% extends "hello/views/templates/base.html" %}
+{% extends "base.html" %}
 
 {% block content %}
 
@@ -13,6 +13,6 @@
     <td>{{message.message}}</td>
   </tr>
   {% endfor %}
-</table>  
-  
+</table>
+
 {% endblock %}

+ 30 - 0
frameworks/Clojure/luminus/hello/src/hello/core.clj

@@ -0,0 +1,30 @@
+(ns hello.core
+  (:require [hello.handler :refer [app init]]
+            [clojure.tools.cli :refer [cli]]
+            [org.httpkit.server :refer [run-server]])
+  (:gen-class))
+
+(defn parse-port [s]
+  "Convert stringy port number int. Defaults to 8080."
+  (cond
+    (string? s) (Integer/parseInt s)
+    (instance? Integer s) s
+    (instance? Long s) (.intValue ^Long s)
+    :else 8080))
+
+(defn start-server [{:keys [port]}]
+  (let [cpu (.availableProcessors (Runtime/getRuntime))]
+    ;; double worker threads should increase database access performance
+    (init)
+    (run-server app {:port port :thread (* 2 cpu)})
+    (println (str "http-kit server listens at :" port))))
+
+(defn -main [& args]
+  (let [[options _ banner]
+        (cli args
+             ["-p" "--port" "Port to listen" :default 8080 :parse-fn parse-port]
+             ["--[no-]help" "Print this help"])]
+    (when (:help options)
+          (println banner)
+          (System/exit 0))
+    (start-server options)))

+ 69 - 0
frameworks/Clojure/luminus/hello/src/hello/db/core.clj

@@ -0,0 +1,69 @@
+(ns hello.db.core
+  (:require
+    [yesql.core :refer [defqueries]])
+  (:import com.mchange.v2.c3p0.ComboPooledDataSource))
+
+(def db-spec
+  {:classname "com.mysql.jdbc.Driver"
+   :subprotocol "mysql"
+   :subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+   :user "benchmarkdbuser"
+   :password "benchmarkdbpass"})
+
+(defn pool
+  [spec]
+  {:datasource
+   (doto (ComboPooledDataSource.)
+     (.setDriverClass (:classname spec))
+     (.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
+     (.setUser (:user spec))
+     (.setPassword (:password spec))
+     ;; expire excess connections after 30 minutes of inactivity:
+     (.setMaxIdleTimeExcessConnections (* 30 60))
+     ;; expire connections after 3 hours of inactivity:
+     (.setMaxIdleTime (* 3 60 60)))})
+
+(defonce db (atom nil))
+
+(defn connect! []
+  (reset! db (pool db-spec)))
+
+(defqueries "sql/queries.sql")
+
+(defn get-world-random
+  "Query a random World record between 1 and 10,000 from the database"
+  []
+  (get-world {:id (inc (rand-int 9999))} {:connection @db}))
+
+(defn get-query-count [queries]
+  "Parse provided string value of query count, clamping values to between 1 and 500."
+  (let [n (try (Integer/parseInt queries)
+               (catch Exception e 1))] ; default to 1 on parse failure
+    (cond
+      (< n 1) 1
+      (> n 500) 500
+      :else n)))
+
+(defn run-queries
+  "Run the specified number of queries, return the results"
+  [queries]
+  (flatten (repeatedly (get-query-count queries) get-world-random)))
+
+(defn get-fortunes []
+   "Fetch the full list of Fortunes from the database, sort them by the fortune
+  message text, and then return the results."
+  (sort-by
+   :message
+   (conj (get-all-fortunes {} {:connection @db})
+         {:id 0 :message "Additional fortune added at request time."})))
+
+(defn update-and-persist
+  "Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+  (for [world (-> queries run-queries)]
+    (let [updated-world (assoc world :randomNumber (inc (rand-int 9999)))]
+      (update-world<! updated-world {:connection @db})
+      updated-world)))
+
+

+ 34 - 34
frameworks/Clojure/luminus/hello/src/hello/handler.clj

@@ -1,20 +1,20 @@
 (ns hello.handler
-  (:use hello.routes.home
-        compojure.core)
-  (:require [noir.util.middleware :as middleware]
+  (:require [compojure.core :refer [defroutes routes]]
+            [hello.routes.home :refer [home-routes]]
+            [hello.db.core :as db]
+            [hello.middleware
+             :refer [development-middleware production-middleware]]
+            [hello.session :as session]
             [compojure.route :as route]
             [taoensso.timbre :as timbre]
-            [taoensso.timbre.appenders.rotor :as rotor]))
-
-
-(defroutes app-routes
-  (route/resources "/")
-  (route/not-found "Not Found"))
-
-
-(defn destroy []
-  (timbre/info "picture-gallery is shutting down"))
+            [taoensso.timbre.appenders.rotor :as rotor]
+            [selmer.parser :as parser]
+            [environ.core :refer [env]]
+            [cronj.core :as cronj]))
 
+(defroutes base-routes
+           (route/resources "/")
+           (route/not-found "Not Found"))
 
 (defn init
   "init will be called once when
@@ -24,34 +24,34 @@
   []
   (timbre/set-config!
     [:appenders :rotor]
-    {:min-level :info
-     :enabled? true
-     :async? false ; should be always false for rotor
+    {:min-level             :info
+     :enabled?              true
+     :async?                false ; should be always false for rotor
      :max-message-per-msecs nil
-     :fn rotor/appender-fn})
+     :fn                    rotor/appender-fn})
 
   (timbre/set-config!
     [:shared-appender-config :rotor]
-    {:path "{{sanitized}}.log" :max-size (* 512 1024) :backlog 10})
-
-  (timbre/info "hello started successfully"))
+    {:path "hello.log" :max-size (* 512 1024) :backlog 10})
 
+  (if (env :dev) (parser/cache-off!))
+  (db/connect!)
+  ;;start the expired session cleanup job
+  (cronj/start! session/cleanup-job)
+  (timbre/info "\n-=[ hello started successfully"
+               (when (env :dev) "using the development profile") "]=-"))
 
 (defn destroy
   "destroy will be called when your application
    shuts down, put any clean up code here"
   []
-  (timbre/info "hello is shutting down..."))
-
-
-(def app (middleware/app-handler
-           ;; add your application routes here
-           [home-routes app-routes]
-           ;; add custom middleware here
-           :middleware []
-           ;; add access rules here
-           :access-rules []
-           ;; serialize/deserialize the following data formats
-           ;; available formats:
-           ;; :json :json-kw :yaml :yaml-kw :edn :yaml-in-html
-           :formats [:json-kw :edn]))
+  (timbre/info "hello is shutting down...")
+  (cronj/shutdown! session/cleanup-job)
+  (timbre/info "shutdown complete!"))
+
+(def app
+  (-> (routes
+        home-routes
+        base-routes)
+      development-middleware
+      production-middleware))

+ 37 - 0
frameworks/Clojure/luminus/hello/src/hello/layout.clj

@@ -0,0 +1,37 @@
+(ns hello.layout
+  (:require [selmer.parser :as parser]
+            [selmer.filters :as filters]
+            [markdown.core :refer [md-to-html-string]]
+            [ring.util.response :refer [content-type response]]
+            [compojure.response :refer [Renderable]]
+            [ring.util.anti-forgery :refer [anti-forgery-field]]
+            [ring.middleware.anti-forgery :refer [*anti-forgery-token*]]
+            [environ.core :refer [env]]))
+
+(parser/set-resource-path!  (clojure.java.io/resource "templates"))
+
+(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field)))
+(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)]))
+
+(deftype RenderableTemplate [template params]
+  Renderable
+  (render [this request]
+    (content-type
+      (->> (assoc params
+                  :page template
+                  :dev (env :dev)
+                  :csrf-token *anti-forgery-token*
+                  :servlet-context
+                  (if-let [context (:servlet-context request)]
+                    ;; If we're not inside a serlvet environment (for
+                    ;; example when using mock requests), then
+                    ;; .getContextPath might not exist
+                    (try (.getContextPath context)
+                         (catch IllegalArgumentException _ context))))
+        (parser/render-file (str template))
+        response)
+      "text/html; charset=utf-8")))
+
+(defn render [template & [params]]
+  (RenderableTemplate. template params))
+

+ 37 - 0
frameworks/Clojure/luminus/hello/src/hello/middleware.clj

@@ -0,0 +1,37 @@
+(ns hello.middleware
+  (:require [hello.session :as session]
+            [taoensso.timbre :as timbre]
+            [environ.core :refer [env]]
+            [selmer.middleware :refer [wrap-error-page]]
+            [prone.middleware :refer [wrap-exceptions]]
+            [ring.util.response :refer [redirect]]
+            [ring.middleware.defaults :refer [site-defaults wrap-defaults]]
+            [ring.middleware.session-timeout :refer [wrap-idle-session-timeout]]
+            [noir-exception.core :refer [wrap-internal-error]]
+            [ring.middleware.session.memory :refer [memory-store]]
+            [ring.middleware.format :refer [wrap-restful-format]]
+            
+            ))
+
+(defn log-request [handler]
+  (fn [req]
+    (timbre/debug req)
+    (handler req)))
+
+(defn development-middleware [handler]
+  (if (env :dev)
+    (-> handler
+        wrap-error-page
+        wrap-exceptions)
+    handler))
+
+(defn production-middleware [handler]
+  (-> handler
+      
+      (wrap-restful-format :formats [:json-kw :edn :transit-json :transit-msgpack])
+      (wrap-idle-session-timeout
+        {:timeout (* 60 30)
+         :timeout-response (redirect "/")})
+      (wrap-defaults
+        (assoc-in site-defaults [:session :store] (memory-store session/mem)))
+      (wrap-internal-error :log #(timbre/error %))))

+ 0 - 94
frameworks/Clojure/luminus/hello/src/hello/models/db.clj

@@ -1,94 +0,0 @@
-(ns hello.models.db
-  (:use korma.core
-         hello.models.schema)
-  (:require [clojure.java.jdbc :as jdbc]))
-
-
-
-; Set up entity World and the database representation
-(defentity world
-  (pk :id)
-  (table :world)
-  (entity-fields :id :randomNumber)
-  (database db))
-
-
-(defn get-world
-  "Query a random World record from the database"
-  []
-  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
-    (select world
-            (fields :id :randomNumber)
-            (where {:id id }))))
-
-
-(defn get-world-raw
-  "Query a random World record from the database"
-  []
-  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
-    (jdbc/with-connection (db-raw)
-      ; Set a naming strategy to preserve column name case
-      (jdbc/with-naming-strategy {:keyword identity}
-        (jdbc/with-query-results rs [(str "select * from world where id = ?") id]
-          (doall rs))))))
-
-
-(defn run-queries
-  "Run the specified number of queries, return the results"
-  [queries]
-  (flatten ; Make it a list of maps
-    (take queries
-          (repeatedly get-world))))
-
-
-(defn run-queries-raw [queries]
-  "Run the specified number of queries, return the results"
-  (flatten ; Make it a list of maps
-    (take queries
-          (repeatedly get-world-raw))))
-
-
-(defn get-query-count [queries]
-  "Parse provided string value of query count, clamping values to between 1 and 500."
-  (let [q (try (Integer/parseInt queries)
-               (catch Exception e 1))] ; default to 1 on parse failure
-    (if (> q 500)
-      500 ; clamp to 500 max
-      (if (< q 1)
-        1 ; clamp to 1 min
-        q)))) ; otherwise use provided value
-
-
-; Set up entity World and the database representation
-(defentity fortune
-  (pk :id)
-  (table :fortune)
-  (entity-fields :id :message)
-  (database db))
-
-
-(def get-all-fortunes
-  "Query all Fortune records from the database."
-  (select fortune
-          (fields :id :message)))
-
-
-(def get-fortunes
-  "Fetch the full list of Fortunes from the database. Insert an additional fortune at runtime.
-  Then sort all by fortune message text. Return the results."
-  (let [fortunes (conj get-all-fortunes
-                       {:id 0 :message "Additional fortune added at request time."})]
-    (sort-by :message fortunes)))
-
-
-(defn update-and-persist
-  "Changes the :randomNumber of a number of world entities.
-  Persists the changes to sql then returns the updated entities"
-  [queries]
-  (let [results (run-queries queries)]
-    (for [w results]
-      (update-in w [:randomNumber (inc (rand-int 9999))]
-        (update world
-                (set-fields {:randomNumber (:randomNumber w)})
-                (where {:id [:id w]}))))
-    results))

+ 0 - 39
frameworks/Clojure/luminus/hello/src/hello/models/schema.clj

@@ -1,39 +0,0 @@
-(ns hello.models.schema
-  (:require [korma.db :refer [defdb mysql]]
-            [clojure.java.jdbc :as sql])
-  (:import com.mchange.v2.c3p0.ComboPooledDataSource))
-
-; Database connection for java.jdbc "raw"
-; https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md
-(def db-spec-mysql-raw
-  {:classname "com.mysql.jdbc.Driver"
-   :subprotocol "mysql"
-   :subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
-   :user "benchmarkdbuser"
-   :password "benchmarkdbpass"})
-
-; Database connection
-(defdb db (mysql {:subname "//localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
-                  :user "benchmarkdbuser"
-                  :password "benchmarkdbpass"
-                  ;;OPTIONAL KEYS
-                  :delimiters "" ;; remove delimiters
-                  :maximum-pool-size 256
-                  }))
-                  
-(defn pool
-  [spec]
-  (let [cpds (doto (ComboPooledDataSource.)
-               (.setDriverClass (:classname spec))
-               (.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
-               (.setUser (:user spec))
-               (.setPassword (:password spec))
-               ;; expire excess connections after 30 minutes of inactivity:
-               (.setMaxIdleTimeExcessConnections (* 30 60))
-               ;; expire connections after 3 hours of inactivity:
-               (.setMaxIdleTime (* 3 60 60)))]
-    {:datasource cpds}))
-
-(def pooled-db (delay (pool db-spec-mysql-raw)))
-
-(defn db-raw [] @pooled-db)

+ 24 - 50
frameworks/Clojure/luminus/hello/src/hello/routes/home.clj

@@ -1,75 +1,49 @@
 (ns hello.routes.home
-  (:use compojure.core
-        hello.models.db)
-  (:require [hello.views.layout :as layout]
-            [noir.response :as response]))
-
+  (:require [hello.layout :as layout]
+            [hello.db.core :as db]
+            [compojure.core :refer [defroutes GET]]
+            [ring.util.response :refer [response]]
+            [clojure.java.io :as io]))
 
 (def json-serialization
   "Test 1: JSON serialization"
-  (response/json {:message "Hello, World!"}))
-
+  (response {:message "Hello, World!"}))
 
-(def single-query-test
+(defn single-query-test
   "Test 2: Single database query"
-  (response/json (first (run-queries 1))))
-
+  []
+  (-> 1 db/run-queries first response))
 
 (defn multiple-query-test
   "Test 3: Multiple database query"
   [queries]
   (-> queries
-      (get-query-count)
-      (run-queries)
-      (response/json)))
-
+      db/run-queries
+      response))
 
-(def single-query-test-raw
-  "Test 2: Single database query (raw)"
-  (-> 1
-      (run-queries-raw)
-      (first)
-      (response/json)))
-
-
-(defn multiple-query-test-raw
-  "Test 3: Multiple database query (raw)"
-  [queries]
-  (-> queries
-      (get-query-count)
-      (run-queries-raw)
-      (response/json)))
-
-
-(def fortunes
+(defn fortunes
   "Test 4: Fortunes"
-  (layout/render "home.html"
-                 {:messages get-fortunes}))
-
+  []
+  (layout/render "home.html" {:messages (db/get-fortunes)}))
 
 (defn db-update
   "Test 5: Database updates"
   [queries]
   (-> queries
-      (get-query-count)
-      (update-and-persist)
-      (response/json)))
-
+      db/update-and-persist
+      response))
 
 (def plaintext
   "Test 6: Plaintext"
   {:status 200
-   :headers {"Content-Type" "text/plain; charset=utf-8"}
+   :headers {"Content-Type" "text/plain"}
    :body "Hello, World!"})
 
-
 (defroutes home-routes
-  (GET "/"                [] "Hello, World!")
-  (GET "/plaintext"       [] plaintext)
-  (GET "/json"            [] json-serialization)
-  (GET "/db"              [] single-query-test)
-  (GET "/db/:queries"     [queries] (multiple-query-test queries))
-  (GET "/dbraw"           [] single-query-test-raw)
-  (GET "/dbraw/:queries"  [queries] (multiple-query-test-raw queries))
-  (GET "/fortune"         [] fortunes)
-  (GET "/update/:queries" [queries] (db-update queries)))
+  (GET "/"                 [] "Hello, World!")
+  (GET "/plaintext"        [] plaintext)
+  (GET "/json"             [] json-serialization)
+  (GET "/db"               [] (single-query-test))
+  (GET "/queries/:queries" [queries] (multiple-query-test queries))
+  (GET "/fortunes"         [] (fortunes))
+  (GET "/updates/:queries"  [queries] (db-update queries)))

+ 21 - 0
frameworks/Clojure/luminus/hello/src/hello/session.clj

@@ -0,0 +1,21 @@
+(ns hello.session
+  (:require [cronj.core :refer [cronj]]))
+
+(defonce mem (atom {}))
+
+(defn- current-time []
+  (quot (System/currentTimeMillis) 1000))
+
+(defn- expired? [[id session]]
+  (pos? (- (:ring.middleware.session-timeout/idle-timeout session) (current-time))))
+
+(defn clear-expired-sessions []
+  (clojure.core/swap! mem #(->> % (filter expired?) (into {}))))
+
+(def cleanup-job
+  (cronj
+    :entries
+    [{:id "session-cleanup"
+      :handler (fn [_ _] (clear-expired-sessions))
+      :schedule "* /30 * * * * *"
+      :opts {}}]))

+ 0 - 10
frameworks/Clojure/luminus/hello/src/hello/views/layout.clj

@@ -1,10 +0,0 @@
-(ns hello.views.layout
-  (:use noir.request)
-  (:require [selmer.parser :as parser]))
-
-(def template-path "hello/views/templates/")
-
-(defn render [template & [params]]
-  (parser/render-file (str template-path template)
-                      (assoc params :context (:context *request*))))
-

+ 0 - 7
frameworks/Clojure/luminus/hello/src/log4j.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
-  <logger name="com.mchange">
-    <level value="WARN"/>
-  </logger>
-</log4j:configuration>

+ 2 - 4
frameworks/Clojure/luminus/hello/test/hello/test/handler.clj

@@ -6,10 +6,8 @@
 (deftest test-app
   (testing "main route"
     (let [response (app (request :get "/"))]
-      (is (= (:status response) 200))
-      (is (= (:body response)
-             "Hello, World!"))))
+      (is (= 200 (:status response)))))
 
   (testing "not-found route"
     (let [response (app (request :get "/invalid"))]
-      (is (= (:status response) 404)))))
+      (is (= 404 (:status response))))))

+ 6 - 12
frameworks/Clojure/luminus/setup.sh

@@ -1,19 +1,13 @@
 #!/bin/bash
-
 source $IROOT/java7.installed
-
 source $IROOT/lein.installed
 
-export RESIN_HOME=${IROOT}/resin-4.0.41
-
-# Path vars must be set here
-export PATH="$JAVA_HOME/bin:$PATH"
-
-sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/models/schema.clj
+# Update db host in the source file
+sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/db/core.clj
 
 cd hello
 lein clean
-lein ring uberwar
-rm -rf $RESIN_HOME/webapps/*
-cp target/hello-luminus-standalone.war $RESIN_HOME/webapps/luminus.war
-$RESIN_HOME/bin/resinctl start
+rm -rf target
+# pack all dependencies into a single jar: target/http-kit-standalone.jar
+lein uberjar
+java -server -jar target/hello.jar  &

+ 23 - 14
frameworks/Clojure/luminus/source_code

@@ -1,23 +1,32 @@
+./luminus/hello/Procfile
+./luminus/hello/README.md
 ./luminus/hello/project.clj
-./luminus/hello/src/
-./luminus/hello/src/log4j.xml
-./luminus/hello/src/hello
-./luminus/hello/src/hello/routes
-./luminus/hello/src/hello/routes/home.clj
-./luminus/hello/src/hello/views
-./luminus/hello/src/hello/views/templates
-./luminus/hello/src/hello/views/templates/base.html
-./luminus/hello/src/hello/views/templates/home.html
-./luminus/hello/src/hello/views/layout.clj
-./luminus/hello/src/hello/handler.clj
-./luminus/hello/src/hello/models
-./luminus/hello/src/hello/models/schema.clj
-./luminus/hello/src/hello/models/db.clj
+./luminus/hello/env/
+./luminus/hello/env/dev/clj
+./luminus/hello/env/dev/clj/hello
+./luminus/hello/env/dev/clj/hello/repl.clj
 ./luminus/hello/resources/
 ./luminus/hello/resources/public
 ./luminus/hello/resources/public/css
 ./luminus/hello/resources/public/css/screen.css
+./luminus/hello/resources/sql
+./luminus/hello/resources/sql/queries.sql
+./luminus/hello//resources/templates
+./luminus/hello//resources/templates/base.html
+./luminus/hello//resources/templates/home.html
+./luminus/hello/src/
+./luminus/hello/src/hello
+./luminus/hello/src/hello/core.clj
+./luminus/hello/src/hello/handler.clj
+./luminus/hello/src/hello/layout.clj
+./luminus/hello/src/hello/middleware.clj
+./luminus/hello/src/hello/session.clj
+./luminus/hello/src/hello/db
+./luminus/hello/src/hello/db/core.clj
+./luminus/hello/src/hello/routes
+./luminus/hello/src/hello/routes/home.clj
 ./luminus/hello/test/
 ./luminus/hello/test/hello
 ./luminus/hello/test/hello/test
 ./luminus/hello/test/hello/test/handler.clj
+