diff --git a/library/server/wsf/router/uri/default/wsf_uri_router.e b/library/server/wsf/router/uri/default/wsf_uri_router.e index 7ec82c2e..e697561d 100644 --- a/library/server/wsf/router/uri/default/wsf_uri_router.e +++ b/library/server/wsf/router/uri/default/wsf_uri_router.e @@ -1,6 +1,7 @@ note - description: "Summary description for {DEFAULT_REQUEST_URI_ROUTER}." - author: "" + description: "[ + Default router based on URI map + ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/uri/default/wsf_uri_routing_handler.e b/library/server/wsf/router/uri/default/wsf_uri_routing_handler.e index f0c107f2..0d06d477 100644 --- a/library/server/wsf/router/uri/default/wsf_uri_routing_handler.e +++ b/library/server/wsf/router/uri/default/wsf_uri_routing_handler.e @@ -1,6 +1,8 @@ note - description: "Summary description for {DEFAULT_REQUEST_URI_ROUTING_HANDLER}." - author: "" + description: "[ + WSF_URI_ROUTING_HANDLER is a default descendant of WSF_URI_ROUTING_HANDLER_I + for WSF_URI_ROUTER + ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/uri/wsf_uri_handler_context.e b/library/server/wsf/router/uri/wsf_uri_handler_context.e index b9b6fa0b..78c8db76 100644 --- a/library/server/wsf/router/uri/wsf_uri_handler_context.e +++ b/library/server/wsf/router/uri/wsf_uri_handler_context.e @@ -1,6 +1,11 @@ note - description: "Summary description for {WSF_URI_HANDLER_CONTEXT}." - author: "" + description: "[ + Context for the handler execution + + It does not provide additional information compared to {WSF_HANDLER_CONTEXT} + - request: WSF_REQUEST -- Associated request + - path: READABLE_STRING_8 -- Associated path + ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/uri/wsf_uri_router_i.e b/library/server/wsf/router/uri/wsf_uri_router_i.e index 8bcf4eb1..aa38ed97 100644 --- a/library/server/wsf/router/uri/wsf_uri_router_i.e +++ b/library/server/wsf/router/uri/wsf_uri_router_i.e @@ -1,6 +1,20 @@ note - description: "Summary description for {WSF_URI_ROUTER}." - author: "" + description: "[ + URL dispatcher/router based on simple URI mapping and request methods if precised + The associated context {WSF_URI_HANDLER_CONTEXT} does not contains any additional information. + + The matching check if the same path is mapped, or if a substring of the path is mapped + + Examples: + + map ("/users/", users_handler) + map_with_request_methods ("/groups/", read_groups_handler, <<"GET">>) + map_with_request_methods ("/groups/", write_groups_handler, <<"POST", "PUT", "DELETE">>) + map_agent_with_request_methods ("/order/", agent do_get_order, <<"GET">>) + map_agent_with_request_methods ("/order/", agent do_post_order, <<"POST">>) + + + ]" date: "$Date$" revision: "$Revision$" @@ -30,7 +44,7 @@ feature -- Initialization set_base_url (a_base_url) end -feature -- Status report +feature {WSF_ROUTED_SERVICE_I} -- Status report handlers_matching_map (a_resource: READABLE_STRING_8; rqst_methods: detachable ARRAY [READABLE_STRING_8]): detachable LIST [H] local @@ -54,6 +68,14 @@ feature -- Status report end end +feature {WSF_ROUTED_SERVICE_I} -- Default: implementation + + default_handler_context (req: WSF_REQUEST): C + -- + do + Result := handler_context (Void, req) + end + feature -- Registration map_with_request_methods (p: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8]) @@ -82,10 +104,10 @@ feature {NONE} -- Implementation feature {NONE} -- Access: Implementation - handler (req: WSF_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] + handler (req: WSF_REQUEST): detachable WSF_ROUTE [H, C] local h: detachable H - ctx: detachable like default_handler_context + ctx: detachable C do h := handler_by_path (source_uri (req), req.request_method) if h = Void then @@ -99,7 +121,7 @@ feature {NONE} -- Access: Implementation if ctx = Void then ctx := handler_context (Void, req) end - Result := [h, ctx] + create Result.make (h, ctx) else Result := Void end @@ -219,20 +241,6 @@ feature {NONE} -- Implementation result_not_empty: not Result.is_empty end -feature {NONE} -- Default: implementation - - default_handler: detachable H - - set_default_handler (h: like default_handler) - do - default_handler := h - end - - default_handler_context (req: WSF_REQUEST): C - do - Result := handler_context (Void, req) - 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)" diff --git a/library/server/wsf/router/uri/wsf_uri_routing_handler_i.e b/library/server/wsf/router/uri/wsf_uri_routing_handler_i.e index 180561a8..81a048ae 100644 --- a/library/server/wsf/router/uri/wsf_uri_routing_handler_i.e +++ b/library/server/wsf/router/uri/wsf_uri_routing_handler_i.e @@ -1,5 +1,7 @@ note - description: "Summary description for {WSF_ROUTING_HANDLER }." + description: "[ + This class helps to build Routing handler based for WSF_URI_ROUTER + ]" author: "" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/uri_template/default/wsf_uri_template_router.e b/library/server/wsf/router/uri_template/default/wsf_uri_template_router.e index b6f4191d..a29c3492 100644 --- a/library/server/wsf/router/uri_template/default/wsf_uri_template_router.e +++ b/library/server/wsf/router/uri_template/default/wsf_uri_template_router.e @@ -1,6 +1,7 @@ note - description: "Summary description for {DEFAULT_REQUEST_URI_TEMPLATE_ROUTER}." - author: "" + description: "[ + Default router based on URI Template map + ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/uri_template/default/wsf_uri_template_routing_handler.e b/library/server/wsf/router/uri_template/default/wsf_uri_template_routing_handler.e index 2606c521..f51843a7 100644 --- a/library/server/wsf/router/uri_template/default/wsf_uri_template_routing_handler.e +++ b/library/server/wsf/router/uri_template/default/wsf_uri_template_routing_handler.e @@ -1,6 +1,8 @@ note - description: "Summary description for {DEFAULT_REQUEST_URI_TEMPLATE_ROUTING_HANDLER}." - author: "" + 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$" diff --git a/library/server/wsf/router/uri_template/wsf_uri_template_handler_context.e b/library/server/wsf/router/uri_template/wsf_uri_template_handler_context.e index b25410e0..d5a0799c 100644 --- a/library/server/wsf/router/uri_template/wsf_uri_template_handler_context.e +++ b/library/server/wsf/router/uri_template/wsf_uri_template_handler_context.e @@ -1,6 +1,17 @@ note - description: "Summary description for {WSF_URI_TEMPLATE_HANDLER_CONTEXT}." - author: "" + description: "[ + Context for the handler execution + + The associated context {WSF_URI_TEMPLATE_HANDLER_CONTEXT} add information about the matched map + - uri_template : the associated URI_TEMPLATE + - uri_template_match : the matching result providing path variables + - additional path_parameter (..) and related queries + + In addition to what WSF_HANDLER_CONTEXT already provides, i.e: + - request: WSF_REQUEST -- Associated request + - path: READABLE_STRING_8 -- Associated path + + ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/uri_template/wsf_uri_template_router_i.e b/library/server/wsf/router/uri_template/wsf_uri_template_router_i.e index b76fbbb0..7c3ce35a 100644 --- a/library/server/wsf/router/uri_template/wsf_uri_template_router_i.e +++ b/library/server/wsf/router/uri_template/wsf_uri_template_router_i.e @@ -1,6 +1,16 @@ note - description: "Summary description for {WSF_URI_TEMPLATE_ROUTER}." - author: "" + 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$" @@ -108,7 +118,7 @@ feature {NONE} -- Implementation feature {WSF_ROUTED_SERVICE_I} -- Handler - handler (req: WSF_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context] + matching_route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C] local l_handlers: like handlers t: READABLE_STRING_8 @@ -134,11 +144,11 @@ feature {WSF_ROUTED_SERVICE_I} -- Handler create l_res.make_empty l_res.path_variables.force (p.substring (t.count + 1, p.count), "path") - Result := [l_info.handler, handler_context (p, req, create {URI_TEMPLATE}.make (t), l_res)] + 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 - Result := [l_info.handler, handler_context (p, req, tpl, res)] + create Result.make (l_info.handler, handler_context (p, req, tpl, res)) end end end @@ -146,6 +156,14 @@ feature {WSF_ROUTED_SERVICE_I} -- Handler end end +feature {WSF_ROUTED_SERVICE_I} -- Default: implementation + + default_handler_context (req: WSF_REQUEST): C + -- + 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 @@ -196,20 +214,6 @@ feature {NONE} -- Implementation result_not_empty: not Result.is_empty end -feature {NONE} -- Default: implementation - - default_handler: detachable H - - set_default_handler (h: like default_handler) - do - default_handler := h - end - - default_handler_context (req: WSF_REQUEST): C - do - Result := handler_context (Void, req, create {URI_TEMPLATE}.make ("/"), create {URI_TEMPLATE_MATCH_RESULT}.make_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)" diff --git a/library/server/wsf/router/uri_template/wsf_uri_template_routing_handler_i.e b/library/server/wsf/router/uri_template/wsf_uri_template_routing_handler_i.e index 6f8396d7..d6fd3dcf 100644 --- a/library/server/wsf/router/uri_template/wsf_uri_template_routing_handler_i.e +++ b/library/server/wsf/router/uri_template/wsf_uri_template_routing_handler_i.e @@ -1,6 +1,7 @@ note - description: "Summary description for {WSF_ROUTING_HANDLER }." - author: "" + description: "[ + This class helps to build Routing handler based for WSF_URI_TEMPLATE_ROUTER + ]" date: "$Date$" revision: "$Revision$" diff --git a/library/server/wsf/router/wsf_handler_context.e b/library/server/wsf/router/wsf_handler_context.e index 1a321eab..ed0e8009 100644 --- a/library/server/wsf/router/wsf_handler_context.e +++ b/library/server/wsf/router/wsf_handler_context.e @@ -1,7 +1,10 @@ note description: "[ - - ]" + Context for the handler execution + It provides information related to the matching handler at runtime, i.e: + - request: WSF_REQUEST -- Associated request + - path: READABLE_STRING_8 -- Associated path + ]" date: "$Date$" revision: "$Revision$" @@ -114,14 +117,6 @@ feature -- Item deferred end - parameter (a_name: READABLE_STRING_8): detachable WSF_VALUE - -- Variable value for parameter or variable `a_name' - -- See `{WSF_REQUEST}.item(s)' - obsolete "[2012-Mars-19] Use `item (a_name)' ." - do - Result := item (a_name) - end - feature -- Parameter string_item (a_name: READABLE_STRING_8): detachable READABLE_STRING_32 @@ -130,13 +125,6 @@ feature -- Parameter Result := string_from (item (a_name)) end - string_parameter (a_name: READABLE_STRING_8): detachable READABLE_STRING_32 - -- String value for any variable of parameter `a_name' if relevant. - obsolete "[2012-Mars-19] Use `string_item (a_name)' ." - do - Result := string_item (a_name) - end - string_array_item (a_name: READABLE_STRING_8): detachable ARRAY [READABLE_STRING_32] -- Array of string values for query parameter `a_name' if relevant. do diff --git a/library/server/wsf/router/wsf_route.e b/library/server/wsf/router/wsf_route.e new file mode 100644 index 00000000..57afda65 --- /dev/null +++ b/library/server/wsf/router/wsf_route.e @@ -0,0 +1,45 @@ +note + description: "[ + a WSF_ROUTE object associates a handler and the associated context at runtime + ]" + date: "$Date$" + revision: "$Revision$" + +class + WSF_ROUTE [H -> WSF_HANDLER [C], C -> WSF_HANDLER_CONTEXT] + +create + make + +feature {NONE} -- Initialization + + make (h: H; c: C) + -- Instantiate Current with `h' and `c' + do + handler := h + context := c + end + +feature -- Access + + handler: H + -- Handler + + context: C + -- Context associated to `handler' for execution + +invariant + handler /= Void + context /= Void + +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 diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e index d15a4fed..b6a7226e 100644 --- a/library/server/wsf/router/wsf_router.e +++ b/library/server/wsf/router/wsf_router.e @@ -1,6 +1,8 @@ note - description: "Summary description for {WSF_ROUTER}." - author: "" + description: "[ + URL dispatcher/router based on deferred mapping (to be defined in descendant) + The associated context {WSF_HANDLER_CONTEXT} does contains information related to the matching at runtime. + ]" date: "$Date$" revision: "$Revision$" @@ -27,14 +29,6 @@ feature -- Status report feature -- Mapping - map_default (h: like default_handler) - -- Map default handler - -- If no route/handler is found, - -- then use `default_handler' as default if not Void - do - set_default_handler (h) - end - map (a_resource: READABLE_STRING_8; h: H) -- Map handler `h' with `a_resource' require @@ -61,12 +55,14 @@ feature -- Mapping feature -- Mapping agent map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]) + -- Map `a_action' as an handler with `a_resource' do map_agent_with_request_methods (a_resource, a_action, Void) end map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) + -- Map `a_action' as an handler with `a_resource' and `rqst_methods' local rah: WSF_AGENT_HANDLER [C] do @@ -80,17 +76,19 @@ feature -- Mapping agent feature -- Mapping response agent - map_agent_response (a_resource: READABLE_STRING_8; a_action: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]) + map_agent_response (a_resource: READABLE_STRING_8; a_function: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]) + -- Map response as Result `a_function' as an handler with `a_resource' do - map_agent_response_with_request_methods (a_resource, a_action, Void) + map_agent_response_with_request_methods (a_resource, a_function, Void) end - map_agent_response_with_request_methods (a_resource: READABLE_STRING_8; a_action: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]; + map_agent_response_with_request_methods (a_resource: READABLE_STRING_8; a_function: FUNCTION [ANY, TUPLE [ctx: C; req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) + -- Map response as Result `a_function' as an handler with `a_resource' and `rqst_methods' local rah: WSF_AGENT_RESPONSE_HANDLER [C] do - create rah.make (a_action) + create rah.make (a_function) if attached {H} rah as h then map_with_request_methods (a_resource, h, rqst_methods) else @@ -120,36 +118,47 @@ feature -- Element change feature -- Execution + route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C] + -- Route matching `req'. + do + Result := matching_route (req) + end + + execute_route (a_route: WSF_ROUTE [H,C]; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Process route `a_route' + require + a_route_attached: a_route /= Void + do + a_route.handler.execute (a_route.context, req, res) + end + dispatch (req: WSF_REQUEST; res: WSF_RESPONSE): BOOLEAN -- Dispatch `req, res' to the associated handler -- And return True is handled, otherwise False do - Result := dispatch_and_return_handler (req, res) /= Void + if attached route (req) as r then + Result := True + execute_route (r, req, res) + end end dispatch_and_return_handler (req: WSF_REQUEST; res: WSF_RESPONSE): detachable H -- Dispatch `req, res' to the associated handler -- And return this handler -- If Result is Void, this means no handler was found. - local - d: like handler - ctx: detachable like default_handler_context do - d := handler (req) - if d /= Void then - Result := d.handler - ctx := d.context - else - Result := default_handler - if Result /= Void then - ctx := default_handler_context (req) - end + if attached route (req) as r then + Result := r.handler + execute_route (r, req, res) end - if Result /= Void and ctx /= Void then - Result.execute (ctx, req, res) - end - ensure - result_void_implie_no_default: Result = Void implies default_handler = Void + end + +feature {WSF_ROUTED_SERVICE_I} -- Implementation + + default_handler_context (req: WSF_REQUEST): C + -- Default handler context associated with `req'. + --| It can be used to build a context if needed. + deferred end feature -- status report @@ -183,8 +192,8 @@ feature {WSF_ROUTED_SERVICE_I} -- Handler Result := req.path_info end - handler (req: WSF_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] - -- Handler whose map matched with `req' + matching_route (req: WSF_REQUEST): detachable WSF_ROUTE [H, C] + -- Handler whose map matched with `req' with associated Context require req_valid: source_uri (req) /= Void deferred @@ -194,21 +203,21 @@ feature {WSF_ROUTED_SERVICE_I} -- Handler feature {NONE} -- Access: Implementation - is_matching_request_methods (a_request_method: READABLE_STRING_GENERAL; rqst_methods: like formatted_request_methods): BOOLEAN - -- `a_request_method' is matching `rqst_methods' contents + is_matching_request_methods (a_request_method: READABLE_STRING_GENERAL; a_rqst_methods: like formatted_request_methods): BOOLEAN + -- `a_request_method' is matching `a_rqst_methods' contents local i,n: INTEGER m: READABLE_STRING_GENERAL do - if rqst_methods /= Void and then not rqst_methods.is_empty then + if a_rqst_methods /= Void and then not a_rqst_methods.is_empty then m := a_request_method from - i := rqst_methods.lower - n := rqst_methods.upper + i := a_rqst_methods.lower + n := a_rqst_methods.upper until i > n or Result loop - Result := m.same_string (rqst_methods[i]) + Result := m.same_string (a_rqst_methods [i]) i := i + 1 end else @@ -236,27 +245,6 @@ feature {NONE} -- Access: Implementation end end -feature {NONE} -- Implementation - - set_default_handler (h: like default_handler) - -- Set `default_handler' to `h' - deferred - ensure - default_handler_set: h = default_handler - end - - default_handler: detachable H - -- Default handler - deferred - end - - default_handler_context (req: WSF_REQUEST): C - -- Default handler context associated with `default_handler' - require - has_default_handler: default_handler /= Void - deferred - 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)" diff --git a/library/server/wsf/router/wsf_routing_handler.e b/library/server/wsf/router/wsf_routing_handler.e index 919d2671..a33ca438 100644 --- a/library/server/wsf/router/wsf_routing_handler.e +++ b/library/server/wsf/router/wsf_routing_handler.e @@ -1,6 +1,25 @@ note - description: "Summary description for {WSF_ROUTING_HANDLER }." - author: "" + description: "[ + WSF_ROUTING_HANDLER is mainly to group a set of handler having the same base + such as /users for + /users/by/id/{id} + /users/by/name/name} + + It can be used to optimize the router, where the router checks only the base path before checking each entries + Then for + /a/a1 + /a/a2 + /a/a3 + /a/a4 + /b/b1 + /b/b2 + /b/b3 + 2 routing handlers could be used "/a" and "/b" + then to find the /b/b2 match, the router has to do only + /a /b /b/b1 and /b/b2 i.e: 4 checks + instead of /a/a1 /a/a2 /a/a3 /a/a4 /b/b1 /b/b2: i.e: 6 checks + On router with deep arborescence this could be significant + ]" date: "$Date$" revision: "$Revision$" @@ -40,11 +59,13 @@ feature -- Execution execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request handler local - hdl: detachable H + r: detachable WSF_ROUTE [H, C] do - hdl := router.dispatch_and_return_handler (req, res) - if hdl = Void then + r := router.route (req) + if r = Void then res.put_header ({HTTP_STATUS_CODE}.not_found, <<[{HTTP_HEADER_NAMES}.header_content_length, "0"]>>) + else + router.execute_route (r, req, res) end end @@ -56,14 +77,6 @@ feature {NONE} -- Routing feature -- Mapping - map_default (h: detachable H) - -- Map default handler - -- If no route/handler is found, - -- then use `default_handler' as default if not Void - do - router.map_default (h) - end - map (a_resource: READABLE_STRING_8; h: H) -- Map handler `h' with `a_resource' do