2013-06-02 32 views
5

Clojure cung cấp một tương tác Java tốt. Tuy nhiên, tôi thực sự muốn có điều này:Bắt đầu các điểm để biến đổi các Servlet thường xuyên thành mã số DSL của tôi

(servlet IndexServlet 
    (service[parmas] ....) 
    (do-post[params] ....) 
    (do-get [params] ....)) 

(servlet-filter SecurityFilter 
    (do-filter [params] ....)) 

Tôi đoán đó là cái được gọi là DSL và trong thế giới Lisp được thực hiện qua Macros.

Tôi không biết chắc phải bắt đầu từ đâu/bắt đầu từ đâu. refiy và mở rộng các hình thức chắc chắn có vai trò quan trọng ở đây nhưng tôi không biết làm thế nào mà sẽ phù hợp với Macros.

Bắt đầu thực hiện DSL này như thế nào?
Đoạn trích, mẹo và thủ thuật thực sự được đánh giá cao.

Trả lời

3

Bạn có thể muốn xem bộ điều hợp Jetty của Ring để biết ví dụ về triển khai servlet trong Clojure. Nguồn có sẵn here (liên kết đến nguồn cho bản phát hành 1.1). Cụ thể, hàm đầu tiên được xác định trong không gian tên đó, proxy-handler trả về một trình xử lý dựa trên một lớp trừu tượng được cung cấp bởi Jetty.

Nếu bạn chọn thực hiện một cách tiếp cận tương tự (dựa trên servlet của bạn trên một lớp Java cung cấp một số phương pháp làm sẵn), bạn sẽ cần sử dụng proxy; nếu bạn chỉ cần triển khai các giao diện (không có phân lớp con), thì có thể bạn sẽ muốn thay đổi reify. Các macro có hay không sẽ hữu ích tùy thuộc vào phần nào của quá trình triển khai sẽ được sửa chữa; Bộ điều hợp Jetty của Ring sẽ không được lợi từ việc sử dụng các macro, nhưng bạn có thể (ví dụ nếu bạn muốn làm cho lớp được mở rộng/giao diện được thực hiện thành một đối số, như câu hỏi dường như chỉ ra).

Trong mọi trường hợp, bất kể chức năng nào bạn chọn triển khai sẽ cần phải là một phần của giao diện hoặc giao thức. Vì vậy, thực hiện javax.servlet.Servlet cộng với một hoạt động thêm foo có thể trông như thế này:

(import (javax.servlet Servlet ServletRequest ServletResponse)) 

(defprotocol PFoo 
    (foo [this x y z])) 

(reify 
    Servlet 
    (service [this ^ServletRequest req ^ServletResponse res] 
    ...) 
    ;; other Servlet methods here... 
    PFoo 
    (foo [this x y z] 
    ...)) 

Sau đó, bạn có thể bọc này trong một vĩ mô để cung cấp bất kỳ đường cú pháp mong muốn. Lưu ý rằng reify không thực sự quan tâm đến cách thức mà bạn interleave giao diện/tên giao thức và định nghĩa phương pháp bên trong cơ thể của nó, vì vậy bạn có thể có sinh ra các macro của bạn

(reify 
    Servlet PFoo ... ; other interfaces & protocols 
    (service [...] ...) 
    (foo [...] ...) 
    ;; other methods 
) 

nếu đó là thuận tiện hơn.

Một phác thảo của một macro dùng một tên của một giao diện servlet để thực hiện (có lẽ kéo dài javax.servlet.Servlet) và tiêm một giao thức với một số phương pháp bổ sung:

(defprotocol PFancyServlet 
    (do-get [this ...]) 
    (do-post [this ...])) 

(defmacro servlet [servlet-iface & meths] 
    `(reify ~servlet-iface PFancyServlet 
     [email protected])) 

meths sẽ cần phải bao gồm do-getdo-post cũng như servlet-iface phương pháp; bạn có thể thêm một số xác nhận đối số để đảm bảo đây là trường hợp. Ví dụ:

(servlet SomeServletInterface 
    (service [this ...] ...) 
    ;; ... 
    (do-get [this ...] ...) 
    (do-post [this ...] ...)) 
+0

Tuyệt vời! Làm thế nào tôi có thể có các hàm không có 'this' làm tham số đầu tiên? (servlet IndexServlet (do-get [yêu cầu đáp ứng])) – Chiron

+0

Bạn có thể cần phải sử dụng 'this' trong các phương thức của phương thức (nếu các phương thức gọi nhau, nói). Điều đó đang được nói, macro của bạn có thể tiền xử lý 'meths' theo các cách tùy ý, đặc biệt thêm' this' trở lại nếu bạn bỏ qua nó trong cú pháp cấp người dùng: '(cho [[meth-name params & body] meth] \' (~ meth-name ~ (vec (khuyết điểm 'tham số này)) ~ @ body)) 'hoặc một cái gì đó tương tự. Điều đó sẽ tạo ra một sự mở rộng trong đó 'this' sẽ có sẵn như là một" tham số ma thuật "trong mỗi cơ quan của phương thức. Hoặc bạn có thể sử dụng '(gensym" this __ ")' thay cho ''this' trong phần mở rộng thành" hide "' this' nếu đó là những gì bạn muốn. –

+0

Ngoài ra, 'proxy' đã làm cho' this' ngầm định (xem '(doc proxy)'), cũng như 'definterface',' gen-interface' và 'gen-class'; 'reify',' deftype', 'defrecord',' defprotocol' thì không. (Re: 'gen-class', nó là khai báo phương thức trong một dạng' gen-class' bỏ qua 'this'; các hàm thực thi phải làm cho nó rõ ràng.) –