Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Revert "Remove modules that were deprecated in 1.2"

This reverts commit 4e5d98a.

Too many build dependencies were broken by this change;
deprecated modules should be removed one-at-a-time.
  • Loading branch information...
commit 055b69c39b0d1ea61d486be11caa98f74c0493fc 1 parent 4e5d98a
Stuart Sierra authored August 20, 2010
16  modules/apply-macro/pom.xml
... ...
@@ -0,0 +1,16 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
  3
+         xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5
+                             http://maven.apache.org/maven-v4_0_0.xsd">
  6
+  <modelVersion>4.0.0</modelVersion>
  7
+  <parent>
  8
+    <groupId>org.clojure.contrib</groupId>
  9
+    <artifactId>parent</artifactId>
  10
+    <version>1.3.0-SNAPSHOT</version>
  11
+    <relativePath>../parent</relativePath>
  12
+  </parent>
  13
+  <artifactId>apply-macro</artifactId>
  14
+  <dependencies>
  15
+  </dependencies>
  16
+</project>
45  modules/apply-macro/src/main/clojure/clojure/contrib/apply_macro.clj
... ...
@@ -0,0 +1,45 @@
  1
+;;; apply_macro.clj: make macros behave like functions
  2
+
  3
+;; by Stuart Sierra, http://stuartsierra.com/
  4
+;; January 28, 2009
  5
+
  6
+;; Copyright (c) Stuart Sierra, 2009. All rights reserved.  The use
  7
+;; and distribution terms for this software are covered by the Eclipse
  8
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  9
+;; which can be found in the file epl-v10.html at the root of this
  10
+;; distribution.  By using this software in any fashion, you are
  11
+;; agreeing to be bound by the terms of this license.  You must not
  12
+;; remove this notice, or any other, from this software.
  13
+
  14
+
  15
+;; Don't use this.  I mean it.  It's evil.  How evil?  You can't
  16
+;; handle it, that's how evil it is.  That's right.  I did it so you
  17
+;; don't have to, ok?  Look but don't touch.  Use this lib and you'll
  18
+;; go blind.
  19
+
  20
+;; DEPRECATED in 1.2 with no replacement.
  21
+
  22
+(ns ^{:deprecated "1.2"}
  23
+  clojure.contrib.apply-macro)
  24
+
  25
+;; Copied from clojure.core/spread, which is private.
  26
+(defn- spread
  27
+  "Flatten final argument list as in apply."
  28
+  [arglist]
  29
+  (cond
  30
+   (nil? arglist) nil
  31
+   (nil? (rest arglist)) (seq (first arglist))
  32
+   :else (cons (first arglist) (spread (rest arglist)))))
  33
+
  34
+(defmacro apply-macro
  35
+  "This is evil.  Don't ever use it.  It makes a macro behave like a
  36
+  function.  Seriously, how messed up is that?
  37
+
  38
+  Evaluates all args, then uses them as arguments to the macro as with
  39
+  apply.
  40
+
  41
+  (def things [true true false])
  42
+  (apply-macro and things)
  43
+  ;; Expands to:  (and true true false)"
  44
+  [macro & args]
  45
+  (cons macro (spread (map eval args))))
26  modules/http-agent/pom.xml
... ...
@@ -0,0 +1,26 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
  3
+         xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5
+                             http://maven.apache.org/maven-v4_0_0.xsd">
  6
+  <modelVersion>4.0.0</modelVersion>
  7
+  <parent>
  8
+    <groupId>org.clojure.contrib</groupId>
  9
+    <artifactId>parent</artifactId>
  10
+    <version>1.3.0-SNAPSHOT</version>
  11
+    <relativePath>../parent</relativePath>
  12
+  </parent>
  13
+  <artifactId>http-agent</artifactId>
  14
+  <dependencies>
  15
+    <dependency>
  16
+      <groupId>org.clojure.contrib</groupId>
  17
+      <artifactId>http-connection</artifactId>
  18
+      <version>1.3.0-SNAPSHOT</version>
  19
+    </dependency>
  20
+    <dependency>
  21
+      <groupId>org.clojure.contrib</groupId>
  22
+      <artifactId>io</artifactId>
  23
+      <version>1.3.0-SNAPSHOT</version>
  24
+    </dependency>
  25
+  </dependencies>
  26
+</project>
386  modules/http-agent/src/main/clojure/clojure/contrib/http/agent.clj
... ...
@@ -0,0 +1,386 @@
  1
+;;; http/agent.clj: agent-based asynchronous HTTP client
  2
+
  3
+;; by Stuart Sierra, http://stuartsierra.com/
  4
+;; August 17, 2009
  5
+
  6
+;; Copyright (c) Stuart Sierra, 2009. All rights reserved.  The use
  7
+;; and distribution terms for this software are covered by the Eclipse
  8
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  9
+;; which can be found in the file epl-v10.html at the root of this
  10
+;; distribution.  By using this software in any fashion, you are
  11
+;; agreeing to be bound by the terms of this license.  You must not
  12
+;; remove this notice, or any other, from this software.
  13
+
  14
+;; DEPRECATED IN 1.2. Use direct Java bits, or take a look at
  15
+;;                    http://github.com/technomancy/clojure-http-client
  16
+
  17
