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 []
60 (. (deref 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 (proxy [DepthFirstAdapter] []
87 ;; - keep the last/previous token
90 (caseTAbbrevRootDesc [node]
92 (println "caseTAbbrevRootDesc CALLED \t\t\t\t class[" (. node getClass) "] \t\t\t\t" (. node toString))
98 (println "caseTLetter CALLED \t\t\t\t\t class[" (. node getClass) "] \t\t\t\t\t" (. node toString))
102 (caseAPredicatelist [node]
104 (proxy-super inAPredicatelist node) ;; duplicating adapter 'in' call
106 (println "caseAPredicatelist CALLED \t\t\t\t class[" (. node getClass) "] \t\t\t\t" (. node toString) "\t\t filtered " (filter-xpath-input (. node toString)))
107 (doseq [ each_predicate (java.util.ArrayList. (. node getPredicate)) ]
110 (println "DEBUG > each predicate... " each_predicate " predicate expresion[" (. each_predicate getExpr)
111 "] getExprsingle[" (.. each_predicate getExpr getExprsingle) "] ugghhhh!! [" ;; this is where = breaks off: getComparisonexpr -here- getComparisonexprPart
112 ;;(.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getComparisonexprPart getRangeexpr) "]" )
113 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getRangeexpr) "]" )
115 ;; LATER - DON'T traverse children & evaluate... for now
116 ;;(. each_predicate apply this)
119 ;; ** here we are assuming there's only one predicate in the list - getting the 'name' and 'value'
121 (clojure.contrib.string/replace-str "@" ""
122 (clojure.contrib.string/replace-str " " ""
123 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getRangeexpr toString))))
125 (clojure.contrib.string/replace-str "'" ""
126 (clojure.contrib.string/replace-str " " ""
127 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getComparisonexprPart getRangeexpr toString))))
128 (println "DEBUG > predicate-name[" predicate-name "] > predicate-value[" predicate-value "]")
131 ;; (peek, then..) pop 'TLetter' & 'RelativePathexpr'
132 (def top (stack-peek))
133 (stack-pop) ;; pop the token
134 (stack-pop) ;; LATER - pop the relativepathpart - we'll have to assume that there's a relative_path_part... for now
136 (println "top of stack["top"] > class["(. top getClass)"]")
138 (instance? com.interrupt.cc.xpath.node.TAbbrevRootDesc top )
141 (instance? com.interrupt.cc.xpath.node.TLetter top )
143 (alter URL-build str (clojure.contrib.string/replace-str " " "" (. top toString) ) "." predicate-value)
144 (alter URL-build str "/"))
146 ;;(instance? com.interrupt.cc.xpath.node.ARootRelativepathexprPartPart top )
147 ;; (dosync (alter URL-build str "/"))
149 (instance? com.interrupt.cc.xpath.node.APredicatelist top )
153 ;; put in a check to see if we are at the leaf document
154 (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)) "]")
156 (if (. (clojure.contrib.string/trim (. top toString)) equals (:leaf-node (deref xpath-data)))
158 (do ;; IF portion here
160 (. (deref URL-build) substring ;; get a substring of our long exist URL
164 ;; (. (deref URL-build) lastIndexOf ;; get the position of substring
165 ;; (:context-parent (deref xpath-data)))
166 ;; (. (:context-parent (deref xpath-data)) length)) ;; plus the char length of the leaf document name
169 ;; write out context directory
171 (alter xpath-data conj
172 { :context-dir thing})
174 ;; write out leaf document
175 (def b_index (+ (. (deref URL-build) lastIndexOf
176 (:context-parent (deref xpath-data)))
177 (. (:context-parent (deref xpath-data)) length)))
179 (println "b_index[" b_index "] > +1[" (+ 1 b_index) "] > :context-parent["(:context-parent (deref xpath-data))"] > URL-build["
180 (deref URL-build)"] > indexOf '/' [" (. (deref URL-build) indexOf "/") "] > FINAL["
181 (. (deref URL-build) indexOf "/" (+ 1 b_index))"] > 'if' check["(< (. (deref URL-build) indexOf "/" (+ 1 b_index)) 0 )"]")
184 (if (> (. (deref URL-build) indexOf "/" (+ 1 b_index)) 0 )
186 (alter xpath-data conj ;; if context directory is NOT the same as leaf document
187 { :leaf-document-name
188 (. (deref URL-build) substring
190 (. (deref URL-build) indexOf "/" (+ 1 b_index)))
193 (alter xpath-data conj ;; if context directory IS the same as leaf document
194 { :leaf-document-name
195 (str (:leaf-node (deref xpath-data)) "." predicate-value )
201 (println "---> We are at the leaf document[" (deref xpath-data) "]" ))
203 (dosync (alter xpath-data conj ;; ELSE, get the child XPath part
204 { :xpath-part (get-xpath-part-midpoint) }))
209 (println "URL-build[" (deref URL-build) "]")
213 (proxy-super outAPredicatelist node) ;; duplicating adapter 'out' call
216 (caseARootRelativepathexprPartPart [node]
218 (println "caseARootRelativepathexprPartPart CALLED \t\t class[" (. node getClass) "] \t\t\t\t" (. node toString))
226 (defn xpath_handler [node handler]
227 (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput (. node getCommandInput) )
231 (println "xpath_handler > node[" (.. node getClass) "] > getLoad[" (.. node getLoad getText) "]")
232 (println "XPATH input[" (.. node getCommandInput toString) "]")
234 ;; 1. filter out <spaces> and `
235 (def input-string (filter-xpath-input (.. node getCommandInput toString)))
236 (println "input-string \t[" input-string "]")
237 (println "stripped XPath \t[" (clojure.contrib.string/replace-re #"\\[[^\\]]*\\]" "" input-string) "]" )
242 ;; put in whole xpath string
243 (alter xpath-data conj { :xpath-string input-string } )
245 ;; for token substring between last / and [
246 (alter xpath-data conj {
248 (. (:xpath-string (deref xpath-data)) substring
249 (+ (. (:xpath-string (deref xpath-data)) lastIndexOf "/") 1)
250 (. (:xpath-string (deref xpath-data)) lastIndexOf "["))
253 ;; with token, lookup context directory
254 (alter xpath-data conj { :context-parent (working-dir-lookup (:leaf-node (deref xpath-data))) } )
256 (println "LEAF token > " (:leaf-node (deref xpath-data)))
257 (println "LEAF context parent > " (:context-parent (deref xpath-data)))
260 ;; 1.2 build an xpath parser
261 (def tree (.parse (get-pushback-parser input-string)))
263 ;; 2. token - find i) leaf document to search ii) root & xpath expression to feed to RESTful exist
264 (. tree apply (get-adapter-proxy ) )
266 ;; 3. build RESTful call
267 (def db-query (str "_wrap=no&_query="
268 "declare default element namespace '"(namespace-lookup (:leaf-node (deref xpath-data))) "';"
270 ;; TODO - check if we need 'and' conditions
271 ;; "**/<token>[ @option='option_value' [ and @option='option_value' ] ]"
272 "//"(:leaf-node (deref xpath-data))"[ @" predicate-name "='" predicate-value "']"
278 (def db-full-PARENT (str db-base-URL "rootDir/" (:context-dir (deref xpath-data))))
280 ;; 4. make RESTful call & 5. pass result sequece to handler
282 (let [xml_string (execute-http-call db-full-PARENT (:leaf-document-name (deref xpath-data)) db-query)]
283 (handler (clojure.xml/parse (ByteArrayInputStream. (.getBytes xml_string "UTF-8"))))
289 ;; (execute-http-call db-full-PARENT (:leaf-document-name (deref xpath-data)) db-query)))
292 ;;(with-out-str (clojure.xml/emit