   "Returns a keyword representative of the document source's
    type."
   {:since "0.0.1"}
-  [source]
+  [^String source]
   (cond (try (.. (File. source) exists) (catch Throwable t)) :file
         (try (URL. source) (catch Throwable t)) :url
         :else nil))

   3. A basic PrintJobListener that prints any events that occur
   on the DocPrintJob."
  {:since "0.0.1"}
  (fn [spec] (apply (some-fn #{:doc} #{:docs}) (keys spec))))

(defmethod make-job :doc [spec]
  (let [{:keys [^PrintService printer ^PrintJobListener listener doc attrs]} spec
        {doc-attrs :attrs} doc]
    (if (and (valid-attrs? doc-attrs :doc)
             (valid-attrs? attrs :job))
      (letfn [(add-doc [spec]
                (assoc-in spec [:doc :obj] (delay (make-doc doc))))
              (add-job [spec]
                (assoc-in spec [:job] (.. printer createPrintJob)))]
        (-> spec add-doc add-job map->JobSpec)))))

(defmethod make-job :docs [spec]
  (let [{docs :docs} spec]
    (for [doc docs]
      (-> spec (dissoc :docs) (assoc :doc doc) make-job))))

;; Old method of encapsulating a 'MultiJobSpec', most
;; values in a JobSpec will be singleton instances

    (let [{{doc-obj :obj} :doc} this
          {:keys [^DocPrintJob job attrs]} this
          attr-set (make-set attrs :request)]
      (.. job (print @doc-obj attr-set)))) ;; Still 
  (add-listener! [this listener-fn]
    (let [{:keys [^DocPrintJob job listener-fn]} this
          listener (listener-fn)]
      (doto job (.addPrintJobListener listener)))))

;; TODO: Nobody wants to hand type this, create a convencience fn
;; that takes arguments in order and retuns a JobSpec

;;  A JobSpec might look something like this:
;; {:doc {:source "/path/to/doc.pdf"
