rlm@10
|
1 ; Copyright (c) Stuart Halloway & Contributors, April 2009. All rights reserved.
|
rlm@10
|
2 ; The use and distribution terms for this software are covered by the
|
rlm@10
|
3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
4 ; which can be found in the file epl-v10.html at the root of this distribution.
|
rlm@10
|
5 ; By using this software in any fashion, you are agreeing to be bound by
|
rlm@10
|
6 ; the terms of this license.
|
rlm@10
|
7 ; You must not remove this notice, or any other, from this software.
|
rlm@10
|
8
|
rlm@10
|
9 ;;
|
rlm@10
|
10 ;; CHANGELOG
|
rlm@10
|
11 ;;
|
rlm@10
|
12 ;; Most functions deprecated in 1.2. Some already exist in c.c.io, and
|
rlm@10
|
13 ;; some replaced by c.c.reflections
|
rlm@10
|
14
|
rlm@10
|
15 (ns
|
rlm@10
|
16 ^{:author "Stuart Halloway, Stephen C. Gilardi, Shawn Hoover, Perry Trolard, Stuart Sierra",
|
rlm@10
|
17 :doc "A set of utilties for dealing with Java stuff like files and properties.
|
rlm@10
|
18
|
rlm@10
|
19 Design goals:
|
rlm@10
|
20
|
rlm@10
|
21 (1) Ease-of-use. These APIs should be convenient. Performance is secondary.
|
rlm@10
|
22
|
rlm@10
|
23 (2) Duck typing. I hate having to think about the difference between
|
rlm@10
|
24 a string that names a file, and a File. Ditto for a ton of other
|
rlm@10
|
25 wrapper classes in the Java world (URL, InternetAddress). With these
|
rlm@10
|
26 APIs you should be able to think about domain equivalence, not type
|
rlm@10
|
27 equivalence.
|
rlm@10
|
28
|
rlm@10
|
29 (3) No bossiness. I am not marking any of these functions as private
|
rlm@10
|
30 the docstrings will tell you the intended usage but do what works for you.
|
rlm@10
|
31
|
rlm@10
|
32 Feedback welcome!
|
rlm@10
|
33
|
rlm@10
|
34 If something in this module violates the principle of least surprise, please
|
rlm@10
|
35 let me (Stu) and the Clojure community know via the mailing list.
|
rlm@10
|
36 Contributors:
|
rlm@10
|
37
|
rlm@10
|
38 Stuart Halloway
|
rlm@10
|
39 Stephen C. Gilardi
|
rlm@10
|
40 Shawn Hoover
|
rlm@10
|
41 Perry Trolard
|
rlm@10
|
42 Stuart Sierra
|
rlm@10
|
43 "}
|
rlm@10
|
44 clojure.contrib.java-utils
|
rlm@10
|
45 (:import [java.io File FileOutputStream]
|
rlm@10
|
46 [java.util Properties]
|
rlm@10
|
47 [java.net URI URL]))
|
rlm@10
|
48
|
rlm@10
|
49 (defmulti relative-path-string
|
rlm@10
|
50 "Interpret a String or java.io.File as a relative path string.
|
rlm@10
|
51 Building block for clojure.contrib.java-utils/file."
|
rlm@10
|
52 {:deprecated "1.2"}
|
rlm@10
|
53 class)
|
rlm@10
|
54
|
rlm@10
|
55 (defmethod relative-path-string String [^String s]
|
rlm@10
|
56 (relative-path-string (File. s)))
|
rlm@10
|
57
|
rlm@10
|
58 (defmethod relative-path-string File [^File f]
|
rlm@10
|
59 (if (.isAbsolute f)
|
rlm@10
|
60 (throw (IllegalArgumentException. (str f " is not a relative path")))
|
rlm@10
|
61 (.getPath f)))
|
rlm@10
|
62
|
rlm@10
|
63 (defmulti ^File as-file
|
rlm@10
|
64 "Interpret a String or a java.io.File as a File. Building block
|
rlm@10
|
65 for clojure.contrib.java-utils/file, which you should prefer
|
rlm@10
|
66 in most cases."
|
rlm@10
|
67 {:deprecated "1.2"}
|
rlm@10
|
68 class)
|
rlm@10
|
69 (defmethod as-file String [^String s] (File. s))
|
rlm@10
|
70 (defmethod as-file File [f] f)
|
rlm@10
|
71
|
rlm@10
|
72 (defn ^File file
|
rlm@10
|
73 "Returns a java.io.File from string or file args."
|
rlm@10
|
74 {:deprecated "1.2"}
|
rlm@10
|
75 ([arg]
|
rlm@10
|
76 (as-file arg))
|
rlm@10
|
77 ([parent child]
|
rlm@10
|
78 (File. ^File (as-file parent) ^String (relative-path-string child)))
|
rlm@10
|
79 ([parent child & more]
|
rlm@10
|
80 (reduce file (file parent child) more)))
|
rlm@10
|
81
|
rlm@10
|
82 (defn as-str
|
rlm@10
|
83 "Like clojure.core/str, but if an argument is a keyword or symbol,
|
rlm@10
|
84 its name will be used instead of its literal representation.
|
rlm@10
|
85
|
rlm@10
|
86 Example:
|
rlm@10
|
87 (str :foo :bar) ;;=> \":foo:bar\"
|
rlm@10
|
88 (as-str :foo :bar) ;;=> \"foobar\"
|
rlm@10
|
89
|
rlm@10
|
90 Note that this does not apply to keywords or symbols nested within
|
rlm@10
|
91 data structures; they will be rendered as with str.
|
rlm@10
|
92
|
rlm@10
|
93 Example:
|
rlm@10
|
94 (str {:foo :bar}) ;;=> \"{:foo :bar}\"
|
rlm@10
|
95 (as-str {:foo :bar}) ;;=> \"{:foo :bar}\" "
|
rlm@10
|
96 {:deprecated "1.2"}
|
rlm@10
|
97 ([] "")
|
rlm@10
|
98 ([x] (if (instance? clojure.lang.Named x)
|
rlm@10
|
99 (name x)
|
rlm@10
|
100 (str x)))
|
rlm@10
|
101 ([x & ys]
|
rlm@10
|
102 ((fn [^StringBuilder sb more]
|
rlm@10
|
103 (if more
|
rlm@10
|
104 (recur (. sb (append (as-str (first more)))) (next more))
|
rlm@10
|
105 (str sb)))
|
rlm@10
|
106 (new StringBuilder ^String (as-str x)) ys)))
|
rlm@10
|
107
|
rlm@10
|
108 (defn get-system-property
|
rlm@10
|
109 "Get a system property."
|
rlm@10
|
110 ([stringable]
|
rlm@10
|
111 (System/getProperty (as-str stringable)))
|
rlm@10
|
112 ([stringable default]
|
rlm@10
|
113 (System/getProperty (as-str stringable) default)))
|
rlm@10
|
114
|
rlm@10
|
115 (defn set-system-properties
|
rlm@10
|
116 "Set some system properties. Nil clears a property."
|
rlm@10
|
117 [settings]
|
rlm@10
|
118 (doseq [[name val] settings]
|
rlm@10
|
119 (if val
|
rlm@10
|
120 (System/setProperty (as-str name) (as-str val))
|
rlm@10
|
121 (System/clearProperty (as-str name)))))
|
rlm@10
|
122
|
rlm@10
|
123 (defmacro with-system-properties
|
rlm@10
|
124 "setting => property-name value
|
rlm@10
|
125
|
rlm@10
|
126 Sets the system properties to the supplied values, executes the body, and
|
rlm@10
|
127 sets the properties back to their original values. Values of nil are
|
rlm@10
|
128 translated to a clearing of the property."
|
rlm@10
|
129 [settings & body]
|
rlm@10
|
130 `(let [settings# ~settings
|
rlm@10
|
131 current# (reduce (fn [coll# k#]
|
rlm@10
|
132 (assoc coll# k# (get-system-property k#)))
|
rlm@10
|
133 {}
|
rlm@10
|
134 (keys settings#))]
|
rlm@10
|
135 (set-system-properties settings#)
|
rlm@10
|
136 (try
|
rlm@10
|
137 ~@body
|
rlm@10
|
138 (finally
|
rlm@10
|
139 (set-system-properties current#)))))
|
rlm@10
|
140
|
rlm@10
|
141
|
rlm@10
|
142 ; Not there is no corresponding props->map. Just destructure!
|
rlm@10
|
143 (defn ^Properties as-properties
|
rlm@10
|
144 "Convert any seq of pairs to a java.utils.Properties instance.
|
rlm@10
|
145 Uses as-str to convert both keys and values into strings."
|
rlm@10
|
146 {:tag Properties}
|
rlm@10
|
147 [m]
|
rlm@10
|
148 (let [p (Properties.)]
|
rlm@10
|
149 (doseq [[k v] m]
|
rlm@10
|
150 (.setProperty p (as-str k) (as-str v)))
|
rlm@10
|
151 p))
|
rlm@10
|
152
|
rlm@10
|
153 (defn read-properties
|
rlm@10
|
154 "Read properties from file-able."
|
rlm@10
|
155 [file-able]
|
rlm@10
|
156 (with-open [f (java.io.FileInputStream. (file file-able))]
|
rlm@10
|
157 (doto (Properties.)
|
rlm@10
|
158 (.load f))))
|
rlm@10
|
159
|
rlm@10
|
160 (defn write-properties
|
rlm@10
|
161 "Write properties to file-able."
|
rlm@10
|
162 {:tag Properties}
|
rlm@10
|
163 ([m file-able] (write-properties m file-able nil))
|
rlm@10
|
164 ([m file-able comments]
|
rlm@10
|
165 (with-open [^FileOutputStream f (FileOutputStream. (file file-able))]
|
rlm@10
|
166 (doto (as-properties m)
|
rlm@10
|
167 (.store f ^String comments)))))
|
rlm@10
|
168
|
rlm@10
|
169 (defn delete-file
|
rlm@10
|
170 "Delete file f. Raise an exception if it fails unless silently is true."
|
rlm@10
|
171 {:deprecated "1.2"}
|
rlm@10
|
172 [f & [silently]]
|
rlm@10
|
173 (or (.delete (file f))
|
rlm@10
|
174 silently
|
rlm@10
|
175 (throw (java.io.IOException. (str "Couldn't delete " f)))))
|
rlm@10
|
176
|
rlm@10
|
177 (defn delete-file-recursively
|
rlm@10
|
178 "Delete file f. If it's a directory, recursively delete all its contents.
|
rlm@10
|
179 Raise an exception if any deletion fails unless silently is true."
|
rlm@10
|
180 {:deprecated "1.2"}
|
rlm@10
|
181 [f & [silently]]
|
rlm@10
|
182 (let [f (file f)]
|
rlm@10
|
183 (if (.isDirectory f)
|
rlm@10
|
184 (doseq [child (.listFiles f)]
|
rlm@10
|
185 (delete-file-recursively child silently)))
|
rlm@10
|
186 (delete-file f silently)))
|
rlm@10
|
187
|
rlm@10
|
188 (defmulti
|
rlm@10
|
189 ^{:deprecated "1.2"
|
rlm@10
|
190 :doc "Coerces argument (URL, URI, or String) to a java.net.URL."
|
rlm@10
|
191 :arglists '([arg])}
|
rlm@10
|
192 as-url type)
|
rlm@10
|
193
|
rlm@10
|
194 (defmethod as-url URL [x] x)
|
rlm@10
|
195
|
rlm@10
|
196 (defmethod as-url URI [^URI x] (.toURL x))
|
rlm@10
|
197
|
rlm@10
|
198 (defmethod as-url String [^String x] (URL. x))
|
rlm@10
|
199
|
rlm@10
|
200 (defmethod as-url File [^File x] (.toURL x))
|
rlm@10
|
201
|
rlm@10
|
202 (defn wall-hack-method
|
rlm@10
|
203 "Calls a private or protected method.
|
rlm@10
|
204 params is a vector of class which correspond to the arguments to the method
|
rlm@10
|
205 obj is nil for static methods, the instance object otherwise
|
rlm@10
|
206 the method name is given as a symbol or a keyword (something Named)"
|
rlm@10
|
207 {:deprecated "1.2"}
|
rlm@10
|
208 [class-name method-name params obj & args]
|
rlm@10
|
209 (-> class-name (.getDeclaredMethod (name method-name) (into-array Class params))
|
rlm@10
|
210 (doto (.setAccessible true))
|
rlm@10
|
211 (.invoke obj (into-array Object args))))
|
rlm@10
|
212
|
rlm@10
|
213 (defn wall-hack-field
|
rlm@10
|
214 "Access to private or protected field."
|
rlm@10
|
215 {:deprecated "1.2"}
|
rlm@10
|
216 [class-name field-name obj]
|
rlm@10
|
217 (-> class-name (.getDeclaredField (name field-name))
|
rlm@10
|
218 (doto (.setAccessible true))
|
rlm@10
|
219 (.get obj)))
|