Mercurial > hg > ltpda-connection-manager
comparison README @ 0:d5fef23867bb
First workig implementation.
author | Daniele Nicolodi <daniele@science.unitn.it> |
---|---|
date | Sun, 23 May 2010 10:51:35 +0200 |
parents | |
children | c4b57991935a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d5fef23867bb |
---|---|
1 * Requirements | |
2 | |
3 1. Provide an interface for the user to insert connection | |
4 credentials: server hostname, database name, user name and | |
5 password. | |
6 | |
7 2. Avoid that the user has to enter those information too often, | |
8 like when retrieving many objects from the repository. This is | |
9 done caching the credentials for a configurable amount of time | |
10 | |
11 3. Provide understandable error messages. | |
12 | |
13 4. Track open connections, and avoid excessive proliferation of open | |
14 connections to the database, due to miss behaving user functions. | |
15 | |
16 This is all about managing connections, so I would propose to call | |
17 this component LTPDAConnectionManager. | |
18 | |
19 | |
20 * Interface definition | |
21 | |
22 ** LTPDAConnectionManager() | |
23 | |
24 Isntantiates a singleton class managing credentials and connections. | |
25 | |
26 Credentials are cached. Credentials, except password are cached | |
27 forever, passwords are cached for a configurable amount of time. | |
28 | |
29 Connections are tracked putting each handed out connection into a | |
30 list. When a new connection is requested, or when requested via a | |
31 dedicated method, the connection list is walked and closed | |
32 connections are removed from it. When the connection number exceeds | |
33 a configurable maximum, no more connection are instantiated. | |
34 | |
35 The singleton clas is implemented as an handle matlab class that | |
36 stores an handle to itself in appdata storage. When the class is | |
37 instantiates it returns an handle to the copy referenced in | |
38 appdata. | |
39 | |
40 *** appdataKey | |
41 | |
42 Static mehod that returns the key used to store the handle to | |
43 instance data in appdata. | |
44 | |
45 *** credentialsExpiry | |
46 | |
47 Property. Taken from user preferences. Time after which the | |
48 credentials are not valid anymore. | |
49 | |
50 *** maxConnectionsNumber | |
51 | |
52 Property. Taken from user preferences. The maximum number of | |
53 connections that can be open at the same time toward the same | |
54 host. | |
55 | |
56 *** cachePassword | |
57 | |
58 Property. Taken from user preferences. Defines if password should | |
59 be cached along with other database access credentials. It may | |
60 take the values: | |
61 | |
62 0. passwords are not cached, | |
63 1. passwords are always cached, | |
64 2. ask if the users desires to cache the given password. | |
65 | |
66 *** connect(hostname, database, username, password) | |
67 | |
68 Try to connect to the database with the given credentials. If the | |
69 connection attempt fails with an 'access denied' error, prompt the | |
70 user for username using the given username as default, and | |
71 password. Present the option to cache password. Cache username and | |
72 password accordingly to user choice. Do not cache passwords by | |
73 default. | |
74 | |
75 Return an object implementing the java.sql.Connection interface, | |
76 representing a connection to the given database, with the given | |
77 credentials. | |
78 | |
79 Connection errors, other than access denied are reported as | |
80 fatal exceptions. User hitting the cancel button on input forms is | |
81 reported as an 'user canceled' exception. | |
82 | |
83 *** connect(hostname, database, username) | |
84 | |
85 Search the credentials cache for user password. If it is not | |
86 found, or the connection attempt fails with an access denied | |
87 error, prompt the user for username, using the given username as | |
88 default, and password. Present the option to cache password. Try | |
89 to connect to the database with the given credentials. When the | |
90 connections succeeds, cache username and password accordingly to | |
91 user choice. | |
92 | |
93 Return an object implementing the java.sql.Connection interface, | |
94 representing a connection to the given database, with the given | |
95 credentials. | |
96 | |
97 Errors, other than acces denied, are reported as fatal | |
98 exceptions. User hitting the cancel button on input forms is | |
99 reported as an 'user canceled' exception. Access denied errors are | |
100 catched and credentials are asked again. | |
101 | |
102 *** connect(hostname, database) | |
103 | |
104 Search the credentials cache looking for usernames and passwords | |
105 for accessing the given database. If credentials are not found, | |
106 there is more than one set of credentials matching, or the | |
107 connection attempt fails with an 'acces denied' error, prompt the | |
108 user for username and password. Present the option to cache | |
109 password. When the connections succeeds, cache username and | |
110 password accordingly to user choice. | |
111 | |
112 Return an object implementing the java.sql.Connection interface, | |
113 representing a connection to the given database, with the given | |
114 credentials. | |
115 | |
116 Errors, other than acces denied, are reported as fatal | |
117 exceptions. User hitting the cancel button on input forms is | |
118 reported as an 'user canceled' exception. Access denied errors are | |
119 catched and credentials are asked again. | |
120 | |
121 *** connect() | |
122 | |
123 Make the user choose between a list of hostname-database-username | |
124 tuples obtained from the credentials cache, and the possibility of | |
125 entering a hostname and a database. Then proceed as in the case of | |
126 the call to connect(hostname, database). | |
127 | |
128 The list of hostname-database pairs can be initialized with data | |
129 from the LTPDA toolbox preferences or witj the add() method. | |
130 | |
131 *** connect(plist) | |
132 | |
133 Same as the previous calls but taking parameters from PLIST. | |
134 | |
135 If PLIST has a 'connection' parameter, and if this is a valid java | |
136 object, implementing the java.sql.Connection, return it instead of | |
137 creating a new connection. If the object does not fulfill the | |
138 requirements throw a meaningful error. | |
139 | |
140 *** count() | |
141 | |
142 Return the number of open connections in the connection pool. It | |
143 has the side effect of removing from the pool any close connection. | |
144 | |
145 *** close(ids) | |
146 | |
147 Close connections with the given IDs in the connections pool. If no | |
148 ID is given close all connection. | |
149 | |
150 *** clear() | |
151 | |
152 Clear credentials cache. | |
153 | |
154 *** add(credentials) | |
155 | |
156 Add the given credentials to the cache. | |
157 | |
158 | |
159 ** Utilities | |
160 | |
161 *** utils.jmysql | |
162 | |
163 Collection of utility functions for interfacing to a database from | |
164 a pure matlab environment. Except connect() all the functions take | |
165 a java object implementing java.sql.Connection as first parameter. | |
166 | |
167 *** utils.jmysql.connect(hostname, database, username, password) | |
168 | |
169 Return an object implementing the java.sql.Connection interface, | |
170 representing a connection to the given database, with the given | |
171 credentials. | |
172 | |
173 Throw an error if the connection fails. | |
174 | |
175 This function can be used when the programmer wants full controll | |
176 on the connection, stepping aside of the connection manager. | |
177 | |
178 Should not be used in toolbox functions or by the toolbox users. | |
179 | |
180 *** utils.jmysql.execute(conn, query, varargin) | |
181 | |
182 Execute the query QUERY, with the parameters specified in VARARGIN | |
183 through the connection CONN. Returns the results in a 2d cell | |
184 array. See the actual implementation. | |
185 | |
186 QUERY is a string, CONN is a java object implementing | |
187 java.sql.Connection, VARARGIN can contain any base matlab type. we | |
188 can think about introducing the marshalling for time() objects | |
189 into SQL strings. | |
190 | |
191 See current implementation in CVS. | |
192 | |
193 *** plist.REPOSITORY_CREDENTIALS_PLIST | |
194 | |
195 Static method that returns a default plist that specifies the | |
196 credentials required to connect to a repository. Should be | |
197 combined in the default plist of the ltpda methods that require | |
198 a connection to the database. Those parameters are: | |
199 | |
200 hostname - Server hostname | |
201 database - Database name | |
202 username - User login name | |
203 password - Password | |
204 | |
205 In addition to those any ltpda method requiring a database | |
206 connection should accept a 'connection' parameter in his plist. An | |
207 open connection can be provided though this parameter. The caller | |
208 is responsible of closing the connection once it is done with it. | |
209 | |
210 | |
211 * Examples | |
212 | |
213 function out = useless(a, b, plist) | |
214 | |
215 % obtain a database connection | |
216 cm = LTPDAConnectionManager(); | |
217 conn = cm.connect(pl) | |
218 | |
219 % ask the database to sum A and B | |
220 out = utils.jmysql.execute(conn, 'SELECT ?+?', a, b); | |
221 | |
222 % out is a cell array containing A + B | |
223 disp out{1}; | |
224 | |
225 % check who is in charge of the connection | |
226 if conn ~= find(pl, 'connection') | |
227 % close connection | |
228 conn.close() | |
229 end | |
230 | |
231 end | |
232 | |
233 This function can be used as follows: | |
234 | |
235 - useless(1, 2) | |
236 | |
237 Will ask the user for hostname, database, username, password. | |
238 | |
239 - useless(1, 2, plist('hostname', 'localhost', 'database', 'test')) | |
240 | |
241 Will ask the user for username and password. | |
242 | |
243 - useless(1, 2, plist('hostname', 'localhost', 'database', 'test', 'username', 'daniele')) | |
244 | |
245 Will ask the user for password. | |
246 | |
247 - useless(1, 2, plist('hostname', 'localhost', 'database', 'test', 'username', 'daniele', 'password', 'passwd')) | |
248 | |
249 Will not ask the user. | |
250 | |
251 - conn = utils.jmysql.conn('localhost', 'test', 'daniele', 'passwd') | |
252 useless(1, 2, plist('connection', conn)); | |
253 useless(3, 4, plist('connection', conn)); | |
254 conn.close(); | |
255 | |
256 Anything is asked to the user. The connection is provided by the | |
257 user and should not be closed inside the function. This is | |
258 usefull for continuously running automated processes. | |
259 | |
260 | |
261 This code is a stupid example of connections not being closed properly: | |
262 | |
263 pl = plist('hostname', 'localhost', 'database', 'test', 'username', 'daniele', 'password', 'passwd'); | |
264 cm = LTPDAConnectionManager(); | |
265 cm.maxConnectionsNumber = 20; | |
266 for kk = 1:100 | |
267 conn{kk} = cm.connect(pl); | |
268 end | |
269 | |
270 It should fail at iteration 21 with an error similat to | |
271 | |
272 ### too many connections open to 'localhost' | |
273 | |
274 | |
275 * Use cases | |
276 | |
277 ** Interactive usage | |
278 | |
279 A connection can be obtained from the connection manager in the | |
280 following ways, requiring user interaction: | |
281 | |
282 1. Open a connection without providing any credential. | |
283 | |
284 A. If there are cached credentials show a list of (hostname, | |
285 database, username) touple, give the possibiity to chose between | |
286 any of those and creating a new one. | |
287 | |
288 B. If there are no cached credentials for the (hostname, | |
289 database, username) touple, or the user choses 'new' in the | |
290 previeus step, a dialog box asks the user for hostname and | |
291 database. The hostname field is an editable drop down lists | |
292 populated with data from the user preferences and cached | |
293 credentials. ADVANCED: the database filed is an editable drop | |
294 down list, when the user presses the drop down button, a list of | |
295 databases is fetch from the server. | |
296 | |
297 C. If there are cached credentials for the (hostname, database, | |
298 username) touple go to E. | |
299 | |
300 D. A dialog box asks the user for username and password and | |
301 gives the option to remember credentials. Username field is an | |
302 editable drop down populated with usernames from the credentials | |
303 cache, the username last entered username this (hostname, | |
304 database) pair is the default. The provided username is cached | |
305 into the credential cache. | |
306 | |
307 E. Connection to the database it attempt. If the connection | |
308 fails go back to C. If the connection succeds and the user | |
309 selected the 'store credentials' options save the password in | |
310 the credentials cache. | |
311 | |
312 F. Return the connection to the caller. | |
313 | |
314 2. Open a connection providing hostname and database. | |
315 | |
316 A. If there are cached credentials go to 1.E. | |
317 | |
318 B. If there are no cached credentials go to 1.D. | |
319 | |
320 3. Open a connection providing hostname, database, username. | |
321 | |
322 A. If there are cached credentials for the (hostname, database, | |
323 username) touple go to 1.E. | |
324 | |
325 A. If there are no cached credentials for the (hostname, database, | |
326 username) touple go to 1.D. | |
327 | |
328 4. Open a connection providing hostname, database, username, password. | |
329 | |
330 A. Go to 1.E. | |
331 | |
332 ** Non interactive usage | |
333 | |
334 A connection can be obtained without requiring user interaction in | |
335 the following ways: | |
336 | |
337 1. Known good credendials can be provided to the connection manager | |
338 connect() method. If called with four arguments it will not | |
339 require user interaction if it connects successfully to the | |
340 database. | |
341 | |
342 2. Known good credentials can be added to the cache with the connection | |
343 manager add() method. Any call to the connection manager | |
344 connect() method specifying at least hostname and database | |
345 matching the ones inserted in the cache, will then use the | |
346 cached credentials. User interaction is required if the | |
347 connection fails. | |
348 | |
349 3. A connection can be obtained with the utils.jmysql.connect() | |
350 function and given to the ltpda methods requiring a database | |
351 connection with the 'connection' plist parameter. In this way | |
352 the caller has full control on the connection. | |
353 | |
354 ** Functions chaining | |
355 | |
356 In the case where a procedure needs to call several ltpda methods | |
357 requiring database access, it is recommended that the connection is | |
358 created in the outermost function, and passed to called functions | |
359 using the 'connection' plist parameter. | |
360 | |
361 This avoids to query the user for connection credentials more than | |
362 once during the executing of the same procedure, even when password | |
363 caching is disabled. It also avoids the performance penalty of | |
364 connecting multiple times to the server. | |
365 | |
366 ** Multiple users scenario | |
367 | |
368 Consider the case where two users are sharing the same matlab | |
369 instance. The two users must be able to interleave the creation of | |
370 database connections, each one with his own credentials. This can | |
371 be accomplished in different ways: | |
372 | |
373 1. If the interleaving of the operations of two users is frequent, | |
374 the connection manager can be configured, via the user | |
375 preferences, to never cache passwords. The users will be always | |
376 queried for their credentials. | |
377 | |
378 If procedures are well written, each one should not require to | |
379 enter user credentials more than once. | |
380 | |
381 2. If the interleaving of the two users is not so frequent, the | |
382 connection manager can be configured, via the user preferences, | |
383 to cache passwords for a short time. | |
384 | |
385 3. The connection manager can be tricked into creating multiple | |
386 user profiles for the same database connection. For example: | |
387 | |
388 cm = LTPDAConnectionManager(); | |
389 cm.add(credentials('host', 'db', 'user1'); | |
390 cm.add(credentials('host', 'db', 'user2'); | |
391 | |
392 Password caching can be enabled. The connection manager will | |
393 make the user decide which credentials to use. However the use | |
394 of the user own credentials is not enforced. |