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.