-- putting auto-commit to 'update' command as well
[bkell-clj.git] / src / xpath_handler.clj
blobab6103dd9eaddc3f65ae3b1e56ae6c7f43682e6c
2 (ns xpath_handler 
3   
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)
12   
13   (:import java.io.InputStreamReader)
14   (:import java.io.PushbackReader) 
15   (:import java.io.ByteArrayInputStream) 
16   (:import java.util.ArrayList)
17   
18   (:use helpers) 
19   
20   (:require clojure.xml)
21   
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))
29         )
30         
31         ;; build the XPath parser  
32         (defn get-pushback-parser [xpath-string] 
33                 (Parser. (Lexer. (PushbackReader. (InputStreamReader. 
34                                                                                                                                                                 (ByteArrayInputStream. (. xpath-string getBytes))) 
35                                                                                                                                                                 1024)))
36         )
37         
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 {})) 
41         
42         ;; we're gonna build our eXist URL with this 
43         ;;(def URL-build (ref "")) 
44         
45         ;; pilfered stack ideas and some implementation from: http://programming-puzzler.blogspot.com/2009/04/adts-in-clojure.html 
46         (def stack (ref [])) 
47         (defn stack-peek [] 
48                 (peek @stack))
49         (defn stack-push [e] 
50                 (dosync (alter stack conj e)) 
51                 (println "PUSH stack [" @stack "]" ))
52         (defn stack-pop [] 
53                 (dosync (alter stack pop)))
54         (defn stack-empty? [] 
55                 (dosync (alter stack empty?)))
56         
57         
58         (defn get-url-midpoint [#^String URL-build] 
59                 (+ 
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
63         )
64         (defn get-xpath-part-midpoint [] 
65                          
66                         (let [b_index 
67                                         (+ 1 
68                                                 (.      (:xpath-string @xpath-data) indexOf 
69                                                         (. (:context-parent @xpath-data) substring 
70                                                                 0 
71                                                                 (. (:context-parent @xpath-data) indexOf ".")))) ]
72                         
73                                                 (. (:xpath-string @xpath-data) substring 
74                                                         (+ 1 (. (:xpath-string @xpath-data) indexOf "/" (+ 1 b_index)))
75                                                 )
76                         )       
77         )       
78         
79         ;; get DepthFirstAdapter proxy 
80         (defn get-adapter-proxy [] 
81                 
82                 (let [URL-build (atom "")]              ;; we're gonna build our eXist URL with this 
83                 (proxy [DepthFirstAdapter] [] 
84                         
85                         ;; keep a stack with 
86                         ;;      i.      AbbrevRoot 
87                         ;;      ii.     Word 
88                         ;;                              - keep the last/previous token 
89                         ;;      iii.    RelativePath 
90                         ;;      iv.     Predicate 
91                         (caseTAbbrevRootDesc [node] 
92                                 
93                                 (println "caseTAbbrevRootDesc CALLED \t\t\t\t class[" (. node getClass) "] \t\t\t\t" (. node toString))
94                                 (stack-push node)
95                                 
96                         )
97                         (caseTLetter [node] 
98                                 
99                                 (println "caseTLetter CALLED \t\t\t\t\t class[" (. node getClass) "] \t\t\t\t\t" (. node toString))
100                                 (stack-push node)
101                                 
102                         )
103                         (caseAPredicatelist [node] 
104                                 
105                                 (proxy-super inAPredicatelist node)     ;; duplicating adapter 'in' call 
106                     
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)) ] 
109                                         (do
110                                                 
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) "]" )
115                                                 
116                                                 ;; TODO - DON'T traverse children & evaluate... for now 
117                                                 ;;(. each_predicate apply this)
118                                                 
119                                                 
120                                                 ;; ** here we are assuming there's only one predicate in the list - getting the 'name' and 'value' 
121                                                 (def predicate-name 
122                                                                 (clojure.contrib.string/replace-str "@" "" 
123                                                                         (clojure.contrib.string/replace-str " " "" 
124                                                                                 (.. each_predicate getExpr getExprsingle getOrexpr getAndexpr getComparisonexpr getRangeexpr toString)))) 
125                                                 (def predicate-value 
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 "]")
130                                                 
131                                                 
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  
136                                                 
137                                                 (println "top of stack["top"] > class["(. top getClass)"] / predicate-value[" predicate-value "] > class["(. predicate-value getClass)"]")
138                                                 (cond 
139                                                         (instance? com.interrupt.cc.xpath.node.TAbbrevRootDesc top ) 
140                                                                 '() 
141                                                         
142                                                         (instance? com.interrupt.cc.xpath.node.TLetter top ) 
143                                                                 (do 
144                                                                         (swap! URL-build str (clojure.contrib.string/replace-str " " "" (. top toString) ) "." predicate-value)
145                                                                         (swap! URL-build str "/")
146                                                                 )
147                                                         
148                                                         ;;(instance? com.interrupt.cc.xpath.node.ARootRelativepathexprPartPart  top ) 
149                                                         ;;      (dosync (alter URL-build str "/"))
150                                                         
151                                                         (instance? com.interrupt.cc.xpath.node.APredicatelist top ) 
152                                                                 '() 
153                                                 )
154                                                 
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) "]") 
157                                                 
158                                                 (if (. (clojure.contrib.string/trim (. top toString)) equals (:leaf-node @xpath-data))
159                                                         
160                                                         (do     ;; IF portion here 
161                                                                 (def thing 
162                                                                         (. @URL-build substring         ;; get a substring of our long exist URL 
163                                                                                                 0 
164                                                                                                 (get-url-midpoint @URL-build)
165                                                                                                 ;;(+
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 
169                                                                                         ))
170                                                                 
171                                                                 ;; write out context directory 
172                                                                 (dosync 
173                                                                         (alter xpath-data conj 
174                                                                                 {       :context-dir thing})
175                                                                         
176                                                                         ;; write out leaf document 
177                                                                         (def b_index    (+      (.      @URL-build lastIndexOf 
178                                                                                                                                                                 (:context-parent @xpath-data))  
179                                                                                                                                                                 (. (:context-parent @xpath-data) length))) 
180                                                                         
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 )"]")
184                                                                                         
185                                                                                         
186                                                                         (if (> (. @URL-build indexOf "/" (+ 1 b_index)) 0 )
187                                                                                  
188                                                                                 (let    [       leaf-doc 
189                                                                                                                 (. @URL-build substring 
190                                                                                                                         (+ 1 b_index) 
191                                                                                                                         (. @URL-build indexOf "/" (+ 1 b_index)))
192                                                                                                         ] 
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 
196                                                                                                                 ;;      (+ 1 b_index) 
197                                                                                                                 ;;      (. URL-build indexOf "/" (+ 1 b_index)))
198                                                                                                 })
199                                                                                 )
200                                                                                 
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 )
204                                                                                         }
205                                                                                 )
206                                                                                 
207                                                                         )
208                                                                 )
209                                                                 (println "---> We are at the leaf document[" @xpath-data "]" )
210                                                                 )
211                                                         
212                                                         (dosync (alter xpath-data conj  ;; ELSE, get the child XPath part
213                                                                 {       :xpath-part     (get-xpath-part-midpoint) })) 
214                                                         
215                                                 )
216                                         )
217                                 )
218                                 (println "URL-build[" @URL-build "]")
219                                 (println)
220                                 (println)
221                                 
222                                 (proxy-super outAPredicatelist node)    ;; duplicating adapter 'out' call 
223                                 
224                         )
225                         (caseARootRelativepathexprPartPart [node] 
226                                 
227                                 (println "caseARootRelativepathexprPartPart CALLED \t\t class[" (. node getClass) "] \t\t\t\t" (. node toString)) 
228                                 (stack-push node) 
229                                 
230                         )
231                 )
232                 )
233         ) 
234         
235         
236 (defmulti xpath_handler   (fn [input handler] 
237                           [
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
241                             )
242                             :handler 
243                           ])
245 (defmethod xpath_handler [:Node :handler] [node handler] 
246     
247    (try 
248       (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput (. node getCommandInput) )
249         (xpath_handler (. node getCommandInput) handler)
250         (println "EEeee.. xpath_handler not processing")
251       )
252       (catch Exception e 
253         (println "EEeee.. xpath_handler not processing > Error Message[" (. e getMessage) "]")) ;; > StackTrace[" (. e printStackTrace) "]"))
254    ) 
256 (defmethod xpath_handler [:AXpathCommandInput :handler] [xinput handler] 
257   (try  
258     (if (instance? com.interrupt.bookkeeping.cc.node.AXpathCommandInput xinput ) 
259                 
260                 (do 
261                    
262                    (println "xpath_handler > xinput[" (. xinput getClass) "]")
263                    (println "XPATH input[" (. xinput toString) "]")
264                    
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) "]" )
269                    
270                          ;; 1.1 
271                          (dosync 
272                                         
273                                         ;; put in whole xpath string 
274                                         (alter xpath-data conj { :xpath-string input-string } )
275                                         
276                                         ;; for token substring between last / and [ 
277                                         (alter xpath-data conj { 
278                                                         :leaf-node 
279                                                         (.      (:xpath-string @xpath-data) substring 
280                                                                         (+ (. (:xpath-string @xpath-data) lastIndexOf "/") 1)
281                                                                         (. (:xpath-string @xpath-data) lastIndexOf "[")) 
282                                                 })
283                                         
284                                         ;; with token, lookup context directory 
285                                         (alter xpath-data conj { :context-parent (working-dir-lookup (:leaf-node @xpath-data)) } )
286                                         
287                                         (println "LEAF token > " (:leaf-node @xpath-data))
288                                         (println "LEAF context parent > " (:context-parent @xpath-data))
289                          )
290                          
291                          ;; 1.2 build an xpath parser    
292                          (def tree (.parse (get-pushback-parser input-string))) 
293                          
294                          ;; 2. token - find i) leaf document to search ii) root & xpath expression to feed to RESTful  exist 
295                    (. tree apply (get-adapter-proxy ) )
296                          
297                          ;; 3. build RESTful call 
298                    (def db-query (str "_wrap=no&_query=" 
299                             "declare default element namespace '"(namespace-lookup (:leaf-node @xpath-data)) "';" 
300                             
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 "']" 
304                             )
305                             
306                    )
307                    
308                    
309                    (def db-full-PARENT (str db-base-URL "rootDir/" (:context-dir @xpath-data)))
310                    
311                    ;; 4. make RESTful call  &  5. pass result sequece to handler
312                    
313                                 (let [result-hash 
314                                                 (execute-http-call 
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)))
317                                                                         "GET" 
318                                                                         {"Content-Type" "text/xml"}
319                                                                         nil 
320                                                 )]
321                                   
322                                   (println "result-hash > " result-hash )
323                                         (let [  xml-string 
324                                                                         (clojure.contrib.str-utils/str-join nil 
325                                                                                 (:body-seq result-hash ))   
326                                                                 ]
327                                                 
328                                                 (println "xpath_handler > string > " xml-string )
329                                                 (handler 
330                                                         (clojure.xml/parse (ByteArrayInputStream. (. xml-string getBytes ) )))
331                                         )
332                         )
333                 )
334    )
335    (catch Exception e (println "EEeee.. xpath_hanlder not processing"))
336    )