New ROUTER design, much simpler, less generic, easier to extend, and now one can mix uri map, uri_template map and so on.
Update the "tutorial" example.
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Default router based on URI Template map
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTER
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_ROUTER_I [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
redefine
|
||||
map_agent_with_request_methods,
|
||||
map_agent_response_with_request_methods
|
||||
end
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature -- Mapping agent
|
||||
|
||||
map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE]];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
h: WSF_AGENT_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
create h.make (a_action)
|
||||
map_with_request_methods (a_id, h, rqst_methods)
|
||||
end
|
||||
|
||||
map_agent_response_with_request_methods (a_id: READABLE_STRING_8; a_action: FUNCTION [ANY, TUPLE [ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE];
|
||||
rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
local
|
||||
h: WSF_AGENT_RESPONSE_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
do
|
||||
create h.make (a_action)
|
||||
map_with_request_methods (a_id, h, rqst_methods)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -1,35 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER is a default descendant of WSF_URI_ROUTING_HANDLER_I
|
||||
for WSF_URI_TEMPLATE_ROUTER
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER_I [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
redefine
|
||||
router
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Routing
|
||||
|
||||
router: WSF_URI_TEMPLATE_ROUTER
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
+17
-14
@@ -1,32 +1,35 @@
|
||||
note
|
||||
description: "Summary description for {DEFAULT_URI_TEMPLATE_ROUTED_SERVICE}."
|
||||
description: "Summary description for {WSF_AGENT_URI_TEMPLATE_HANDLER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_TEMPLATE_ROUTED_SERVICE
|
||||
class
|
||||
WSF_AGENT_URI_TEMPLATE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_SERVICE_I [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||
redefine
|
||||
router
|
||||
end
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
create_router
|
||||
-- Create router
|
||||
--| it can be redefine to create with precise count if needed.
|
||||
make (a_action: like action)
|
||||
do
|
||||
create router.make (0)
|
||||
action := a_action
|
||||
end
|
||||
|
||||
feature -- Router
|
||||
action: PROCEDURE [ANY, TUPLE [context: WSF_URI_TEMPLATE_HANDLER_CONTEXT; request: WSF_REQUEST; response: WSF_RESPONSE]]
|
||||
|
||||
router: WSF_URI_TEMPLATE_ROUTER
|
||||
feature -- Execution
|
||||
|
||||
;note
|
||||
execute (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
action.call ([ctx, req, res])
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
@@ -0,0 +1,19 @@
|
||||
note
|
||||
description: "Summary description for EWF_URI_TEMPLATE_HANDLER."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
inherit
|
||||
WSF_HANDLER
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,81 @@
|
||||
note
|
||||
description: "Summary description for {EWF_ROUTER_URI_TEMPLATE_PATH}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_MAPPING
|
||||
|
||||
inherit
|
||||
WSF_ROUTER_MAPPING
|
||||
|
||||
create
|
||||
make,
|
||||
make_from_string
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_from_string (s: READABLE_STRING_8; h: like handler)
|
||||
do
|
||||
make (create {URI_TEMPLATE}.make (s), h)
|
||||
end
|
||||
|
||||
make (tpl: URI_TEMPLATE; h: like handler)
|
||||
do
|
||||
template := tpl
|
||||
handler := h
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
handler: WSF_URI_TEMPLATE_HANDLER
|
||||
|
||||
template: URI_TEMPLATE
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_handler (h: like handler)
|
||||
do
|
||||
handler := h
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER
|
||||
local
|
||||
tpl: URI_TEMPLATE
|
||||
p: READABLE_STRING_32
|
||||
ctx: detachable WSF_URI_TEMPLATE_HANDLER_CONTEXT
|
||||
do
|
||||
p := source_uri (req)
|
||||
tpl := based_uri_template (template, a_router)
|
||||
if attached tpl.match (p) as tpl_res then
|
||||
Result := handler
|
||||
create ctx.make (req, tpl, tpl_res, source_uri (req))
|
||||
a_router.execute_before (Current)
|
||||
ctx.apply (req)
|
||||
handler.execute (ctx, req, res)
|
||||
ctx.revert (req)
|
||||
a_router.execute_after (Current)
|
||||
end
|
||||
rescue
|
||||
if ctx /= Void then
|
||||
ctx.revert (req)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_uri_template (a_tpl: like template; a_router: WSF_ROUTER): like template
|
||||
do
|
||||
if attached a_router.base_url as l_base_url then
|
||||
Result := a_tpl.duplicate
|
||||
Result.set_template (l_base_url + a_tpl.template)
|
||||
else
|
||||
Result := a_tpl
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -1,228 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
URL dispatcher/router based on URI Template mapping and request methods if precised
|
||||
The associated context {WSF_URI_TEMPLATE_HANDLER_CONTEXT} contains information about the matched map.
|
||||
|
||||
Examples:
|
||||
|
||||
map ("/users/", users_handler)
|
||||
map_with_request_methods ("/order/{order-id}", order_handler, <<"GET", "POST">>)
|
||||
map_agent_with_request_methods ("/order/{order-id}", agent do_get_order, <<"GET">>)
|
||||
map_agent_with_request_methods ("/order/{order-id}", agent do_post_order, <<"POST">>)
|
||||
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTER_I [H -> WSF_HANDLER [C], C -> WSF_URI_TEMPLATE_HANDLER_CONTEXT create make end]
|
||||
|
||||
inherit
|
||||
WSF_ROUTER [H, C]
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create handlers.make (n)
|
||||
create templates.make (n)
|
||||
handlers.compare_objects
|
||||
initialize
|
||||
end
|
||||
|
||||
make_with_base_url (n: INTEGER; a_base_url: like base_url)
|
||||
-- Make router allocated for at least `n' maps,
|
||||
-- and use `a_base_url' as base_url
|
||||
do
|
||||
make (n)
|
||||
set_base_url (a_base_url)
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
handlers_matching_map (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_ROUTER_METHODS): detachable LIST [H]
|
||||
local
|
||||
l_res: READABLE_STRING_8
|
||||
do
|
||||
l_res := based_resource (a_resource)
|
||||
across
|
||||
handlers as c
|
||||
loop
|
||||
if c.item.resource.same_string (l_res) then
|
||||
if
|
||||
rqst_methods = Void or else
|
||||
across rqst_methods as rq some is_matching_request_methods (rq.item, c.item.request_methods) end
|
||||
then
|
||||
if Result = Void then
|
||||
create {ARRAYED_LIST [H]} Result.make (1)
|
||||
end
|
||||
Result.extend (c.item.handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Registration
|
||||
|
||||
map_with_uri_template (uri: URI_TEMPLATE; h: H)
|
||||
require
|
||||
has_not_such_map: not has_map (uri.template, Void, h)
|
||||
do
|
||||
map_with_uri_template_and_request_methods (uri, h, Void)
|
||||
end
|
||||
|
||||
map_with_uri_template_and_request_methods (uri: URI_TEMPLATE; h: H; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
require
|
||||
uri_is_valid: uri.is_valid
|
||||
has_not_such_map: not has_map (uri.template, rqst_methods, h)
|
||||
local
|
||||
l_tpl: like {URI_TEMPLATE}.template
|
||||
l_uri: URI_TEMPLATE
|
||||
do
|
||||
l_uri := based_uri (uri)
|
||||
l_tpl := l_uri.template
|
||||
|
||||
handlers.force ([h, l_tpl, rqst_methods])
|
||||
templates.force (l_uri, l_tpl)
|
||||
h.on_handler_mapped (l_tpl, rqst_methods)
|
||||
end
|
||||
|
||||
map_with_request_methods (tpl: READABLE_STRING_8; h: H; rqst_methods: detachable WSF_ROUTER_METHODS)
|
||||
do
|
||||
map_with_uri_template_and_request_methods (create {URI_TEMPLATE}.make (tpl), h, rqst_methods)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
based_uri (uri: URI_TEMPLATE): URI_TEMPLATE
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
Result := uri.duplicate
|
||||
Result.set_template (l_base_url + uri.template)
|
||||
else
|
||||
Result := uri
|
||||
end
|
||||
end
|
||||
|
||||
based_resource (a_resource: READABLE_STRING_8): READABLE_STRING_8
|
||||
do
|
||||
if attached base_url as l_base_url then
|
||||
Result := l_base_url + a_resource
|
||||
else
|
||||
Result := a_resource
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Handler
|
||||
|
||||
matching_route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C]
|
||||
local
|
||||
l_handlers: like handlers
|
||||
t: READABLE_STRING_8
|
||||
p: READABLE_STRING_8
|
||||
l_req_method: READABLE_STRING_8
|
||||
l_res: URI_TEMPLATE_MATCH_RESULT
|
||||
do
|
||||
p := source_uri (req)
|
||||
from
|
||||
l_req_method := request_method (req)
|
||||
l_handlers := handlers
|
||||
l_handlers.start
|
||||
until
|
||||
l_handlers.after or Result /= Void
|
||||
loop
|
||||
if attached l_handlers.item as l_info then
|
||||
if is_matching_request_methods (l_req_method, l_info.request_methods) then
|
||||
t := l_info.resource
|
||||
if
|
||||
attached {WSF_ROUTING_HANDLER [H, C]} l_info.handler as rah and then
|
||||
p.starts_with (t)
|
||||
then
|
||||
create l_res.make_empty
|
||||
l_res.path_variables.force (p.substring (t.count + 1, p.count), "path")
|
||||
|
||||
create Result.make (l_info.handler, handler_context (p, req, create {URI_TEMPLATE}.make (t), l_res))
|
||||
elseif attached templates.item (t) as tpl and then
|
||||
attached tpl.match (p) as res
|
||||
then
|
||||
create Result.make (l_info.handler, handler_context (p, req, tpl, res))
|
||||
end
|
||||
end
|
||||
end
|
||||
l_handlers.forth
|
||||
end
|
||||
end
|
||||
|
||||
feature {WSF_ROUTED_SERVICE_I} -- Default: implementation
|
||||
|
||||
default_handler_context (req: WSF_REQUEST): C
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := handler_context (Void, req, create {URI_TEMPLATE}.make ("/"), create {URI_TEMPLATE_MATCH_RESULT}.make_empty)
|
||||
end
|
||||
|
||||
feature {NONE} -- Context factory
|
||||
|
||||
handler_context (p: detachable READABLE_STRING_8; req: WSF_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): C
|
||||
do
|
||||
if p /= Void then
|
||||
create Result.make (req, tpl, tpl_res, p)
|
||||
else
|
||||
create Result.make (req, tpl, tpl_res, source_uri (req))
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access: ITERABLE
|
||||
|
||||
new_cursor: ITERATION_CURSOR [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Fresh cursor associated with current structure
|
||||
do
|
||||
Result := handlers.new_cursor
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
handlers: ARRAYED_LIST [TUPLE [handler: H; resource: READABLE_STRING_8; request_methods: detachable WSF_ROUTER_METHODS]]
|
||||
-- Handlers indexed by the template expression
|
||||
-- see `templates'
|
||||
|
||||
templates: HASH_TABLE [URI_TEMPLATE, READABLE_STRING_8]
|
||||
-- URI Template indexed by the template expression
|
||||
|
||||
context_path (a_path: STRING): STRING
|
||||
-- Prepared path from context which match requirement
|
||||
-- i.e: not empty, starting with '/'
|
||||
local
|
||||
p: INTEGER
|
||||
do
|
||||
Result := a_path
|
||||
if Result.is_empty then
|
||||
Result := "/"
|
||||
else
|
||||
if Result[1] /= '/' then
|
||||
Result := "/" + Result
|
||||
end
|
||||
p := Result.index_of ('.', 1)
|
||||
if p > 0 then
|
||||
Result := Result.substring (1, p - 1)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
result_not_empty: not Result.is_empty
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
This class helps to build Routing handler based for WSF_URI_TEMPLATE_ROUTER
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_URI_TEMPLATE_ROUTING_HANDLER_I [H -> WSF_HANDLER [C],
|
||||
C -> WSF_URI_TEMPLATE_HANDLER_CONTEXT create make end]
|
||||
|
||||
inherit
|
||||
WSF_ROUTING_HANDLER [H, C]
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base_url
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
create router.make (n)
|
||||
end
|
||||
|
||||
make_with_base_url (n: INTEGER; a_base_url: like base_url)
|
||||
-- Make allocated for at least `n' maps,
|
||||
-- and use `a_base_url' as base_url
|
||||
do
|
||||
create router.make_with_base_url (n, a_base_url)
|
||||
end
|
||||
|
||||
feature {NONE} -- Routing
|
||||
|
||||
router: WSF_URI_TEMPLATE_ROUTER_I [H, C]
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
Reference in New Issue
Block a user