4 (:import com.interrupt.cc.xpath.lexer.Lexer)
5 (:import com.interrupt.cc.xpath.lexer.LexerException)
6 (:import com.interrupt.cc.xpath.node.Node)
7 (:import com.interrupt.cc.xpath.node.Start)
8 (:import com.interrupt.cc.xpath.parser.Parser)
9 (:import com.interrupt.cc.xpath.parser.ParserException)
10 (:import com.interrupt.cc.xpath.analysis.DepthFirstAdapter)
11 (:import com.interrupt.bob.processor.cc.DepthFirstVisitor)
13 (:import java.io.InputStreamReader)
14 (:import java.io.PushbackReader)
15 (:import java.io.ByteArrayInputStream)
16 (:import java.util.ArrayList)
20 (:require clojure.xml)
25 ;; remove the SableCC added <spaces> and `
26 (defn filter-xpath-input [input-string]
27 (clojure.contrib.string/replace-str " " ""
28 (clojure.contrib.string/replace-str "`" "" input-string))
31 ;; build the XPath parser
32 (defn get-pushback-parser [xpath-string]
33 (Parser. (Lexer. (PushbackReader. (InputStreamReader.
34 (ByteArrayInputStream. (. xpath-string getBytes)))
38 ;; the XPath string that the proxy / adapter will use to figure out context directory & XPath expression
39 ;; (def XPATH-string (ref ""))
40 (def xpath-data (ref {}))
42 ;; we're gonna build our eXist URL with this
43 ;;(def URL-build (ref ""))
45 ;; pilfered stack ideas and some implementation from: http://programming-puzzler.blogspot.com/2009/04/adts-in-clojure.html
50 (dosync (alter stack conj e))
51 (println "PUSH stack [" @stack "]" ))
53 (dosync (alter stack pop)))
55 (dosync (alter stack empty?)))
58 (defn get-url-midpoint [#^String URL-build]
60 (. URL-build lastIndexOf ;; get the position of substring
61 (:context-parent @xpath-data))
62 (. (:context-parent @xpath-data) length)) ;; plus the char length of the leaf document name
64 (defn get-xpath-part-midpoint []
68 (. (:xpath-string @xpath-data) indexOf
69 (. (:context-parent @xpath-data) substring
71 (. (:context-parent @xpath-data) indexOf ".")))) ]
73 (. (:xpath-string @xpath-data) substring
74 (+ 1 (. (:xpath-string @xpath-data) indexOf "/" (+ 1 b_index)))
79 ;; get DepthFirstAdapter proxy
80 (defn get-adapter-proxy []
82 (let [URL-build (atom "")] ;; we're gonna build our eXist URL with this
83 (proxy [DepthFirstAdapter] []
88 ;; - keep the last/previous token
91 (caseTAbbrevRootDesc [node]
93 (println "caseTAbbrevRootDesc CALLED \t\t\t\t class[" (. node getClass) "] \t\t\t\t" (. node toString))
99 (println "caseTLetter CALLED \t\t\t\t\t class[" (. node getClass) "] \t\t\t\t\t" (. node toString))
103 (caseAPredicatelist [node]
105 (proxy-super inAPredicatelist node) ;; duplicating adapter 'in' call
107 (println "caseAPredicatelist CALLED \t\t\t\t class[" (. node getClass) "] \t\t\t\t" (. node toString) "\t\t filtered " (filter-xpath-input (. node toString)))
108 (doseq [ each_predicate (java.util.ArrayList. (. node getPredicate)) ]
111 (println "DEBUG > each predicate... " each_predicate " predicate expresion[" (. each_predicate getExpr)
112 "] getExprsingle[" (.. each_predicate getExpr getExprsingle) "] ugghhhh!! [" ;; this is where = breaks off: getComparisonexpr -here- getComparisonexprPart
113 ;;(.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getComparisonexprPart getRangeexpr) "]" )
114 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getRangeexpr) "]" )
116 ;; TODO - DON'T traverse children & evaluate... for now
117 ;;(. each_predicate apply this)
120 ;; ** here we are assuming there's only one predicate in the list - getting the 'name' and 'value'
122 (clojure.contrib.string/replace-str "@" ""
123 (clojure.contrib.string/replace-str " " ""
124 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getRangeexpr toString))))
126 (clojure.contrib.string/replace-str "'" ""
127 (clojure.contrib.string/replace-str " " ""
128 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getComparisonexprPart getRangeexpr toString))))
129 (println "DEBUG > predicate-name[" predicate-name "] > predicate-value[" predicate-value "]")
132 ;; (peek, then..) pop 'TLetter' & 'RelativePathexpr'
133 (def top (stack-peek))
134 (stack-pop) ;; pop the token
135 (stack-pop) ;; LATER - pop the relativepathpart - we'll have to assume that there's a relative_path_part... for now
137 (println "top of stack["top"] > class["(. top getClass)"] / predicate-value[" predicate-value "] > class["(. predicate-value getClass)"]")
139 (instance? com.interrupt.cc.xpath.node.TAbbrevRootDesc top )
142 (instance? com.interrupt.cc.xpath.node.TLetter top )
144 (swap! URL-build str (clojure.contrib.string/replace-str " " "" (. top toString) ) "." predicate-value)
145 (swap! URL-build str "/")
148 ;;(instance? com.interrupt.cc.xpath.node.ARootRelativepathexprPartPart top )
149 ;; (dosync (alter URL-build str "/"))
151 (instance? com.interrupt.cc.xpath.node.APredicatelist top )
155 ;; put in a check to see if we are at the leaf document
156 (println "leaf check [" (. (clojure.contrib.string/trim (. top toString)) equals (:leaf-node @xpath-data)) "] > top[" (clojure.contrib.string/trim (. top toString)) "] > leaf-node[" (:leaf-node @xpath-data) "]")
158 (if (. (clojure.contrib.string/trim (. top toString)) equals (:leaf-node @xpath-data))
160 (do ;; IF portion here
162 (. @URL-build substring ;; get a substring of our long exist URL
164 (get-url-midpoint @URL-build)
166 ;; (. URL-build lastIndexOf ;; get the position of substring
167 ;; (:context-parent @xpath-data))
168 ;; (. (:context-parent @xpath-data) length)) ;; plus the char length of the leaf document name
171 ;; write out context directory
173 (alter xpath-data conj
174 { :context-dir thing})
176 ;; write out leaf document
177 (def b_index (+ (. @URL-build lastIndexOf
178 (:context-parent @xpath-data))
179 (. (:context-parent @xpath-data) length)))
181 (println "b_index[" b_index "] > +1[" (+ 1 b_index) "] > :context-parent["(:context-parent @xpath-data)"] > URL-build["
182 @URL-build"] > indexOf '/' [" (. @URL-build indexOf "/") "] > FINAL["
183 (. @URL-build indexOf "/" (+ 1 b_index))"] > 'if' check["(< (. @URL-build indexOf "/" (+ 1 b_index)) 0 )"]")
186 (if (> (. @URL-build indexOf "/" (+ 1 b_index)) 0 )
189 (. @URL-build substring
191 (. @URL-build indexOf "/" (+ 1 b_index)))
193 (alter xpath-data conj ;; if context directory is NOT the same as leaf document
194 { :leaf-document-name (str leaf-doc "/" leaf-doc)
195 ;;(. URL-build substring
197 ;; (. URL-build indexOf "/" (+ 1 b_index)))
201 (alter xpath-data conj ;; if context directory IS the same as leaf document
202 { :leaf-document-name
203 (str (:leaf-node @xpath-data) "." predicate-value )
209 (println "---> We are at the leaf document[" @xpath-data "]" )
212 (dosync (alter xpath-data conj ;; ELSE, get the child XPath part
213 { :xpath-part (get-xpath-part-midpoint) }))
218 (println "URL-build[" @URL-build "]")
222 (proxy-super outAPredicatelist node) ;; duplicating adapter 'out' call
225 (caseARootRelativepathexprPartPart [node]
227 (println "caseARootRelativepathexprPartPart CALLED \t\t class[" (. node getClass) "] \t\t\t\t" (. node toString))
236 (defmulti xpath_handler (fn [input handler]
238 (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput input )
239 :AXpathCommandInput ;; com.interrupt.bookkeeping.cc.node.AXpathCommandInput
240 :Node ;;com.interrupt.bookkeeping.cc.node.Node
245 (defmethod xpath_handler [:Node :handler] [node handler]
248 (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput (. node getCommandInput) )
249 (xpath_handler (. node getCommandInput) handler)
250 (println "EEeee.. xpath_handler not processing")
253 (println "EEeee.. xpath_handler not processing > Error Message[" (. e getMessage) "]")) ;; > StackTrace[" (. e printStackTrace) "]"))
256 (defmethod xpath_handler [:AXpathCommandInput :handler] [xinput handler]
258 (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput xinput )
262 (println "xpath_handler > xinput[" (. xinput getClass) "]")
263 (println "XPATH input[" (. xinput toString) "]")
265 ;; 1. filter out <spaces> and `
266 (def input-string (filter-xpath-input (. xinput toString)))
267 (println "input-string \t[" input-string "]")
268 ;;(println "stripped XPath \t[" (clojure.contrib.string/replace-re #"\\[[^\\]]*\\]" "" input-string) "]" )
273 ;; put in whole xpath string
274 (alter xpath-data conj { :xpath-string input-string } )
276 ;; for token substring between last / and [
277 (alter xpath-data conj {
279 (. (:xpath-string @xpath-data) substring
280 (+ (. (:xpath-string @xpath-data) lastIndexOf "/") 1)
281 (. (:xpath-string @xpath-data) lastIndexOf "["))
284 ;; with token, lookup context directory
285 (alter xpath-data conj { :context-parent (working-dir-lookup (:leaf-node @xpath-data)) } )
287 (println "LEAF token > " (:leaf-node @xpath-data))
288 (println "LEAF context parent > " (:context-parent @xpath-data))
291 ;; 1.2 build an xpath parser
292 (def tree (.parse (get-pushback-parser input-string)))
294 ;; 2. token - find i) leaf document to search ii) root & xpath expression to feed to RESTful exist
295 (. tree apply (get-adapter-proxy ) )
297 ;; 3. build RESTful call
298 (def db-query (str "_wrap=no&_query="
299 "declare default element namespace '"(namespace-lookup (:leaf-node @xpath-data)) "';"
301 ;; TODO - check if we need 'and' conditions
302 ;; "**/<token>[ @option='option_value' [ and @option='option_value' ] ]"
303 "//"(:leaf-node @xpath-data)"[ @" predicate-name "='" predicate-value "']"
309 (def db-full-PARENT (str db-base-URL "rootDir/" (:context-dir @xpath-data)))
311 ;; 4. make RESTful call & 5. pass result sequece to handler
315 ;;(str db-full-PARENT "/" (:leaf-document-name @xpath-data) (str "?" (url-encode db-query)))
316 (str db-full-PARENT "/" (:leaf-document-name @xpath-data) (str "?" (url-encode-spaces db-query)))
318 {"Content-Type" "text/xml"}
322 (println "result-hash > " result-hash )
324 (clojure.contrib.str-utils/str-join nil
325 (:body-seq result-hash ))
328 (println "xpath_handler > string > " xml-string )
330 (clojure.xml/parse (ByteArrayInputStream. (. xml-string getBytes ) )))
335 (catch Exception e (println "EEeee.. xpath_hanlder not processing"))