+(ns ^{:deprecated "1.2"
  18
+      :doc "Agent-based asynchronous HTTP client.
  19
+
  20
+  This is a HTTP client library based on Java's HttpURLConnection
  21
+  class and Clojure's Agent system.  It allows you to make multiple
  22
+  HTTP requests in parallel.
  23
+
  24
+  Start an HTTP request with the 'http-agent' function, which
  25
+  immediately returns a Clojure Agent.  You will never deref this
  26
+  agent; that is handled by the accessor functions.  The agent will
  27
+  execute the HTTP request on a separate thread.
  28
+
  29
+  If you pass a :handler function to http-agent, that function will be
  30
+  called as soon as the HTTP response body is ready.  The handler
  31
+  function is called with one argument, the HTTP agent itself.  The
  32
+  handler can read the response body by calling the 'stream' function
  33
+  on the agent.
  34
+
  35
+  The value returned by the handler function becomes part of the state
  36
+  of the agent, and you can retrieve it with the 'result' function.
  37
+  If you call 'result' before the HTTP request has finished, it will
  38
+  block until the handler function returns.
  39
+
  40
+  If you don't provide a handler function, the default handler will
  41
+  buffer the entire response body in memory, which you can retrieve
  42
+  with the 'bytes', 'string', or 'stream' functions.  Like 'result',
  43
+  these functions will block until the HTTP request is completed.
  44
+
  45
+  If you want to check if an HTTP request is finished without
  46
+  blocking, use the 'done?' function.
  47
+
  48
+  A single GET request could be as simple as:
  49
+
  50
+    (string (http-agent \"http://www.stuartsierra.com/\"))
  51
+
  52
+  A simple POST might look like:
  53
+
  54
+    (http-agent \"http...\" :method \"POST\" :body \"foo=1\")
  55
+
  56
+  And you could write the response directly to a file like this:
  57
+
  58
+    (require '[clojure.contrib.io :as d])
  59
+
  60
+    (http-agent \"http...\"
  61
+                :handler (fn [agnt] 
  62
+                           (with-open [w (d/writer \"/tmp/out\")] 
  63
+                             (d/copy (stream agnt) w))))
  64
+"
  65
+       :author "Stuart Sierra"
  66
+       }
  67
+
  68
+  clojure.contrib.http.agent
  69
+  (:refer-clojure :exclude [bytes])
  70
+  (:require [clojure.contrib.http.connection :as c]
  71
+            [clojure.contrib.io :as duck])
  72
+  (:import (java.io InputStream ByteArrayOutputStream
  73
+                    ByteArrayInputStream)
  74
+           (java.net HttpURLConnection)))
  75
+
  76
+
  77
+;;; PRIVATE
  78
+
  79
+(declare result stream)
  80
+
  81
+(defn- setup-http-connection
  82
+  "Sets the instance method, redirect behavior, and request headers of
  83
+  the HttpURLConnection."
  84
+  [^HttpURLConnection conn options]
  85
+  (when-let [t (:connect-timeout options)]
  86
+    (.setConnectTimeout conn t))
  87
+  (when-let [t (:read-timeout options)]
  88
+    (.setReadTimeout conn t))
  89
+  (.setRequestMethod conn (:method options))
  90
+  (.setInstanceFollowRedirects conn (:follow-redirects options))
  91
+  (doseq [[name value] (:headers options)]
  92
+    (.setRequestProperty conn name value)))
  93
+
  94
+(defn- start-request
  95
+  "Agent action that starts sending the HTTP request."
  96
+  [state options]
  97
+  (let [conn (::connection state)]
  98
+    (setup-http-connection conn options)
  99
+    (c/start-http-connection conn (:body options))
  100
+    (assoc state ::state ::started)))
  101
+
  102
+(defn- connection-success? [^HttpURLConnection conn]
  103
+  "Returns true if the HttpURLConnection response code is in the 2xx
  104
+  range."
  105
+  (= 2 (quot (.getResponseCode conn) 100)))
  106
+
  107
+(defn- open-response
  108
+  "Agent action that opens the response body stream on the HTTP
  109
+  request; this will block until the response stream is available." ;
  110
+  [state options]
  111
+  (let [^HttpURLConnection conn (::connection state)]
  112
+    (assoc state
  113
+      ::response-stream (if (connection-success? conn)
  114
+                          (.getInputStream conn)
  115
+                          (.getErrorStream conn))
  116
+      ::state ::receiving)))
  117
+
  118
+(defn- handle-response
  119
+  "Agent action that calls the provided handler function, with no
  120
+  arguments, and sets the ::result key of the agent to the handler's
  121
+  return value."
  122
+  [state handler options]
  123
+  (let [conn (::connection state)]
  124
+    (assoc state
  125
+      ::result (handler)
  126
+      ::state ::finished)))
  127
+
  128
+(defn- disconnect
  129
+  "Agent action that closes the response body stream and disconnects
  130
+  the HttpURLConnection."
  131
+  [state options]
  132
+  (when (::response-stream state)
  133
+    (.close ^InputStream (::response-stream state)))
  134
+  (.disconnect ^HttpURLConnection (::connection state))
  135
+  (assoc state
  136
+    ::response-stream nil
  137
+    ::state ::disconnected))
  138
+
  139
+(defn- status-in-range?
  140
+  "Returns true if the response status of the HTTP agent begins with
  141
+  digit, an Integer."
  142
+  [digit http-agnt]
  143
+  (= digit (quot (.getResponseCode
  144
+                              ^HttpURLConnection (::connection @http-agnt))
  145
+                             100)))
  146
+
  147
+(defn- ^ByteArrayOutputStream get-byte-buffer [http-agnt]
  148
+  (let [buffer (result http-agnt)]
  149
+    (if (instance? ByteArrayOutputStream buffer)
  150
+      buffer
  151
+      (throw (Exception. "Handler result was not a ByteArrayOutputStream")))))
  152
+
  153
+
  154
+(defn buffer-bytes
  155
+  "The default HTTP agent result handler; it collects the response
  156
+  body in a java.io.ByteArrayOutputStream, which can later be
  157
+  retrieved with the 'stream', 'string', and 'bytes' functions."
  158
+  [http-agnt]
  159
+  (let [output (ByteArrayOutputStream.)]
  160
+    (duck/copy (or (stream http-agnt) "") output)
  161
+    output))
  162
+
  163
+
  164
+;;; CONSTRUCTOR
  165
+
  166
+(def *http-agent-defaults*
  167
+     {:method "GET"
  168
+      :headers {}
  169
+      :body nil
  170
+      :connect-timeout 0
  171
+      :read-timeout 0
  172
+      :follow-redirects true
  173
+      :handler buffer-bytes})
  174
+
  175
+(defn http-agent
  176
+  "Creates (and immediately returns) an Agent representing an HTTP
  177
+  request running in a new thread.
  178
+
  179
+  options are key/value pairs:
  180
+
  181
+  :method string
  182
+
  183
+  The HTTP method name.  Default is \"GET\".
  184
+
  185
+  :headers h
  186
+
  187
+  HTTP headers, as a Map or a sequence of pairs like 
  188
+  ([key1,value1], [key2,value2])  Default is nil.
  189
+
  190
+  :body b
  191
+  
  192
+  HTTP request entity body, one of nil, String, byte[], InputStream,
  193
+  Reader, or File.  Default is nil.
  194
+
  195
+  :connect-timeout int
  196
+
  197
+  Timeout value, in milliseconds, when opening a connection to the
  198
+  URL.  Default is zero, meaning no timeout.
  199
+
  200
+  :read-timeout int
  201
+
  202
+  Timeout value, in milliseconds, when reading data from the
  203
+  connection.  Default is zero, meaning no timeout.
  204
+
  205
+  :follow-redirects boolean
  206
+
  207
+  If true, HTTP 3xx redirects will be followed automatically.  Default
  208
+  is true.
  209
+
  210
+  :handler f
  211
+
  212
+  Function to be called when the HTTP response body is ready.  If you
  213
+  do not provide a handler function, the default is to buffer the
  214
+  entire response body in memory.
  215
+
  216
+  The handler function will be called with the HTTP agent as its
  217
+  argument, and can use the 'stream' function to read the response
  218
+  body.  The return value of this function will be stored in the state
  219
+  of the agent and can be retrieved with the 'result' function.  Any
  220
+  exceptions thrown by this function will be added to the agent's
  221
+  error queue (see agent-errors).  The default function collects the
  222
+  response stream in a memory buffer.
  223
+  "
  224
+  ([uri & options]
  225
+     (let [opts (merge *http-agent-defaults* (apply array-map options))]
  226
+       (let [a (agent {::connection (c/http-connection uri)
  227
+                       ::state ::created
  228
+                       ::uri uri
  229
+                       ::options opts})]
  230
+         (send-off a start-request opts)
  231
+         (send-off a open-response opts)
  232
+         (send-off a handle-response (partial (:handler opts) a) opts)
  233
+         (send-off a disconnect opts)))))
  234
+
  235
+
  236
+;;; RESPONSE BODY ACCESSORS
  237
+
  238
+(defn result
  239
+  "Returns the value returned by the :handler function of the HTTP
  240
+  agent; blocks until the HTTP request is completed.  The default
  241
+  handler function returns a ByteArrayOutputStream."
  242
+  [http-agnt]
  243
+  (await http-agnt)
  244
+  (::result @http-agnt))
  245
+
  246
+(defn stream
  247
+  "Returns an InputStream of the HTTP response body.  When called by
  248
+  the handler function passed to http-agent, this is the raw
  249
+  HttpURLConnection stream.
  250
+
  251
+  If the default handler function was used, this function returns a
  252
+  ByteArrayInputStream on the buffered response body."
  253
+  [http-agnt]
  254
+  (let [a @http-agnt]
  255
+    (if (= (::state a) ::receiving)
  256
+      (::response-stream a)
  257
+      (ByteArrayInputStream.
  258
+       (.toByteArray (get-byte-buffer http-agnt))))))
  259
+
  260
+(defn bytes
  261
+  "Returns a Java byte array of the content returned by the server;
  262
+  nil if the content is not yet available."
  263
+  [http-agnt]
  264
+  (.toByteArray (get-byte-buffer http-agnt)))
  265
+
  266
+(defn string
  267
+  "Returns the HTTP response body as a string, using the given
  268
+  encoding.
  269
+
  270
+  If no encoding is given, uses the encoding specified in the server
  271
+  headers, or clojure.contrib.io/*default-encoding* if it is
  272
+  not specified."
  273
+  ([http-agnt]
  274
+     (await http-agnt) ;; have to wait for Content-Encoding
  275
+     (string http-agnt (or (.getContentEncoding
  276
+                            ^HttpURLConnection (::connection @http-agnt))
  277
+                           duck/*default-encoding*)))
  278
+  ([http-agnt ^String encoding]
  279
+     (.toString (get-byte-buffer http-agnt) encoding)))
  280
+
  281
+
  282
+;;; REQUEST ACCESSORS
  283
+
  284
+(defn request-uri
  285
+  "Returns the URI/URL requested by this HTTP agent, as a String."
  286
+  [http-agnt]
  287
+  (::uri @http-agnt))
  288
+
  289
+(defn request-headers
  290
+  "Returns the request headers specified for this HTTP agent."
  291
+  [http-agnt]
  292
+  (:headers (::options @http-agnt)))
  293
+
  294
+(defn method
  295
+  "Returns the HTTP method name used by this HTTP agent, as a String."
  296
+  [http-agnt]
  297
+  (:method (::options @http-agnt)))
  298
+
  299
+(defn request-body
  300
+  "Returns the HTTP request body given to this HTTP agent.  
  301
+
  302
+  Note: if the request body was an InputStream or a Reader, it will no
  303
+  longer be usable."
  304
+  [http-agnt]
  305
+  (:body (::options @http-agnt)))
  306
+
  307
+
  308
+;;; RESPONSE ACCESSORS
  309
+
  310
+(defn done?
  311
+  "Returns true if the HTTP request/response has completed."
  312
+  [http-agnt]
  313
+  (if (#{::finished ::disconnected} (::state @http-agnt))
  314
+    true false))
  315
+
  316
+(defn status
  317
+  "Returns the HTTP response status code (e.g. 200, 404) for this
  318
+  request, as an Integer, or nil if the status has not yet been
  319
+  received."
  320
+  [http-agnt]
  321
+  (when (done? http-agnt)
  322
+    (.getResponseCode ^HttpURLConnection (::connection @http-agnt))))
  323
+
  324
+(defn message
  325
+  "Returns the HTTP response message (e.g. 'Not Found'), for this
  326
+  request, or nil if the response has not yet been received."
  327
+  [http-agnt]
  328
+  (when (done? http-agnt)
  329
+    (.getResponseMessage ^HttpURLConnection (::connection @http-agnt))))
  330
+
  331
+(defn headers
  332
+  "Returns a map of HTTP response headers.  Header names are converted
  333
+  to keywords in all lower-case Header values are strings.  If a
  334
+  header appears more than once, only the last value is returned."
  335
+  [http-agnt]
  336
+  (reduce (fn [m [^String k v]]
  337
+            (assoc m (when k (keyword (.toLowerCase k))) (last v)))
  338
+          {} (.getHeaderFields
  339
+              ^HttpURLConnection (::connection @http-agnt))))
  340
+
  341
+(defn headers-seq
  342
+  "Returns the HTTP response headers in order as a sequence of
  343
+  [String,String] pairs.  The first 'header' name may be null for the
  344
+  HTTP status line."
  345
+  [http-agnt]
  346
+  (let [^HttpURLConnection conn (::connection @http-agnt)
  347
+        f (fn thisfn [^Integer i]
  348
+            ;; Get value first because first key may be nil.
  349
+            (when-let [value (.getHeaderField conn i)]
  350
+              (cons [(.getHeaderFieldKey conn i) value]
  351
+                    (thisfn (inc i)))))]
  352
+    (lazy-seq (f 0))))
  353
+
  354
+
  355
+;;; RESPONSE STATUS CODE ACCESSORS
  356
+
  357
+(defn success?
  358
+  "Returns true if the HTTP response code was in the 200-299 range."
  359
+  [http-agnt]
  360
+  (status-in-range? 2 http-agnt))
  361
+
  362
+(defn redirect?
  363
+  "Returns true if the HTTP response code was in the 300-399 range.
  364
+
  365
+  Note: if the :follow-redirects option was true (the default),
  366
+  redirects will be followed automatically and a the agent will never
  367
+  return a 3xx response code."
  368
+  [http-agnt]
  369
+  (status-in-range? 3 http-agnt))
  370
+
  371
+(defn client-error?
  372
+  "Returns true if the HTTP response code was in the 400-499 range."
  373
+  [http-agnt]
  374
+  (status-in-range? 4 http-agnt))
  375
+
  376
+(defn server-error?
  377
+  "Returns true if the HTTP response code was in the 500-599 range."
  378
+  [http-agnt]
  379
+  (status-in-range? 5 http-agnt))
  380
+
  381
+(defn error?
  382
+  "Returns true if the HTTP response code was in the 400-499 range OR
  383
+  the 500-599 range."
  384
+  [http-agnt]
  385
+  (or (client-error? http-agnt)
  386
+      (server-error? http-agnt)))
21  modules/http-connection/pom.xml
... ...
@@ -0,0 +1,21 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
  3
+         xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5
+                             http://maven.apache.org/maven-v4_0_0.xsd">
  6
+  <modelVersion>4.0.0</modelVersion>
  7
+  <parent>
  8
+    <groupId>org.clojure.contrib</groupId>
  9
+    <artifactId>parent</artifactId>
  10
+    <version>1.3.0-SNAPSHOT</version>
  11
+    <relativePath>../parent</relativePath>
  12
+  </parent>
  13
+  <artifactId>http-connection</artifactId>
  14
+  <dependencies>
  15
+    <dependency>
  16
+      <groupId>org.clojure.contrib</groupId>
  17
+      <artifactId>io</artifactId>
  18
+      <version>1.3.0-SNAPSHOT</version>
  19
+    </dependency>
  20
+  </dependencies>
  21
+</project>
62  modules/http-connection/src/main/clojure/clojure/contrib/http/connection.clj
... ...
@@ -0,0 +1,62 @@
  1
+;;; http/connection.clj: low-level HTTP client API around HttpURLConnection
  2
+
  3
+;; by Stuart Sierra, http://stuartsierra.com/
  4
+;; June 8, 2009
  5
+
  6
+;; Copyright (c) Stuart Sierra, 2009. All rights reserved.  The use
  7
+;; and distribution terms for this software are covered by the Eclipse
  8
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  9
+;; which can be found in the file epl-v10.html at the root of this
  10
+;; distribution.  By using this software in any fashion, you are
  11
+;; agreeing to be bound by the terms of this license.  You must not
  12
+;; remove this notice, or any other, from this software.
  13
+
  14
+;; DEPRECATED IN 1.2. Use direct Java bits, or take a look at
  15
+;;                    http://github.com/technomancy/clojure-http-client
  16
+
  17
+(ns ^{:deprecated "1.2"
  18
+      :doc "Low-level HTTP client API around HttpURLConnection"}
  19
+  clojure.contrib.http.connection
  20
+  (:require [clojure.contrib.io :as duck])
  21
+  (:import (java.net URI URL HttpURLConnection)
  22
+           (java.io File InputStream Reader)))
  23
+
  24
+(defn http-connection
  25
+  "Opens an HttpURLConnection at the URL, handled by as-url."
  26
+  [url]
  27
+  (.openConnection (duck/as-url url)))
  28
+
  29
+(defmulti
  30
+  ^{:doc "Transmits a request entity body."}
  31
+  send-request-entity (fn [conn entity] (type entity)))
  32
+
  33
+(defmethod send-request-entity duck/*byte-array-type* [^HttpURLConnection conn entity]
  34
+  (.setFixedLengthStreamingMode conn (count entity))
  35
+  (.connect conn)
  36
+  (duck/copy entity (.getOutputStream conn)))
  37
+
  38
+(defmethod send-request-entity String [conn ^String entity]
  39
+  (send-request-entity conn (.getBytes entity duck/*default-encoding*)))
  40
+
  41
+(defmethod send-request-entity File [^HttpURLConnection conn ^File entity]
  42
+  (.setFixedLengthStreamingMode conn (.length entity))
  43
+  (.connect conn)
  44
+  (duck/copy entity (.getOutputStream conn)))
  45
+
  46
+(defmethod send-request-entity InputStream [^HttpURLConnection conn entity]
  47
+  (.setChunkedStreamingMode conn -1)
  48
+  (.connect conn)
  49
+  (duck/copy entity (.getOutputStream conn)))
  50
+
  51
+(defmethod send-request-entity Reader [^HttpURLConnection conn entity]
  52
+  (.setChunkedStreamingMode conn -1)
  53
+  (.connect conn)
  54
+  (duck/copy entity (.getOutputStream conn)))
  55
+
  56
+(defn start-http-connection
  57
+  ([^HttpURLConnection conn] (.connect conn))
  58
+  ([^HttpURLConnection conn request-entity-body]
  59
+     (if request-entity-body
  60
+       (do (.setDoOutput conn true)
  61
+           (send-request-entity conn request-entity-body))
  62
+       (.connect conn))))
26  modules/javadoc/pom.xml
... ...
@@ -0,0 +1,26 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
  3
+         xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5
+                             http://maven.apache.org/maven-v4_0_0.xsd">
  6
+  <modelVersion>4.0.0</modelVersion>
  7
+  <parent>
  8
+    <groupId>org.clojure.contrib</groupId>
  9
+    <artifactId>parent</artifactId>
  10
+    <version>1.3.0-SNAPSHOT</version>
  11
+    <relativePath>../parent</relativePath>
  12
+  </parent>
  13
+  <artifactId>javadoc</artifactId>
  14
+  <dependencies>
  15
+    <dependency>
  16
+      <groupId>org.clojure.contrib</groupId>
  17
+      <artifactId>shell</artifactId>
  18
+      <version>1.3.0-SNAPSHOT</version>
  19
+    </dependency>
  20
+    <dependency>
  21
+      <groupId>org.clojure.contrib</groupId>
  22
+      <artifactId>def</artifactId>
  23
+      <version>1.3.0-SNAPSHOT</version>
  24
+    </dependency>
  25
+  </dependencies>
  26
+</project>
4  modules/javadoc/src/main/clojure/clojure/contrib/javadoc.clj
... ...
@@ -0,0 +1,4 @@
  1
+(ns ^{:deprecated "1.2"}
  2
+  clojure.contrib.javadoc)
  3
+
  4
+(throw (Exception. "clojure.contrib.javadoc/javadoc can now be found in clojure.java.javadoc"))
51  modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse.clj
... ...
@@ -0,0 +1,51 @@
  1
+;;; browse.clj -- start a web browser from Clojure
  2
+
  3
+;   Copyright (c) Christophe Grand, December 2008. All rights reserved.
  4
+;   The use and distribution terms for this software are covered by the
  5
+;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  6
+;   which can be found in the file epl-v10.html at the root of this 
  7
+;   distribution.
  8
+;   By using this software in any fashion, you are agreeing to be bound by
  9
+;   the terms of this license.
  10
+;   You must not remove this notice, or any other, from this software.
  11
+
  12
+(ns 
  13
+  ^{:author "Christophe Grand",
  14
+    :deprecated "1.2"
  15
+    :doc "Start a web browser from Clojure"}
  16
+  clojure.contrib.javadoc.browse
  17
+  (:require [clojure.contrib.shell :as sh]) 
  18
+  (:import (java.net URI)))
  19
+
  20
+(defn- macosx? []
  21
+  (-> "os.name" System/getProperty .toLowerCase
  22
+    (.startsWith "mac os x")))
  23
+
  24
+(def *open-url-script* (when (macosx?) "/usr/bin/open"))
  25
+
  26
+(defn open-url-in-browser
  27
+  "Opens url (a string) in the default system web browser.  May not
  28
+  work on all platforms.  Returns url on success, nil if not
  29
+  supported."
  30
+  [url]
  31
+  (try 
  32
+    (when (clojure.lang.Reflector/invokeStaticMethod "java.awt.Desktop" 
  33
+      "isDesktopSupported" (to-array nil))
  34
+      (-> (clojure.lang.Reflector/invokeStaticMethod "java.awt.Desktop" 
  35
+            "getDesktop" (to-array nil))
  36
+        (.browse (URI. url)))
  37
+      url)
  38
+    (catch ClassNotFoundException e
  39
+      nil)))        
  40
+
  41
+(defn open-url-in-swing
  42
+ "Opens url (a string) in a Swing window."
  43
+ [url]
  44
+  ; the implementation of this function resides in another namespace to be loaded "on demand"
  45
+  ; this fixes a bug on mac os x where requiring repl-utils turns the process into a GUI app
  46
+  ; see http://code.google.com/p/clojure-contrib/issues/detail?id=32
  47
+  (require 'clojure.contrib.javadoc.browse-ui)
  48
+  ((find-var 'clojure.contrib.javadoc.browse-ui/open-url-in-swing) url))
  49
+
  50
+(defn browse-url [url]
  51
+  (or (open-url-in-browser url) (when *open-url-script* (sh/sh *open-url-script* (str url)) true) (open-url-in-swing url)))
31  modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse_ui.clj
... ...
@@ -0,0 +1,31 @@
  1
+;;; browse_ui.clj -- starts a swing web browser :-(
  2
+
  3
+;   Copyright (c) Christophe Grand, December 2008. All rights reserved.
  4
+;   The use and distribution terms for this software are covered by the
  5
+;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  6
+;   which can be found in the file epl-v10.html at the root of this 
  7
+;   distribution.
  8
+;   By using this software in any fashion, you are agreeing to be bound by
  9
+;   the terms of this license.
  10
+;   You must not remove this notice, or any other, from this software.
  11
+
  12
+(ns ^{:deprecated "1.2"}
  13
+  clojure.contrib.javadoc.browse-ui)
  14
+
  15
+(defn open-url-in-swing
  16
+  "Opens url (a string) in a Swing window."
  17
+  [url]
  18
+  (let [htmlpane (javax.swing.JEditorPane. url)]
  19
+    (.setEditable htmlpane false)
  20
+    (.addHyperlinkListener htmlpane
  21
+      (proxy [javax.swing.event.HyperlinkListener] []
  22
+        (hyperlinkUpdate [^javax.swing.event.HyperlinkEvent e]
  23
+          (when (= (.getEventType e) (. javax.swing.event.HyperlinkEvent$EventType ACTIVATED))
  24
+            (if (instance? javax.swing.text.html.HTMLFrameHyperlinkEvent e)
  25
+              (-> htmlpane .getDocument (.processHTMLFrameHyperlinkEvent e))
  26
+              (.setPage htmlpane (.getURL e)))))))
  27
+    (doto (javax.swing.JFrame.)
  28
+      (.setContentPane (javax.swing.JScrollPane. htmlpane))
  29
+      (.setBounds 32 32 700 900)
  30
+      (.show))))
  31
+      
26  modules/properties/pom.xml
... ...
@@ -0,0 +1,26 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
  3
+         xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5
+                             http://maven.apache.org/maven-v4_0_0.xsd">
  6
+  <modelVersion>4.0.0</modelVersion>
  7
+  <parent>
  8
+    <groupId>org.clojure.contrib</groupId>
  9
+    <artifactId>parent</artifactId>
  10
+    <version>1.3.0-SNAPSHOT</version>
  11
+    <relativePath>../parent</relativePath>
  12
+  </parent>
  13
+  <artifactId>properties</artifactId>
  14
+  <dependencies>
  15
+    <dependency>
  16
+      <groupId>org.clojure.contrib</groupId>
  17
+      <artifactId>io</artifactId>
  18
+      <version>1.3.0-SNAPSHOT</version>
  19
+    </dependency>
  20
+    <dependency>
  21
+      <groupId>org.clojure.contrib</groupId>
  22
+      <artifactId>string</artifactId>
  23
+      <version>1.3.0-SNAPSHOT</version>
  24
+    </dependency>
  25
+  </dependencies>
  26
+</project>
77  modules/properties/src/main/clojure/clojure/contrib/properties.clj
... ...
@@ -0,0 +1,77 @@
  1
+;   Copyright (c) Stuart Halloway & Contributors, April 2009. All rights reserved.
  2
+;   The use and distribution terms for this software are covered by the
  3
+;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  4
+;   which can be found in the file epl-v10.html at the root of this distribution.
  5
+;   By using this software in any fashion, you are agreeing to be bound by
  6
+;   the terms of this license.
  7
+;   You must not remove this notice, or any other, from this software.
  8
+
  9
+;; DEPRECATED in 1.2.  Moved to c.c.java-utils
  10
+
  11
+(ns ^{:deprecated "1.2"}
  12
+  clojure.contrib.properties
  13
+  (:use [clojure.contrib.string :only (as-str)]
  14
+        [clojure.contrib.io :only (file)])
  15
+  (:import (java.util Properties)
  16
+           (java.io FileInputStream FileOutputStream)))
  17
+
  18
+(defn get-system-property 
  19
+  "Get a system property."
  20
+  ([stringable]
  21
+   (System/getProperty (as-str stringable)))
  22
+  ([stringable default]
  23
+   (System/getProperty (as-str stringable) default)))
  24
+
  25
+(defn set-system-properties
  26
+  "Set some system properties. Nil clears a property."
  27
+  [settings]
  28
+  (doseq [[name val] settings]
  29
+    (if val
  30
+      (System/setProperty (as-str name) (as-str val))
  31
+      (System/clearProperty (as-str name)))))
  32
+
  33
+(defmacro with-system-properties
  34
+  "setting => property-name value
  35
+
  36
+  Sets the system properties to the supplied values, executes the body, and
  37
+  sets the properties back to their original values. Values of nil are
  38
+  translated to a clearing of the property."
  39
+  [settings & body]
  40
+  `(let [settings# ~settings
  41
+         current# (reduce (fn [coll# k#]
  42
+			    (assoc coll# k# (get-system-property k#)))
  43
+			  {}
  44
+			  (keys settings#))]
  45
+     (set-system-properties settings#)       
  46
+     (try
  47
+      ~@body
  48
+      (finally
  49
+       (set-system-properties current#)))))
  50
+
  51
+
  52
+; Not there is no corresponding props->map. Just destructure!
  53
+(defn ^Properties as-properties
  54
+  "Convert any seq of pairs to a java.utils.Properties instance.
  55
+   Uses as-str to convert both keys and values into strings."
  56
+  {:tag Properties}
  57
+  [m]
  58
+  (let [p (Properties.)]
  59
+    (doseq [[k v] m]
  60
+      (.setProperty p (as-str k) (as-str v)))
  61
+    p))
  62
+
  63
+(defn read-properties
  64
+  "Read properties from file-able."
  65
+  [file-able]
  66
+  (with-open [f (java.io.FileInputStream. (file file-able))]
  67
+    (doto (Properties.)
  68
+      (.load f))))
  69
+
  70
+(defn write-properties
  71
+  "Write properties to file-able."
  72
+  {:tag Properties}
  73
+  ([m file-able] (write-properties m file-able nil))
  74
+  ([m file-able comments]
  75
+    (with-open [^FileOutputStream f (FileOutputStream. (file file-able))]
  76
+      (doto (as-properties m)
  77
+        (.store f ^String comments)))))
63  modules/properties/src/test/clojure/clojure/contrib/test_properties.clj
... ...
@@ -0,0 +1,63 @@
  1
+(ns clojure.contrib.test-properties
  2
+  (:refer-clojure :exclude (spit))
  3
+  (:use clojure.test clojure.contrib.properties
  4
+        [clojure.contrib.io :only (spit)])
  5
+  (:import (java.util Properties)
  6
+           (java.io File)))
  7
+
  8
+(deftest test-get-system-property
  9
+  (testing "works the same with keywords, symbols, and strings"
  10
+    (is (= (get-system-property "java.home") (get-system-property 'java.home)))
  11
+    (is (= (get-system-property "java.home") (get-system-property :java.home))))
  12
+  (testing "treats second arg as default"
  13
+    (is (= "default" (get-system-property "testing.test-system-property" "default"))))
  14
+  (testing "returns nil for missing properties"
  15
+    (is (nil? (get-system-property "testing.test-system-property")))))
  16
+
  17
+(deftest test-set-system-properties 
  18
+  (testing "set and then unset a property using keywords"
  19
+           (let [propname :clojure.contrib.java.test-set-system-properties]
  20
+             (is (nil? (get-system-property propname)))
  21
+             (set-system-properties {propname :foo})
  22
+             (is (= "foo") (get-system-property propname))
  23
+             (set-system-properties {propname nil})
  24
+             (is (nil? (get-system-property propname))))))
  25
+
  26
+(deftest test-with-system-properties
  27
+  (let [propname :clojure.contrib.java.test-with-system-properties]
  28
+    (testing "sets a property only for the duration of a block"
  29
+      (is (= "foo" 
  30
+	     (with-system-properties {propname "foo"}
  31
+	       (get-system-property propname))))
  32
+      (is (nil? (get-system-property propname)))))
  33
+  (testing "leaves other properties alone"
  34
+    ; TODO: write this test better, using a properties -> map function
  35
+    (let [propname :clojure.contrib.java.test-with-system-properties
  36
+          propcount (count (System/getProperties))]
  37
+      (with-system-properties {propname "foo"}
  38
+        (is (= (inc propcount) (count (System/getProperties)))))
  39
+      (is (= propcount (count (System/getProperties)))))))
  40
+
  41
+(deftest test-as-properties
  42
+  (let [expected (doto (Properties.)
  43
+		   (.setProperty "a" "b")
  44
+		   (.setProperty "c" "d"))]
  45
+    (testing "with a map"
  46
+      (is (= expected
  47
+	     (as-properties {:a "b" :c "d"}))))
  48
+    (testing "with a sequence of pairs"
  49
+      (is (= expected
  50
+	     (as-properties [[:a :b] [:c :d]]))))))
  51
+
  52
+(deftest test-read-properties
  53
+  (let [f (File/createTempFile "test" "properties")]
  54
+    (spit f "a=b\nc=d")
  55
+    (is (= {"a" "b" "c" "d"}
  56
+	   (read-properties f)))))
  57
+	   
  58
+(deftest test-write-properties
  59
+  (let [f (File/createTempFile "test" "properties")]
  60
+    (write-properties [['a 'b] ['c 'd]] f)
  61
+    (is (= {"a" "b" "c" "d"}
  62
+	   (read-properties f)))))
  63
+	   
16  modules/test-is/pom.xml
... ...
@@ -0,0 +1,16 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
  3
+         xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5
+                             http://maven.apache.org/maven-v4_0_0.xsd">
  6
+  <modelVersion>4.0.0</modelVersion>
  7
+  <parent>
  8
+    <groupId>org.clojure.contrib</groupId>
  9
+    <artifactId>parent</artifactId>
  10
+    <version>1.3.0-SNAPSHOT</version>
  11
+    <relativePath>../parent</relativePath>
  12
+  </parent>
  13
+  <artifactId>test-is</artifactId>
  14
+  <dependencies>
  15
+  </dependencies>
  16
+</project>
119  modules/test-is/src/main/clojure/clojure/contrib/test_is.clj
... ...
@@ -0,0 +1,119 @@
  1
+;;; test_is.clj: Compatibility layer for old clojure.contrib.test-is
  2
+
  3
+;; by Stuart Sierra, http://stuartsierra.com/
  4
+;; August 28, 2009
  5
+
  6
+;; Copyright (c) Stuart Sierra, 2009. All rights reserved.  The use
  7
+;; and distribution terms for this software are covered by the Eclipse
  8
+;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  9
+;; which can be found in the file epl-v10.html at the root of this
  10
+;; distribution.  By using this software in any fashion, you are
  11
+;; agreeing to be bound by the terms of this license.  You must not
  12
+;; remove this notice, or any other, from this software.
  13
+
  14
+;; DEPRECATED in 1.2: Moved to clojure.test
  15
+
  16
+(ns ^{:deprecated "1.2"
  17
+      :doc "Backwards-compatibility for clojure.contrib.test-is
  18
+
  19
+  The clojure.contrib.test-is library moved from Contrib into the
  20
+  Clojure distribution as clojure.test.
  21
+
  22
+  This happened on or around clojure-contrib Git commit
  23
+  82cf0409d0fcb71be477ebfc4da18ee2128a2ad1 on June 25, 2009.
  24
+
  25
+  This file makes the clojure.test interface available under the old
  26
+  namespace clojure.contrib.test-is.
  27
+
  28
+  This includes support for the old syntax of the 'are' macro.
  29
+
  30
+  This was suggested by Howard Lewis Ship in ticket #26, 
  31
+  http://www.assembla.com/spaces/clojure-contrib/tickets/26"
  32
+       :author "Stuart Sierra"}
  33
+    clojure.contrib.test-is
  34
+    (:require clojure.test
  35
+              [clojure.walk :as walk]))
  36
+
  37
+
  38
+;;; COPY INTERNED VARS (EXCEPT are) FROM clojure.test
  39
+
  40
+(doseq [v (disj (set (vals (ns-interns 'clojure.test)))
  41
+                #'clojure.test/are)]
  42
+  (intern *ns* (with-meta (:name (meta v)) (meta v)) (var-get v)))
  43
+
  44
+
  45
+;;; REDEFINE OLD clojure.contrib.template 
  46
+
  47
+(defn find-symbols
  48
+  "Recursively finds all symbols in form."
  49
+  [form]
  50
+  (distinct (filter symbol? (tree-seq coll? seq form))))
  51
+
  52
+(defn find-holes
  53
+  "Recursively finds all symbols starting with _ in form."
  54
+  [form]
  55
+  (sort (distinct (filter #(.startsWith (name %) "_")
  56
+                          (find-symbols form)))))
  57
+
  58
+(defn find-pure-exprs
  59
+  "Recursively finds all sub-expressions in form that do not contain
  60
+  any symbols starting with _"
  61
+  [form]
  62
+  (filter #(and (list? %)
  63
+                (empty? (find-holes %)))
  64
+          (tree-seq seq? seq form)))
  65
+
  66
+(defn flatten-map
  67
+  "Transforms a map into a vector like [key value key value]."
  68
+  [m]
  69
+  (reduce (fn [coll [k v]] (conj coll k v))
  70
+          [] m))
  71
+
  72
+(defn template?
  73
+  "Returns true if form is a valid template expression."
  74
+  [form]
  75
+  (if (seq (find-holes form)) true false))
  76
+
  77
+(defn apply-template
  78
+  "Replaces _1, _2, _3, etc. in expr with corresponding elements of
  79
+  values.  Returns the modified expression.  For use in macros."
  80
+  [expr values]
  81
+  (when-not (template? expr)
  82
+    (throw (IllegalArgumentException. (str (pr-str expr) " is not a valid template."))))
  83
+  (let [expr (walk/postwalk-replace {'_ '_1} expr)
  84
+        holes (find-holes expr)
  85
+        smap (zipmap holes values)]
  86
+    (walk/prewalk-replace smap expr)))
  87
+
  88
+(defmacro do-template
  89
+  "Repeatedly evaluates template expr (in a do block) using values in
  90
+  args.  args are grouped by the number of holes in the template.
  91
+  Example: (do-template (check _1 _2) :a :b :c :d)
  92
+  expands to (do (check :a :b) (check :c :d))"
  93
+  [expr & args]
  94
+  (when-not (template? expr)
  95
+    (throw (IllegalArgumentException. (str (pr-str expr) " is not a valid template."))))
  96
+  (let [expr (walk/postwalk-replace {'_ '_1} expr)
  97
+        argcount (count (find-holes expr))]
  98
+    `(do ~@(map (fn [a] (apply-template expr a))
  99
+                (partition argcount args)))))
  100
+
  101
+
  102
+
  103
+;;; REDEFINE are MACRO TO MATCH OLD TEMPLATE BEHAVIOR
  104
+
  105
+(defmacro are
  106
+  "Checks multiple assertions with a template expression.
  107
+  See clojure.contrib.template/do-template for an explanation of
  108
+  templates.
  109
+
  110
+  Example: (are (= _1 _2)  
  111
+                2 (+ 1 1)
  112
+                4 (* 2 2))
  113
+  Expands to: 
  114
+           (do (is (= 2 (+ 1 1)))
  115
+               (is (= 4 (* 2 2))))
  116
+
  117
+  Note: This breaks some reporting features, such as line numbers."
  118
+  [expr & args]
  119
+  `(do-template (is ~expr) ~@args))
6  pom.xml
@@ -24,6 +24,7 @@
24 24
 
25 25
     <module>modules/accumulators</module>
26 26
     <module>modules/agent-utils</module>
  27
+    <module>modules/apply-macro</module>
27 28
     <module>modules/base64</module>
28 29
     <module>modules/classpath</module>
29 30
     <module>modules/combinatorics</module>
@@ -45,10 +46,13 @@
45 46
     <module>modules/generic</module>
46 47
     <module>modules/graph</module>
47 48
     <module>modules/greatest-least</module>
  49
+    <module>modules/http-agent</module>
  50
+    <module>modules/http-connection</module>
48 51
     <module>modules/import-static</module>
49 52
     <module>modules/io</module>
50 53
     <module>modules/jar</module>
51 54
     <module>modules/java-utils</module>
  55
+    <module>modules/javadoc</module>
52 56
     <module>modules/jmx</module>
53 57
     <module>modules/json</module>
54 58
     <module>modules/lazy-seqs</module>
@@ -68,6 +72,7 @@
68 72
     <module>modules/priority-map</module>
69 73
     <module>modules/probabilities</module>
70 74
     <module>modules/profile</module>
  75
+    <module>modules/properties</module>
71 76
     <module>modules/prxml</module>
72 77
     <module>modules/reflect</module>
73 78
     <module>modules/repl-ln</module>
@@ -86,6 +91,7 @@
86 91
     <module>modules/string</module>
87 92
     <module>modules/strint</module>
88 93
     <module>modules/swing-utils</module>
  94
+    <module>modules/test-is</module>
89 95
     <module>modules/trace</module>
90 96