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 [" (deref 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 (deref xpath-data)))
62 (. (:context-parent (deref xpath-data)) length)) ;; plus the char length of the leaf document name
64 (defn get-xpath-part-midpoint []
68 (. (:xpath-string (deref xpath-data)) indexOf
69 (. (:context-parent (deref xpath-data)) substring
71 (. (:context-parent (deref xpath-data)) indexOf ".")))) ]
73 (. (:xpath-string (deref xpath-data)) substring
74 (+ 1 (. (:xpath-string (deref 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 (deref xpath-data))) "] > top[" (clojure.contrib.string/trim (. top toString)) "] > leaf-node[" (:leaf-node (deref xpath-data)) "]")
158 (if (. (clojure.contrib.string/trim (. top toString)) equals (:leaf-node (deref 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 (deref xpath-data)))
168 ;; (. (:context-parent (deref 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 (deref xpath-data)))
179 (. (:context-parent (deref xpath-data)) length)))
181 (println "b_index[" b_index "] > +1[" (+ 1 b_index) "] > :context-parent["(:context-parent (deref 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 (deref xpath-data)) "." predicate-value )
209 (println "---> We are at the leaf document[" (deref 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 (defn xpath_handler [node handler]
237 (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput (. node getCommandInput) )
241 (println "xpath_handler > node[" (.. node getClass) "] > getLoad[" (.. node getLoad getText) "]")
242 (println "XPATH input[" (.. node getCommandInput toString) "]")
244 ;; 1. filter out <spaces> and `
245 (def input-string (filter-xpath-input (.. node getCommandInput toString)))
246 (println "input-string \t[" input-string "]")
247 ;;(println "stripped XPath \t[" (clojure.contrib.string/replace-re #"\\[[^\\]]*\\]" "" input-string) "]" )
252 ;; put in whole xpath string
253 (alter xpath-data conj { :xpath-string input-string } )
255 ;; for token substring between last / and [
256 (alter xpath-data conj {
258 (. (:xpath-string (deref xpath-data)) substring
259 (+ (. (:xpath-string (deref xpath-data)) lastIndexOf "/") 1)
260 (. (:xpath-string (deref xpath-data)) lastIndexOf "["))
263 ;; with token, lookup context directory
264 (alter xpath-data conj { :context-parent (working-dir-lookup (:leaf-node (deref xpath-data))) } )
266 (println "LEAF token > " (:leaf-node (deref xpath-data)))
267 (println "LEAF context parent > " (:context-parent (deref xpath-data)))
270 ;; 1.2 build an xpath parser
271 (def tree (.parse (get-pushback-parser input-string)))
273 ;; 2. token - find i) leaf document to search ii) root & xpath expression to feed to RESTful exist
274 (. tree apply (get-adapter-proxy ) )
276 ;; 3. build RESTful call
277 (def db-query (str "_wrap=no&_query="
278 "declare default element namespace '"(namespace-lookup (:leaf-node (deref xpath-data))) "';"
280 ;; TODO - check if we need 'and' conditions
281 ;; "**/<token>[ @option='option_value' [ and @option='option_value' ] ]"
282 "//"(:leaf-node (deref xpath-data))"[ @" predicate-name "='" predicate-value "']"
288 (def db-full-PARENT (str db-base-URL "rootDir/" (:context-dir (deref xpath-data))))
290 ;; 4. make RESTful call & 5. pass result sequece to handler
294 ;;(str db-full-PARENT "/" (:leaf-document-name (deref xpath-data)) (str "?" (url-encode db-query)))
295 (str db-full-PARENT "/" (:leaf-document-name (deref xpath-data)) (str "?" (url-encode-spaces db-query)))
297 {"Content-Type" "text/xml"}
301 (println "result-hash > " result-hash )
303 (clojure.contrib.str-utils/str-join nil
304 (:body-seq result-hash ))
307 (println "xpath_handler > string > " xml-string )
309 (clojure.xml/parse (ByteArrayInputStream. (. xml-string getBytes ) )))