paulb@654 | 1 | <?xml version="1.0" encoding="iso-8859-1"?> |
paulb@354 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
paulb@354 | 3 | <html xmlns="http://www.w3.org/1999/xhtml"> |
paulb@354 | 4 | <head> |
paulb@354 | 5 | <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type" /> |
paulb@354 | 6 | <title>Integrating with Other Systems</title> |
paulb@354 | 7 | <link href="styles.css" rel="stylesheet" type="text/css" /> |
paulb@354 | 8 | </head> |
paulb@354 | 9 | <body> |
paulb@354 | 10 | <h1>Integrating with Other Systems</h1> |
paulb@749 | 11 | |
paulb@749 | 12 | <p>Most Web applications are not self-contained - instead of providing |
paulb@749 | 13 | information which is written into the application code itself, they may often |
paulb@749 | 14 | access data from other places or even communicate with other systems. Since |
paulb@749 | 15 | applications may be very different in the way that they access external systems |
paulb@749 | 16 | or the way in which they obtain external information, WebStack does not mandate |
paulb@749 | 17 | a single mechanism for hooking into such systems or loading such information. |
paulb@749 | 18 | Instead, it is recommended that applications import packages and modules which |
paulb@749 | 19 | provide the functionality necessary to carry out such integration, using the |
paulb@749 | 20 | appropriate conveniences (such as <a href="selectors.html">selector |
paulb@749 | 21 | resources</a>) to manage that functionality where appropriate.</p> |
paulb@749 | 22 | |
paulb@354 | 23 | <h2>Examples of Packages</h2> |
paulb@749 | 24 | |
paulb@749 | 25 | <p>Examples of packages and modules that might be used for integration purposes |
paulb@749 | 26 | include the following:</p> |
paulb@749 | 27 | |
paulb@354 | 28 | <ul> |
paulb@354 | 29 | <li>Database access packages, including object-relational mappers.</li> |
paulb@749 | 30 | <li>Communications libraries - for connecting to Web services or other remote |
paulb@749 | 31 | services, for example.</li> |
paulb@749 | 32 | <li>Templating or reporting systems. (Note that templating systems are also |
paulb@749 | 33 | very useful when generating <a href="responses.html">responses</a>.)</li> |
paulb@354 | 34 | </ul> |
paulb@749 | 35 | |
paulb@749 | 36 | <h2>Using External Packages in General</h2> |
paulb@749 | 37 | |
paulb@749 | 38 | <p>In the simplest of cases, the use of external packages is as straightforward |
paulb@749 | 39 | as importing a Python module (or package) and then using that module's |
paulb@749 | 40 | contents. This can often be done in the <a href="resources.html">resource</a> |
paulb@749 | 41 | code; for example:</p> |
paulb@749 | 42 | |
paulb@749 | 43 | <pre> |
paulb@749 | 44 | import urllib |
paulb@749 | 45 | |
paulb@749 | 46 | class MyResource: |
paulb@749 | 47 | def respond(self, trans): |
paulb@749 | 48 | [Examine the transaction, decide what the user wants to do.] |
paulb@749 | 49 | |
paulb@749 | 50 | f = urllib.urlopen("http://www.boddie.org.uk/rss/feed.xml") |
paulb@749 | 51 | |
paulb@749 | 52 | [Produce some kind of response which tells the user what happened.] |
paulb@749 | 53 | </pre> |
paulb@749 | 54 | |
paulb@354 | 55 | <p>In the above example, here is what happens:</p> |
paulb@749 | 56 | |
paulb@354 | 57 | <table style="text-align: left; width: 80%;" align="center" border="1" |
paulb@354 | 58 | cellpadding="5" cellspacing="0"> |
paulb@354 | 59 | <tbody> |
paulb@354 | 60 | <tr> |
paulb@354 | 61 | <th>What we do</th> |
paulb@354 | 62 | <th>Where it happens and how often</th> |
paulb@354 | 63 | </tr> |
paulb@354 | 64 | <tr> |
paulb@749 | 65 | <td>Import <code>urllib</code> to gain access to functionality which we |
paulb@749 | 66 | can then use to access a remote service.</td> |
paulb@749 | 67 | <td>This happens once - when the above code is itself imported into |
paulb@749 | 68 | Python.</td> |
paulb@354 | 69 | </tr> |
paulb@354 | 70 | <tr> |
paulb@749 | 71 | <td>Use the <code>urlopen</code> function of <code>urllib</code> to |
paulb@749 | 72 | actually access a remote service.</td> |
paulb@749 | 73 | <td>This happens in the resource code each time the resource decides to |
paulb@749 | 74 | access the service.</td> |
paulb@354 | 75 | </tr> |
paulb@354 | 76 | </tbody> |
paulb@354 | 77 | </table> |
paulb@749 | 78 | |
paulb@749 | 79 | <h2>Using Database Connections</h2> |
paulb@749 | 80 | |
paulb@749 | 81 | <p>In the above case, the functionality is relatively easy to acquire and does not |
paulb@749 | 82 | require any initialisation. But what if we were connecting to a database? There |
paulb@749 | 83 | might be a need to specially initialise the database module - only once, though |
paulb@749 | 84 | - and then repeatedly use it. Moreover, we may want to ensure that any |
paulb@749 | 85 | transactions created as our resources run are terminated when the resources |
paulb@749 | 86 | have themselves completed their work. At this point, it is worth considering |
paulb@749 | 87 | the <code>StoreSelector</code> class, as described in the <a |
paulb@749 | 88 | href="selectors.html">"Selectors - Components for Dispatching to |
paulb@749 | 89 | Resources"</a> document. Consider this example:</p> |
paulb@749 | 90 | |
paulb@749 | 91 | <pre> |
paulb@749 | 92 | from WebStack.Resources.Selectors import StoreSelector |
paulb@749 | 93 | |
paulb@749 | 94 | class MyResource: |
paulb@749 | 95 | def respond(self, trans): |
paulb@749 | 96 | [Examine the transaction, decide what the user wants to do.] |
paulb@749 | 97 | |
paulb@749 | 98 | connection = trans.get_attributes()["store"] |
paulb@749 | 99 | cursor = connection.cursor() |
paulb@749 | 100 | try: |
paulb@749 | 101 | cursor.execute("select url from feeds where owner=?", ["boddie.org.uk"]) |
paulb@749 | 102 | results = cursor.fetchall() |
paulb@749 | 103 | finally: |
paulb@749 | 104 | cursor.close() |
paulb@749 | 105 | |
paulb@749 | 106 | [Produce some kind of response which tells the user what happened.] |
paulb@749 | 107 | |
paulb@749 | 108 | def get_site_map(connection): |
paulb@749 | 109 | return StoreSelector(MyResource(), connection) |
paulb@354 | 110 | </pre> |
paulb@749 | 111 | |
paulb@749 | 112 | <p>The initialisation would be done elsewhere, perhaps in the same module:</p> |
paulb@749 | 113 | |
paulb@749 | 114 | <pre> |
paulb@749 | 115 | import mydb |
paulb@749 | 116 | |
paulb@749 | 117 | connection = mydb.connect("me", "myPassword") |
paulb@749 | 118 | try: |
paulb@749 | 119 | site = get_site_map(connection) |
paulb@749 | 120 | deploy(site) |
paulb@749 | 121 | finally: |
paulb@749 | 122 | connection.close() |
paulb@749 | 123 | </pre> |
paulb@749 | 124 | |
paulb@354 | 125 | <p>In the above example, here is what happens:</p> |
paulb@749 | 126 | |
paulb@354 | 127 | <table style="text-align: left; width: 80%;" align="center" border="1" |
paulb@354 | 128 | cellpadding="5" cellspacing="0"> |
paulb@354 | 129 | <tbody> |
paulb@354 | 130 | <tr> |
paulb@354 | 131 | <th>What we do</th> |
paulb@354 | 132 | <th>Where it happens and how often</th> |
paulb@354 | 133 | </tr> |
paulb@354 | 134 | <tr> |
paulb@749 | 135 | <td>Import the <code>mydb</code> module to gain access to database access functionality.</td> |
paulb@749 | 136 | <td>This happens once - when the above code is itself imported into Python.</td> |
paulb@749 | 137 | </tr> |
paulb@749 | 138 | <tr> |
paulb@749 | 139 | <td>Initialise a database connection using the <code>connect</code> function from the <code>mydb</code> module.</td> |
paulb@749 | 140 | <td>This also happens only once - when the above code is itself imported into Python.</td> |
paulb@749 | 141 | </tr> |
paulb@749 | 142 | <tr> |
paulb@749 | 143 | <td>Wrap the application in a <code>StoreSelector</code> which manages |
paulb@749 | 144 | the database connection.</td> |
paulb@749 | 145 | <td>This happens in the <code>get_site_map</code> function which |
paulb@749 | 146 | prepares the application before deployment.</td> |
paulb@354 | 147 | </tr> |
paulb@354 | 148 | <tr> |
paulb@749 | 149 | <td>Make the connection available in a transaction object.</td> |
paulb@749 | 150 | <td>This happens <strong>automatically</strong> for every incoming transaction or request to access the |
paulb@749 | 151 | application - it is managed by the <code>StoreSelector</code> object.</td> |
paulb@354 | 152 | </tr> |
paulb@354 | 153 | <tr> |
paulb@749 | 154 | <td>Obtain the connection from the attributes on the transaction object; |
paulb@749 | 155 | use the <code>cursor</code> method on the connection object to access |
paulb@749 | 156 | the database; use the methods on the cursor object.</td> |
paulb@749 | 157 | <td>This happens in the resource code each time the resource decides to |
paulb@749 | 158 | access the database.</td> |
paulb@749 | 159 | </tr> |
paulb@749 | 160 | <tr> |
paulb@749 | 161 | <td>Terminate the active transaction on the connection object.</td> |
paulb@749 | 162 | <td>This happens <strong>automatically</strong> for every completed transaction or request to access the |
paulb@749 | 163 | application - it is managed by the <code>StoreSelector</code> object.</td> |
paulb@749 | 164 | </tr> |
paulb@749 | 165 | <tr> |
paulb@749 | 166 | <td>Close the database connection using the <code>close</code> method on |
paulb@749 | 167 | the connection object.</td> |
paulb@749 | 168 | <td>This also happens only once - when the application is |
paulb@749 | 169 | terminating.</td> |
paulb@354 | 170 | </tr> |
paulb@354 | 171 | </tbody> |
paulb@354 | 172 | </table> |
paulb@749 | 173 | |
paulb@749 | 174 | <p>The choice of initialising the connection may seem arbitrary - why not just |
paulb@749 | 175 | obtain a connection in the resource? Usually, such decisions are made on the |
paulb@749 | 176 | basis of efficiency and on constraints outside the control of the application - |
paulb@749 | 177 | some database systems limit the number of connections, for example, and if a |
paulb@749 | 178 | large number of resources suddenly became active, some of them would fail to |
paulb@749 | 179 | obtain connections if the connection initialisation code were in the |
paulb@749 | 180 | <code>respond</code> method of the resource. Moreover, by using the |
paulb@749 | 181 | <code>StoreSelector</code>, a certain amount of "boilerplate" code can be |
paulb@749 | 182 | hidden away and not written within each resource.</p> |
paulb@749 | 183 | |
paulb@354 | 184 | </body> |
paulb@354 | 185 | </html> |