You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by Apache Bloodhound <de...@bloodhound.apache.org> on 2013/06/04 05:45:42 UTC

[Apache Bloodhound] Proposals/BEP-0003 modified

Page "Proposals/BEP-0003" was changed by olemis
Diff URL: <https://issues.apache.org/bloodhound/wiki/Proposals/BEP-0003?action=diff&version=35>
Revision 35
Comment: bep:0003 Remove details related to Routes framework
Changes:
-------8<------8<------8<------8<------8<------8<------8<------8<--------
Index: Proposals/BEP-0003
=========================================================================
--- Proposals/BEP-0003 (version: 34)
+++ Proposals/BEP-0003 (version: 35)
@@ -58,7 +58,7 @@
 
 }}}
 
-Product environments will not be recursive , which means that the following statement will fail
+Product environments will not be recursive, which means that the following statement will fail
 
 {{{
 #!py
@@ -92,7 +92,7 @@
   Implementation notes
 }}} 
 
-In order to make this happen and yet avoid object explosion , some caching strategy (e.g. [http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used LRU cache] like [http://docs.python.org/dev/library/functools.html#functools.lru_cache functools.lru_cache] or equivalent) should be installed in place , maybe combined with [http://docs.python.org/2.7/library/weakref.html weak references] .
+In order to make this happen and yet avoid object explosion, some caching strategy (e.g. [http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used LRU cache] like [http://docs.python.org/dev/library/functools.html#functools.lru_cache functools.lru_cache] or equivalent) should be installed in place, maybe combined with [http://docs.python.org/2.7/library/weakref.html weak references] .
 
 }}}
 
@@ -152,64 +152,75 @@
 
 [=#product-env-idem] Remaining members of `trac.env.Environment` will be returned by product environments too.
 
-=== Product routes #routes
-
-[http://routes.groovie.org/ Routes] framework will be used to match URLs based on predefined patterns and use this information to dispatch requests addressed to product environments. This will introduce an explicit installation dependency with that framework. 
-
-In first place there will be an instance of `routes.mapper.Mapper`. It will contain the definitions of the routes used to access product environments and their resources. Some variables in routes definitions will have special meaning though.
-
-||= Variable =||= Purpose =||= Observations =||
-|| `controller` || ''Ignored'' ||  ||
-|| `action` || ''Ignored'' ||  ||
-|| `envname` || Target environment name || Only used in multiple environment mode to determine target environment folder. Ignored otherwise. ||
-|| `product` || Target product prefix || Represents  ||
-|| `path_info` || Path to product resource or view  || Since paths under product base URL will be used to access anything that could be considered as belonging to the product, route definitions often will include [http://routes.readthedocs.org/en/latest/setting_up.html#magic-path-info path_info] to shift `SCRIPT_NAME` and `PATH_INFO` ''WSGI'' variables as expected ||
-
-Considering the previous discussion ''Bloodhound'' will provide a modified copy of the main entry point for the web interface (i.e. the [http://www.python.org/dev/peps/pep-0333/ WSGI] function `trac.web.main.dispatch_request`) to make it aware of external routing information. It will be wrapped by a `routes.middleware.RoutesMiddleware` object responsible for route matching and ''WSGI'' environment updates. This fact is important to understand subsequent discussion taking place in this section.
-
-Aforementioned data will be considered to dispatch requests in addition to the existing ''WSGI'' environment variables (i.e. `trac.env_path`, `trac.env_parent_dir`, `trac.env_index_template`, `trac.template_vars`, `trac.base_url`, `trac.env_paths`) or the equivalent global variables (i.e. `TRAC_ENV`, `TRAC_ENV_PARENT_DIR`, `TRAC_ENV_INDEX_TEMPLATE`, `TRAC_TEMPLATE_VARS`, `TRAC_BASE_URL`). The updated copy of `trac.web.main.dispatch_request` will read routing information like shown below
-
-{{{
-#!py
-
-route = environ.get('routes.route')
-match = environ.get('wsgiorg.routing_args', (None, {}) )[1]
-
-}}}
-
-==== Environment lookup #env-dispatch
-
-As a result the following rules will be used to determine the environment performing subsequent request dispatching :
-
-  - If `match == {}` (equivalent to `route is None`)
-    then no route was matched, hence respond with a 
-    404 (''Not Found'') HTTP status code.
-  - ... else if `match['envname']` is empty then no 
-    specific environment was requested. 
-    * For multi-environment deployments 
-      (i.e. `TRAC_ENV_PARENT_DIR`) just render an 
-      environment index page.
-    * For single-environment deployments always 
-      instantiate configured environment.
-  - ... for multi-environment deployments, if 
-    `match['envname']` is not empty then 
-    instantiate the environment at the corresponding 
-    child folder of the parent directory.
-  - ... if `match['product']` is empty then the 
-    global environment found up to this point will dispatch the 
-    request
-  - ... else if `match['product']` is set then 
-    [#product-env-api instantiate the product environment]
-    for the corresponding product prefix. There will be
-    an instance of `trac.web.main.RequestDispatcher`
-    responsible for further request dispatching in that 
-    context.
-
-Sub-paths will be handled from there as usual.
+=== Web bootstrap handlers and hooks #hooks
+
+Web bootstrap handlers are needed to cope with flexible [#url-mapping URL mappings]. Their type contract is defined as follows:
+
+{{{#!py
+
+class BootstrapHandlerBase(object):
+    """Objects responsible for loading the target environment and
+    request objects used in subsequent dispatching. 
+    """
+    def open_environment(self, environ, start_response):
+        """Load and initialize target Trac environment involved in request
+        dispatching.
+
+        The following WSGI entries will also be present in `environ` dict:
+
+        ||= WSGI variable =||= Environment variable =||= Comment =||
+        || trac.env_path || TRAC_ENV || See wiki:TracModWSGI ||
+        || trac.env_parent_dir || TRAC_ENV_PARENT_DIR || See wiki:TracModWSGI||
+        || trac.env_index_template || TRAC_ENV_INDEX_TEMPLATE || See wiki:TracInterfaceCustomization ||
+        || trac.template_vars || TRAC_TEMPLATE_VARS || See wiki:TracInterfaceCustomization ||
+        || trac.locale ||  || Target locale ||
+        || trac.base_url || TRAC_BASE_URL || Trac base URL hint ||
+
+        This method may handle the request (e.g. render environment index page)
+        in case environment lookup yields void results. In that case it MUST 
+        invoke WSGI `write` callable returned by `start_response` and raise 
+        `trac.web.api.RequestDone` exception.
+
+        :param environ: WSGI environment dict
+        :param start_response: WSGI callback for starting the response
+        :throws RequestDone: if the request is fully processed while loading
+                             target environment e.g. environment index page
+        :throws EnvironmentError: if it is impossible to find a way to locate
+                                  target environment e.g. TRAC_ENV and 
+                                  TRAC_ENV_PARENT_DIR both missing
+        :throws Exception: any other exception will be processed by the caller 
+                           in order to send a generic error message back to
+                           the HTTP client
+        """
+        raise NotImplementedError("Must override method 'open_environment'")
+
+    def create_request(self, env, environ, start_response):
+        """Instantiate request object used in subsequent request dispatching
+        
+        :param env: target Trac environment returned by `open_environment`
+        :param environ: WSGI environment dict
+        :param start_response: WSGI callback for starting the response
+        """
+        raise NotImplementedError("Must override method 'create_request'")
+
+}}}
+
+{{{#div class="well"
+
+{{{#!span class="label label-info"
+Note
+}}}
+
+[attachment:t514_r1477773_tracd_bootstrap.diff:ticket:514 A patch] has been proposed in #514 to
+augment the web bootstrap handlers protocol by adding `probe_environment` method, since it's needed
+to make TracStandalone authentication middlewares work under the new conditions.
+}}}
+
+Default bootstrap handler is a façade to underlying environment and request factories (i.e. hooks) which in turn by default [#deploy-global-env-embed embed product URL namespace into global namespace]. Other web bootstrap handlers may be contributed by third party libraries e.g. those implementing ([#reject-routes rejected]) [./Routes Routes dispatching]. In order to select a given handler set either `trac.bootstrap_handler` WSGI variable or `TRAC_BOOTSTRAP_HANDLER` environment variable to an [#ref3 entry point expression] pointing to the target instance.
 
 === Resource neighborhoods #resource-neighborhood
 
-''Apache™ Bloodhound'' will expand resources API by introducing the concept of ''Neighborhoods''. In a few words they are the topmost level of the hierarchy representing resources managed by a component manager, thereby identifying the later. As such ''resource neighborhoods'' serve to the purpose of specifying absolute references to resources hosted beyond the boundaries of a given component manager (e.g. ''Trac'' environments , [#product-envs product environments], ...) . As a side effect they will be used to load manager objects on demand.
+''Apache™ Bloodhound'' will expand resources API by introducing the concept of ''Neighborhoods''. In a few words they are the topmost level of the hierarchy representing resources managed by a component manager, thereby identifying the later. As such ''resource neighborhoods'' serve to the purpose of specifying absolute references to resources hosted beyond the boundaries of a given component manager (e.g. ''Trac'' environments, [#product-envs product environments], ...) . As a side effect they will be used to load manager objects on demand.
 
 '''Resource neighborhoods''' will always be at the top of the resources hierarchy . Instances will have a ''realm'' identifying the kind of manager (e.g. `global` for ''Trac'' environment, `product` for product environments). For example the following resource identifiers will point to `attachment:file.txt:ticket:1` resource in local scope, product `P1`, product `P2` and global environment, in that order.
 
@@ -325,7 +336,7 @@
 
 Implementation notes
 }}}
-The code of Trac components structures file-system access using paths relative to the environment's top-level folder . Considering the fact that plugins migration towards multi-product support should be as smooth as possible the layout of product file-system area will be exactly the same as before . In other words , if the global environment's root folder is `/path/to/env` then the root folder of file-system area for product (prefix) `P` will be `/path/to/env/products/P` . Attachment `foo.txt` for ticket `42` in product `P` will be located at `/path/to/env/products/P/files/attachments/ticket/92c/92cfceb39d57d914ed8b14d0e37643de0797ae56/9206ac42b532ef8e983470c251f4e1a365fd636c.txt` whereas attachment `foo.txt` for ticket `42` in the global environment will be located at `/path/to/env/files/attachments/ticket/92c/92cfceb39d57d914ed8b14d0e37643de0797ae56/9206ac42b532ef8e983470c251f4e1a365fd636c.txt`.
+The code of Trac components structures file-system access using paths relative to the environment's top-level folder . Considering the fact that plugins migration towards multi-product support should be as smooth as possible the layout of product file-system area will be exactly the same as before . In other words, if the global environment's root folder is `/path/to/env` then the root folder of file-system area for product (prefix) `P` will be `/path/to/env/products/P` . Attachment `foo.txt` for ticket `42` in product `P` will be located at `/path/to/env/products/P/files/attachments/ticket/92c/92cfceb39d57d914ed8b14d0e37643de0797ae56/9206ac42b532ef8e983470c251f4e1a365fd636c.txt` whereas attachment `foo.txt` for ticket `42` in the global environment will be located at `/path/to/env/files/attachments/ticket/92c/92cfceb39d57d914ed8b14d0e37643de0797ae56/9206ac42b532ef8e983470c251f4e1a365fd636c.txt`.
 
 Product-aware components may do a different thing if they need to .
 
@@ -375,10 +386,10 @@
 
 `trac.conf.Configuration` instance in [#product-env-config config attribute] of product environments will read settings from the database and will be configured to inherit settings in environments' `trac.ini` file.
 
-Even if the proposal only suggests one database backend to store product-specific configuration it is also possible to think of using other configuration repositories (e.g. ''ini files'' , [http://hadoop.apache.org/hdfs/ HDFS], remote data repositories). It is a feasible enhancement though details have been omitted.
-}}}
-
-The following requirements are a corollary , considering that such customizations are performed in  the configuration file.
+Even if the proposal only suggests one database backend to store product-specific configuration it is also possible to think of using other configuration repositories (e.g. ''ini files'', [http://hadoop.apache.org/hdfs/ HDFS], remote data repositories). It is a feasible enhancement though details have been omitted.
+}}}
+
+The following requirements are a corollary, considering that such customizations are performed in  the configuration file.
 
 ==== Product logo #logo
 
@@ -455,109 +466,22 @@
 
 === Product resources namespaces #url-mapping
 
-Product and resource ID should form a two dimensional namespace. The mapping should be flexible enough to support the scenarios mentioned below. Other deployments may still be possible but are beyond the scope of this specification. However , in all cases every requests sent to any path under product base URL will be handled by the request handlers and filters activated in the target product environment.
+Product and resource ID should form a two dimensional namespace. The mapping should be flexible enough to support the scenarios mentioned below. Other deployments may still be possible but are beyond the scope of this specification. However, in all cases every requests sent to any path under product base URL will be handled by the request handlers and filters activated in the target product environment.
 
   - [=#deploy-domain] '''Product sub domain''' : The base URL of products
     will be at sibling sub-domains. A well-known
-    example is edgewall.org (i.e. bitten.edgewall.org ,
-    genshi.edgewall.org , trac.edgewall.org ). 
+    example is edgewall.org (i.e. bitten.edgewall.org,
+    genshi.edgewall.org, trac.edgewall.org ). 
     The global environment may be accessible at one 
     such sub-domain, at top level domain, or
     somewhere else.
-
-{{{
-#!div class="well"
-
-{{{
-#!span class="label label-info"
-
-  Implementation notes
-}}}
-
-'''TODO'''
-}}}
-
   - [=#deploy-sibling-paths] '''Product path namespace''' : Each product is 
     accessible at sibling paths on the same domain.
     The global environment will be available either at 
     one such path or somewhere else.
-
-{{{
-#!div class="well"
-
-{{{
-#!span class="label label-info"
-
-  Implementation notes
-}}} 
-
-This case is very similar to the [./MultienvParentDir reference multi-environment setup] .
-
-Considering the [#routes enhanced routing mechanism] the following routes definition will be suitable for single-environment installations
-
-{{{
-#!py
-
->>> from wsgiref.util import setup_testing_defaults as wsgi_environ
->>> from routes import Mapper
->>> m = Mapper()
->>> m.connect(None, '/path/to/bloodhound/{product}/{path_info:.*}')
->>> m.match('/path/to/bloodhound/product1/ticket/1')
-{'action': u'index', 'product': u'product1', 'controller': u'content', 'path_info': 'ticket/1'}
-
-}}}
-
-If the global environment will be treated as yet another sibling product environment
-
-{{{
-#!py
-
->>> from wsgiref.util import setup_testing_defaults as wsgi_environ
->>> from routes import Mapper
->>> m = Mapper()
->>> m.connect(None, '/path/to/bloodhound/global/{path_info:.*}', product='')
->>> m.connect(None, '/path/to/bloodhound/{product}/{path_info:.*}')
->>> m.match('/path/to/bloodhound/global/ticket/1')
-{'action': u'index', 'product': u'', 'controller': u'content', 'path_info': 'ticket/1'}
->>> m.match('/path/to/bloodhound/product1/ticket/1')
-{'action': u'index', 'product': u'product1', 'controller': u'content', 'path_info': 'ticket/1'}
-
-}}}
-
-For multi-environment installations
-
-{{{
-#!py
-
->>> from wsgiref.util import setup_testing_defaults as wsgi_environ
->>> from routes import Mapper
->>> m = Mapper()
->>> m.connect(None, '/path/to/bloodhound/{envname}/{product}/{path_info:.*}')
->>> m.match('/path/to/bloodhound/enterprise/product1/ticket/1')
-{'action': u'index', 'product': u'product1', 'envname': u'enterprise', 'controller': u'content', 'path_info': 'ticket/1'}
-
-}}}
-
-}}}
-
   - [=#deploy-global-env-embed] '''Embedded product path namespace''' : Each 
     product is accessible at sibling paths inside 
     the URL space of the global environment. 
-
-{{{
-#!div class="well"
-
-{{{
-#!span class="label label-info"
-
-  Implementation notes
-}}} 
-Even if this case is very similar to the [./MultienvParentDir reference multi-environment setup] a better match will be another setup based on [TracHacks:TracWsgiPlugin]. The main difference with respect to [#deploy-sibling-paths sibling paths] deployment is that the global environment plays an active role dispatching the requests addressed to an specific product by forwarding them to the corresponding product environment.
-
-This particular case does not even need to make use of the [#routes enhanced routing mechanism]. Instead of external routes definitions , a component (request handler) will be enabled in the global environment. It will handle requests sent to sub-paths of the form `product/<product prefix>/path/to/resource` relative to the global environment's base URL. Products base URL will be `product/<product prefix>` as a result. In its `process_request` method it will forward request dispatching to the instance of `trac.web.main.RequestDispatcher` of the corresponding product environment.
-
-}}}
-
   - [=#deploy-domain-path] '''Product sub domain + path namespace''' : 
     In this case product prefix will be 
     matched against URL sub domain whereas 
@@ -567,20 +491,6 @@
     web applications for projects . In general 
     product base URL will look like 
     `http://<product prefix>.domain.tld/path/to/bloodhound` .
-
-{{{
-#!div class="well"
-
-{{{
-#!span class="label label-info"
-
-  Implementation notes
-}}} 
-
-'''TODO'''
-
-}}}
-
   - [=#deploy-complex-path] '''Arbitrary product path namespace''' : 
     Sometimes hosting providers like forges do not 
     support product sub-domains . Hence 
@@ -590,63 +500,9 @@
     One such hypothetical example would be 
     `http://sourceforge.net/p/<product prefix>/bloodhound` .
 
-
-{{{
-#!div class="well"
-
-{{{
-#!span class="label label-info"
-
-  Implementation notes
-}}} 
-
-Considering the [#routes enhanced routing mechanism] the following routes definition will be suitable for single-environment installations
-
-{{{
-#!py
-
->>> from wsgiref.util import setup_testing_defaults as wsgi_environ
->>> from routes import Mapper
->>> m = Mapper()
->>> m.connect(None, '/path/to/bloodhound/{product}/path/to/bloodhound/{path_info:.*}')
->>> m.match('/path/to/bloodhound/product1/path/to/bloodhound/ticket/1')
-{'action': u'index', 'product': u'product1', 'controller': u'content', 'path_info': 'ticket/1'}
-
-}}}
-
-The example mentioned above for ''Allura'' 
-
-{{{
-#!py
-
->>> from wsgiref.util import setup_testing_defaults as wsgi_environ
->>> from routes import Mapper
->>> m = Mapper()
->>> m.connect(None, '/p/{product}/bloodhound/{path_info:.*}')
->>> m.match('/p/product1/bloodhound/ticket/1')
-{'action': u'index', 'product': u'product1', 'controller': u'content', 'path_info': 'ticket/1'}
-
-}}}
-
-For multi-environment installations
-
-{{{
-#!py
-
->>> from wsgiref.util import setup_testing_defaults as wsgi_environ
->>> from routes import Mapper
->>> m = Mapper()
->>> m.connect(None, '/{envname}/path/to/bloodhound/{product}/path/to/bloodhound/{path_info:.*}')
->>> m.match('/company/path/to/bloodhound/product1/path/to/bloodhound/ticket/1')
-{'action': u'index', 'product': u'product1', 'envname': u'company', 'controller': u'content', 'path_info': 'ticket/1'}
-
-}}}
-
-}}}
-
 '''FIXME''' also be addressable through the product URL namespace, namely /ticket/<product prefix>/<local ticket id>. 
 
-In a multi-product configuration product resources should not be accessed using current global URL scheme (i.e. /path/to/bloodhound/<environment>/<realm>/<id>). Since [#permissions products will have their own permissions schema] then requests handled by components in the context of the top-level environment will perform neither the right permissions checks nor even use appropriate settings , and so on ... The same will happen for resources moved between products . In general such requests should be redirected to a URL under the namespace of resource's product.
+In a multi-product configuration product resources should not be accessed using current global URL scheme (i.e. /path/to/bloodhound/<environment>/<realm>/<id>). Since [#permissions products will have their own permissions schema] then requests handled by components in the context of the top-level environment will perform neither the right permissions checks nor even use appropriate settings, and so on ... The same will happen for resources moved between products . In general such requests should be redirected to a URL under the namespace of resource's product.
 
 ==== Tickets #tickets-namespace
 
@@ -656,7 +512,7 @@
 
 === Ubiquitous access to resources #resource-refs
 
-Existing resource APIs have to be extended to work across product boundaries (or component manager, if the feature is analysed from a more abstract perspective) . While performing some computation (e.g. request handling, trac-admin command , ...) it will be possible to refer to resources managed by another product (i.e. in another scope) . Notable use cases are:
+Existing resource APIs have to be extended to work across product boundaries (or component manager, if the feature is analysed from a more abstract perspective) . While performing some computation (e.g. request handling, trac-admin command, ...) it will be possible to refer to resources managed by another product (i.e. in another scope) . Notable use cases are:
 
   - Rendering context
   - Permission checks and related assertions
@@ -738,7 +594,7 @@
 
   - It has an impact on code scattered all over Trac core and plugins
   - Even if all invocations performed by resource API clients will still work 
-    for local resources , they'll have to be modified to cope with external
+    for local resources, they'll have to be modified to cope with external
     references.
     * ... which represents a challenge when it comes to providing generic 
       helpers to render links in ''Genshi'' templates .
@@ -806,11 +662,15 @@
 
 }}}
 
+==== Product routes #reject-routes
+
+[=#routes] Former versions stated that [http://routes.groovie.org/ Routes] framework would be used to match URLs based on predefined patterns and use this information to dispatch requests addressed to product environments. This proposal was rejected to be distributed with mainstream Apache™ Bloodhound distribution considering the fact that it will introduce an explicit installation dependency with that framework. However related details are still documented in [./Routes routes appendix] for historical reasons and also because this approach will be provided by third-party libraries.
+
 == Backwards Compatibility #backwards-compatibility
 
 The solution has to be compatible with single product solution whenever possible in order to make possible smooth upgrade paths from previous installations. This is particularly important for plugins to work out-of-the-box under the new circumstances or at least to make easier the upgrade development process for hack authors.
 
-''Product environments'' in proposed multi-product configuration will act as the replacement for sibling environments under common parent directory in [./MultienvParentDir reference multi-environments setup]. They will ensure that the correct translations will be performed for requests addressed to resources owned by a product using the `trac.env.Environment` API as usual. Components will have access to it by reading `self.env` attribute (as usual !!!). All this means that from a component perspective the very same operations will be invoked , thus plugins adaptation to the new conditions will be rather smooth. If plugins do want to know whether they are acting on behalf of a product environment or the global environment then the following conditional statement would be enough
+''Product environments'' in proposed multi-product configuration will act as the replacement for sibling environments under common parent directory in [./MultienvParentDir reference multi-environments setup]. They will ensure that the correct translations will be performed for requests addressed to resources owned by a product using the `trac.env.Environment` API as usual. Components will have access to it by reading `self.env` attribute (as usual !!!). All this means that from a component perspective the very same operations will be invoked, thus plugins adaptation to the new conditions will be rather smooth. If plugins do want to know whether they are acting on behalf of a product environment or the global environment then the following conditional statement would be enough
 
 {{{
 #!py
@@ -850,9 +710,11 @@
 
 == References #references
 
-  1. Multi-project support (trac:ticket:130)
-  2. Multiple Projects within a Single Trac Environment
+  1. [=#ref1] Multi-project support [[BR]] (trac:ticket:130)
+  2. [=#ref2] Multiple Projects within a Single Trac Environment [[BR]] 
      (trac:wiki:TracMultipleProjects/SingleEnvironment)
+  3. [=#ref3] Setuptools dynamic discovery of services and plugins [[BR]] 
+     (http://peak.telecommunity.com/DevCenter/setuptools#dynamic-discovery-of-services-and-plugins)
 
 == Copyright #copyright
 
-------8<------8<------8<------8<------8<------8<------8<------8<--------

--
Page URL: <https://issues.apache.org/bloodhound/wiki/Proposals/BEP-0003>
Apache Bloodhound <https://issues.apache.org/bloodhound/>
The Apache Bloodhound issue tracker

This is an automated message. Someone added your email address to be
notified of changes on 'Proposals/BEP-0003' page.
If it was not you, please report to .