Create file in Clojure - clojure

I'm trying to create rdf model with Apache Jena TDB, so here is the code:
(def model (com.hp.hpl.jena.tdb.TDBFactory/createModel "/rdfrepo"))
Which gives me following error:
Exception in thread "main" com.hp.hpl.jena.tdb.base.file.FileException: Failed to open: /rdfrepo/node2id.idn (mode=rw)
I have tried adding
:resource-paths ["shared" "resources"]
to projects.clj but didn't make any change.
I'm not very familiar with file system management in Clojure so I really need help with this one.

You can get resource file with clojure.java.io/resource
(clojure.java.io/resource "css/default.css")
=> #<URL file:/Users/yyy/xx/resources/css/default.css>
You don't need to add the / before the resource path.
You can then open the file with io/file:
(require '[clojure.java.io :as io])
(-> "file.png" io/resource io/file)
In your case you can try passing (io/resource "rdfrepo") to createModel

A path that begins with / is always at the root of the file system, which is a place you should not be trying to write. Will the code work without the leading / on the path?

Related

Clojure importing nested classes

I am trying to write a couple of wrapper functions for the code here
it basically has the form (as given in the example page) of
String json = ...
VPackParser parser = new VPackParser.Builder().build();
VPackSlice slice = parser.fromJson(json);
I am aware that To import inner classes one uses $, but every combination of the following doesn't seem to work.
(ns the.pain.is.real
(:require [clojure.reflect :as r])
(:import
com.arangodb.velocypack.VPackBuilder ;; fine
com.arangodb.velocypack.VPackSlice ;; fine
com.arangodb.velocypack.VPackParser ;; fine
com.arangodb.velocypack.VPack ;; fine
com.arangodb.velocypack.VPackParser$Builder ;; nope
))
I just get a Unhandled java.lang.ClassNotFoundException.
I had worked with some similar code that I had got working using:
(ns winning
(:import com.arangodb.ArangoDB$Builder))
(.build (-> (new ArangoDB$Builder)
(.host "127.0.0.1" 8529)
(.user username)
(.password password)))
Any ideas?
looking in the jar file does show
com/arangodb/velocypack/VPackParser$Builder.class
Is it just trial and error?
Answering my own question.
It appears that two versions were downloaded when using lein deps. Even though only [com.arangodb/velocypack "1.0.0"] was in the project file, both 1.0.0 and 1.0.10 were in the .m2 dir. The class com/arangodb/velocypack/VPackParser$Builder.class is only found in version 1.0.10.
After changing the project file to [com.arangodb/velocypack "1.0.10"] the import works.

Loading file with namespace doesn't work?

Take I have a completely separate (as in, somewhere in the file system) file:
(ns separate)
(def a "test")
Now, if I try to load that file like this:
(load-file "separate.clj")
(require 'separate)
(separate/a)
It throws an error saying that separate isn't found as a namespace. Why is this and how do I fix it?
EDIT: This is literally the code I'm running:
(require 'separate)
Should be:
(require '[separate])
There is no example in clojuredocs probably because single part namespaces are unusual.
Found the solution, I need to do something like this:
(deref (get (ns-interns 'separate) 'a))

How to set S3 path style in Clojure using Amazonica library?

I'm a Ruby dev moving over to Clojure and I'm having trouble understanding how to translate the following Java call into Clojure based on the conventions used in the Clojure library Amazonica.
AmazonS3 client = new AmazonS3Client(credentials);
client.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true));
The code I have at the moment is:
(ns spurious-aws-sdk-helper.core
(:use [amazonica.aws.s3]])
(:require [amazonica.core :refer [ex->map]]))
(def credentials {:access-key "development_access"
:secret-key "development_secret"
:endpoint "s3.spurious.localhost:49154"
:client-config {:protocol "http"}})
(try
(amazonica.aws.s3/set-s3client-options {:path-style-access true})
(create-bucket credentials "testing")
(catch Exception e
(clojure.pprint/write (ex->map e))))
But I'm getting the following error:
com.amazonaws.http.AmazonHttpClient executeHelper
INFO: Unable to execute HTTP request: testing.s3.spurious.localhost
java.net.UnknownHostException: testing.s3.spurious.localhost
This doesn't look to be correct as it's prefixing the bucket name (testing) onto the hostname. Where as I need the SDK to talk to our local (fake) S3 service (s3.spurious.localhost:49154) using path style.
e.g. like http://s3.spurious.localhost:49154/testing
I think it's because I'm not translating the Java code correctly...
(amazonica.aws.s3/set-s3client-options {:path-style-access true})
...this is passing a map to set-s3client-options rather than what it should be, which is passing the result of calling withPathStyleAccess(true) on a new instance of S3ClientOptions. But I don't know how to do that here?
Any help would be greatly appreciated.
UPDATE
Here is the latest version of the code (which still doesn't work)...
(ns spurious-aws-sdk-helper.core
(:use [amazonica.aws.s3])
(:require [amazonica.core :refer [ex->map]]))
(def credentials {:access-key "development_access"
:secret-key "development_secret"
:endpoint "s3.spurious.localhost:49154"
:client-config {:protocol "http"}})
(try
(amazonica.aws.s3/set-s3client-options
(. (com.amazonaws.services.s3.S3ClientOptions.) setPathStyleAccess true))
(create-bucket credentials "testing")
(catch Exception e
(clojure.pprint/write (ex->map e))))
Your first call to set up the S3ClientOptions is the correct one.
I think you're confusing what that setting does.
It changes the pre-signed URL generation from using the Virtual Hosted Style https://my_bucket_name.s3.amazonaws.com/my_key to the Path Style https://s3.amazonaws.com/my_bucket_name/my_key
This is necessary if your bucket name contains dots, as the virtual hosted style breaks Amazon's SSL certificate identification (i.e. it only supports the wildcard *.s3.amazonaws.com)
So if you're generating pre-signed URLs on a bucket name containing dots in Clojure e.g.
(s3/generate-presigned-url bucket key (-> 6 hours from-now)))
You will first need to set the path style using
(amazonica.aws.s3/set-s3client-options {:path-style-access true})
Thanks to #stukennedy for responding to the open question. I should have come back long ago and updated this space with the actual solution which I managed to figure out and implement ~8months ago (Feb 2nd 2015):
(ns spurious-aws-sdk-helper.s3
(:use [amazonica.aws.s3])
(:require [spurious-aws-sdk-helper.utils :refer [endpoint cred]]))
(defn resource [type]
(endpoint type :spurious-s3))
(defn setup
([type]
(set-s3client-options (cred (resource type)) :path-style-access true))
([type name]
(try
(let [credentials (cred (resource type))]
(set-s3client-options credentials :path-style-access true)
(create-bucket credentials name))
(catch Exception e
(prn "S3 Error: chances are you're creating a bucket that already exists")))))
You can find the full details here: https://github.com/Integralist/spurious-clojure-aws-sdk-helper if you need more context
If I remember correctly, I needed to pass credentials through to set-s3client-options (without them it wouldn't work)

How do I depend on every clojure contrib library?

I used to like to include all of clojure.contrib, and require all the libraries. This makes find-doc useful as a discovery tool.
Nowadays (clojure 1.4) clojure.contrib is split into many sub-libraries. And that rather spoils my scheme, and it also means that I am constantly having to restart the JVM every time I need a new library.
So I'm busy constructing a project.clj file with many lines:
[org.clojure/algo.generic "0.0.6"]
....
[org.clojure/data.xml "0.0.4"]
....
So that I can get leiningen to put every clojure contrib library on the classpath, whether I need them or not.
And I reckon that this is going to be a spectacular pain in the neck, what with the version numbers, and all.
And I wonder if anyone has a better way to do the same thing?
EDIT: Thinking about it, if there's a web page somewhere that has a list of library names and current versions, I can turn that into a project file fairly easily.
You could use pomegranate if you just want to run it in the REPL (which seems like it would be the only appropriate use case, right?). You can have it look up the latest versions using the Maven Central API. I think this is better than maintaining some sort of dependencies project, generated or otherwise.
(require '[cemerick.pomegranate :refer [add-dependencies]])
(add-dependencies
:coordinates '[[clj-http "0.5.8"]]
:repositories {"clojars" "http://clojars.org/repo"})
(require '[clj-http.client :as client])
;; contrib project names from https://github.com/clojure
(def contrib ["tools.nrepl" "tools.trace" "tools.namespace" "tools.macro"
"test.generative" "math.numeric-tower" "core.match" "core.logic"
"data.priority-map" "core.contracts" "tools.cli" "java.jmx"
"java.jdbc" "java.classpath" "data.xml" "data.json" "core.unify"
"core.incubator" "core.cache" "algo.monads" "data.generators"
"core.memoize" "math.combinatorics" "java.data" "tools.logging"
"data.zip" "data.csv" "algo.generic" "data.codec"
"data.finger-tree"])
(defn add-contrib-dependencies
"look up the latest version of every contrib project in maven central,
and add them as dependencies using pomegranate."
[project-names]
(add-dependencies
:coordinates
(map (juxt
(comp symbol (partial format "org.clojure/%s"))
(fn [proj]
(Thread/sleep 100)
(-> "http://search.maven.org/solrsearch/select?q=%s&rows=1&wt=json"
(format proj)
(client/get {:as :json})
:body :response :docs first :latestVersion)))
project-names)))
Now you can just invoke this function on the list of project names:
user=> (add-contrib-dependencies contrib)
{[org.clojure/data.zip "0.1.1"] nil,
[org.clojure/java.classpath "0.2.0"] nil,
[org.clojure/core.cache "0.6.2"] nil, ...}
UPDATE: as suggested earlier, I had made this answer into a library. It can be used either as nREPL middleware or invoked manually from a running REPL session. The code can be found at https://github.com/rplevy/contrib-repl, where usage instructions can also be found.
I feel your pain. It should be helpful http://dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go

FTP with Clojure

Are there any libraries to perform FTP transfer with clojure, idiomatic to clojure, or is it necessary to use a java library such as apache commons?
Thanks
It is not necessary to use java library and you can roll complete FTP implementation in Clojure but that would be like re-inventing the wheel and not a feasible thing to do. What you can do is probably write a more functional wrapper over the Java library and then use that wrapper in your clojure code so that everything seems seamless and that't how many of the existing Java libraries are being used in Clojure.
You can use https://github.com/miner/clj-ftp either by invoking few convenience functions or by opening a client and invoking multiple commands with it.
The full API is documented in GitHub at https://github.com/miner/clj-ftp/blob/master/src/miner/ftp.clj .
Contents of project.clj
(defproject my-sweet-project "0.5.0"
:dependencies [[com.velisco/clj-ftp "0.3.0"]
; Other deps
]
; ...
)
Invoking a single FTP command
This will open new FTP connection for each command so it should be used for invoking a single command only. See the full API for complete list of these convenience functions.
(ns my-sweet-name.space
(:require [miner.ftp :as ftp]))
(defn list-files-from-ftp-server []
"Here we list contents of a directory with a convenience function"
(let [ftp-url "ftp://username:password#my.ftp.server.host:port/path/to/stuff"]
(ftp/list-files ftp-url)))
Invoking multiple commands with same connection
This will open FTP connection and invoke arbitrary amount of commands with it. This should be used when multiple commands should be invoked. The FTP connection will be automatically closed. Again check the full API for complete list of functions.
(ns my-sweet-name.space
(:require [miner.ftp :as ftp]))
(defn list-and-download-files []
"Here we list and download contents of a directory"
(let [ftp-url "ftp://username:password#my.ftp.server.host:port/path/to/stuff"]
(ftp/with-ftp [ftp-client ftp-url]
; client-file-names is used to list contents of the ftp-url
; client-get is used to download a file
(doseq [file-name (ftp/client-file-names ftp-client)]
(let [local-file-name (str "/download-path/" file-name)]
(ftp/client-get ftp-client file-name local-file-name))))))
https://github.com/miner/clj-ftp is a wrapper over Apache Commons Net.