Most Web applications are not self-contained - instead of providing information which is written into the application code itself, they may often access data from other places or even communicate with other systems. Since applications may be very different in the way that they access external systems or the way in which they obtain external information, WebStack does not mandate a single mechanism for hooking into such systems or loading such information. Instead, it is recommended that applications import packages and modules which provide the functionality necessary to carry out such integration, using the appropriate conveniences (such as selector resources) to manage that functionality where appropriate.
Examples of packages and modules that might be used for integration purposes include the following:
In the simplest of cases, the use of external packages is as straightforward as importing a Python module (or package) and then using that module's contents. This can often be done in the resource code; for example:
import urllib class MyResource: def respond(self, trans): [Examine the transaction, decide what the user wants to do.] f = urllib.urlopen("http://www.boddie.org.uk/rss/feed.xml") [Produce some kind of response which tells the user what happened.]
In the above example, here is what happens:
What we do | Where it happens and how often |
---|---|
Import urllib to gain access to functionality which we
can then use to access a remote service. |
This happens once - when the above code is itself imported into Python. |
Use the urlopen function of urllib to
actually access a remote service. |
This happens in the resource code each time the resource decides to access the service. |
In the above case, the functionality is relatively easy to acquire and does not
require any initialisation. But what if we were connecting to a database? There
might be a need to specially initialise the database module - only once, though
- and then repeatedly use it. Moreover, we may want to ensure that any
transactions created as our resources run are terminated when the resources
have themselves completed their work. At this point, it is worth considering
the StoreSelector
class, as described in the "Selectors - Components for Dispatching to
Resources" document. Consider this example:
from WebStack.Resources.Selectors import StoreSelector class MyResource: def respond(self, trans): [Examine the transaction, decide what the user wants to do.] connection = trans.get_attributes()["store"] cursor = connection.cursor() try: cursor.execute("select url from feeds where owner=?", ["boddie.org.uk"]) results = cursor.fetchall() finally: cursor.close() [Produce some kind of response which tells the user what happened.] def get_site_map(connection): return StoreSelector(MyResource(), connection)
The initialisation would be done elsewhere, perhaps in the same module:
import mydb connection = mydb.connect("me", "myPassword") try: site = get_site_map(connection) deploy(site) finally: connection.close()
In the above example, here is what happens:
What we do | Where it happens and how often |
---|---|
Import the mydb module to gain access to database access functionality. |
This happens once - when the above code is itself imported into Python. |
Initialise a database connection using the connect function from the mydb module. |
This also happens only once - when the above code is itself imported into Python. |
Wrap the application in a StoreSelector which manages
the database connection. |
This happens in the get_site_map function which
prepares the application before deployment. |
Make the connection available in a transaction object. | This happens automatically for every incoming transaction or request to access the
application - it is managed by the StoreSelector object. |
Obtain the connection from the attributes on the transaction object;
use the cursor method on the connection object to access
the database; use the methods on the cursor object. |
This happens in the resource code each time the resource decides to access the database. |
Terminate the active transaction on the connection object. | This happens automatically for every completed transaction or request to access the
application - it is managed by the StoreSelector object. |
Close the database connection using the close method on
the connection object. |
This also happens only once - when the application is terminating. |
The choice of initialising the connection may seem arbitrary - why not just
obtain a connection in the resource? Usually, such decisions are made on the
basis of efficiency and on constraints outside the control of the application -
some database systems limit the number of connections, for example, and if a
large number of resources suddenly became active, some of them would fail to
obtain connections if the connection initialisation code were in the
respond
method of the resource. Moreover, by using the
StoreSelector
, a certain amount of "boilerplate" code can be
hidden away and not written within each resource.