33 |
from ConfigParser import * |
from ConfigParser import * |
34 |
import sys, string, copy, netrc |
import sys, string, copy, netrc |
35 |
from gnue.common.apps import GDebug |
from gnue.common.apps import GDebug |
36 |
from gnue.common.datasources import GDataObjects |
from gnue.common.datasources import Exceptions |
37 |
from gnue.common.datasources import GLoginHandler |
from gnue.common.datasources import GLoginHandler |
38 |
from gnue.common.datasources.drivers import DRIVERS as ALLDRIVERS |
from gnue.common.datasources.drivers import DRIVERS as ALLDRIVERS |
39 |
from gnue.common.utils.FileUtils import openResource, dyn_import |
from gnue.common.utils.FileUtils import openResource, dyn_import |
56 |
# in an unreadable format. |
# in an unreadable format. |
57 |
pass |
pass |
58 |
|
|
59 |
LoginError = GDataObjects.LoginError |
LoginError = Exceptions.LoginError |
60 |
|
|
61 |
|
|
62 |
class GConnections: |
class GConnections: |
182 |
self._definitions[string.lower(name)] = copy.copy(parameters) |
self._definitions[string.lower(name)] = copy.copy(parameters) |
183 |
|
|
184 |
|
|
185 |
|
|
186 |
|
def getConnection(self, connection_name, login=0): |
187 |
|
|
188 |
|
|
189 |
|
connection_name = connection_name.lower() |
190 |
|
|
191 |
|
try: |
192 |
|
return self._openConnections[connection_name] |
193 |
|
except KeyError: |
194 |
|
pass |
195 |
|
|
196 |
|
# Support for multiple open connections |
197 |
|
# to same database. |
198 |
|
# Specify as 'gnue:1', 'gnue:2', etc, to open |
199 |
|
# two actual connections to 'gnue', each with |
200 |
|
# their own transactions, etc. |
201 |
|
connection_base = connection_name.split(':')[0] |
202 |
|
|
203 |
|
# This will throw a GConnections.NotFoundError if an unknown |
204 |
|
# connection name is specified. The calling method should |
205 |
|
# catch this exception and handle it properly (exit w/message) |
206 |
|
|
207 |
|
parameters = self.getConnectionParameters(connection_base) |
208 |
|
|
209 |
|
driver = parameters['provider'].lower().replace('/','.') |
210 |
|
behavior = parameters.get('behavior','').lower().replace('/','.') |
211 |
|
|
212 |
|
try: |
213 |
|
basedriver, extradriver =driver.split('.',1) |
214 |
|
extradriver = "." + extradriver |
215 |
|
except: |
216 |
|
basedriver = driver |
217 |
|
extradriver = "" |
218 |
|
|
219 |
|
path = [] |
220 |
|
|
221 |
|
dbdriver = None |
222 |
|
|
223 |
|
basemodule = _find_base_driver(basedriver, ALLDRIVERS) |
224 |
|
GDebug.printMesg(1,'Using %s as base driver for %s' % (basemodule, driver)) |
225 |
|
|
226 |
|
if basemodule: |
227 |
|
dbdriver = _get_dbdriver(basemodule + extradriver) |
228 |
|
|
229 |
|
if not dbdriver: |
230 |
|
tmsg = _("No database driver found for provider type '%s'") % driver |
231 |
|
raise Exceptions.ProviderNotSupportedError, tmsg |
232 |
|
|
233 |
|
|
234 |
|
conn = dbdriver.Connection(self, connection_name, parameters) |
235 |
|
self._openConnections[connection_name] = conn |
236 |
|
|
237 |
|
if login: |
238 |
|
self.loginToConnection(conn) |
239 |
|
|
240 |
|
# TODO: Process the behavior = and |
241 |
|
# TODO: set conn.behavior= to the |
242 |
|
# TODO: specific Introspection class |
243 |
|
return conn |
244 |
|
|
245 |
|
|
246 |
# |
# |
247 |
# Return a database provider object |
# Return a database provider object |
248 |
# |
# |
249 |
def getDataObject(self, connection_name, connection_type): |
def getDataObject(self, connection_name, connection_type): |
250 |
|
|
251 |
# This will throw a GConnections.NotFoundError if an unknown |
# This will throw a GConnections.NotFoundError if an unknown |
252 |
# connection name is specified. The calling method should |
# connection name is specified. The calling method should |
253 |
# catch this exception and handle it properly (exit w/message) |
# catch this exception and handle it properly (exit w/message) |
254 |
return _load_dbdriver( |
connection = self.getConnection(connection_name) |
255 |
self.getConnectionParameters(connection_name), |
|
256 |
connection_type, self) |
try: |
257 |
|
dd = connection.supportedDataObjects[connection_type](connection) |
258 |
|
GDebug.printMesg (1,'Attaching to %s (%s)' % (dd.__class__.__name__, connection_type)) |
259 |
|
return dd |
260 |
|
except KeyError: |
261 |
|
tmsg = _("DB Driver '%s' does not support source type '%s'") % (connection, connection_type) |
262 |
|
raise Exceptions.ObjectTypeNotAvailableError, tmsg |
263 |
|
|
264 |
|
|
265 |
|
|
266 |
# |
# |
267 |
# Has a connection been initialized/established? |
# Has a connection been initialized/established? |
268 |
# |
# |
269 |
|
# TODO: this was likely broken |
270 |
def isConnectionActive(self, connection): |
def isConnectionActive(self, connection): |
271 |
return self._openConnections.has_key(string.lower(connection)) |
return self._openConnections.has_key(string.lower(connection)) |
272 |
|
|
274 |
# |
# |
275 |
# Get a data connection for a specified database |
# Get a data connection for a specified database |
276 |
# |
# |
277 |
def requestConnection(self, dataObject, connection): |
def requestConnection(self, dataObject): |
278 |
connection_name = string.lower(connection) |
|
279 |
if self._openConnections.has_key(connection_name): |
print """TODO: once this branch makes it into CVS head, |
280 |
|
eliminate the GConnections.requestConnection logic!""" |
281 |
# If a database connetion has already been established, use it |
|
282 |
dataObject.setDataConnection(self._openConnections[connection_name]) |
# Support for multiple open connections |
283 |
GDebug.printMesg(5,'Reusing data connection to %s' % connection_name) |
# to same database. |
284 |
|
# Specify as 'gnue:1', 'gnue:2', etc, to open |
285 |
|
# two actual connections to 'gnue', each with |
286 |
|
# their own transactions, etc. |
287 |
|
|
288 |
|
self.loginToConnection(dataObject._connection) |
289 |
|
dataObject.connect() |
290 |
|
|
|
else: |
|
291 |
|
|
292 |
# Get the parameters from the Connections Definition File |
def loginToConnection(self, connection): |
|
loginData = self.getConnectionParameters(connection_name) |
|
293 |
|
|
294 |
|
connection_name = connection.name |
295 |
|
connection_base = connection_name.split(':')[0] |
296 |
|
|
297 |
|
try: |
298 |
|
connected = connection.__connected |
299 |
|
except AttributeError: |
300 |
|
connected = 0 |
301 |
|
|
302 |
|
if not connected: |
303 |
|
loginData = connection.parameters |
304 |
try: |
try: |
305 |
# load the user's netrc file: |
# load the user's netrc file: |
306 |
# a sample .netrc could look like: |
# a sample .netrc could look like: |
313 |
# set the HOME environement variable [SET HOME=...]) |
# set the HOME environement variable [SET HOME=...]) |
314 |
|
|
315 |
netrcData = netrc.netrc().authenticators( |
netrcData = netrc.netrc().authenticators( |
316 |
"'gnue://%s/'" % connection_name ) |
"'gnue://%s/'" % connection_base ) |
317 |
if netrcData!=None: |
if netrcData!=None: |
318 |
GDebug.printMesg(5, 'Read the user\'s .netrc file') |
GDebug.printMesg(5, 'Read the user\'s .netrc file') |
319 |
loginData['_username'] = netrcData[0][1:-1] |
loginData['_username'] = netrcData[0][1:-1] |
333 |
# Load |
# Load |
334 |
if loginData.has_key('custom_auth'): |
if loginData.has_key('custom_auth'): |
335 |
authenticator = dyn_import(loginData['custom_auth']).Authenticator() |
authenticator = dyn_import(loginData['custom_auth']).Authenticator() |
336 |
checkFields = authenticator.getLoginFields(dataObject.getLoginFields()) |
checkFields = authenticator.getLoginFields(connection.getLoginFields()) |
337 |
else: |
else: |
338 |
checkFields = dataObject.getLoginFields() |
checkFields = connection.getLoginFields() |
339 |
authenticator = None |
authenticator = None |
340 |
|
|
341 |
haveAllInformation = 1 |
haveAllInformation = 1 |
345 |
break |
break |
346 |
|
|
347 |
if haveAllInformation: |
if haveAllInformation: |
348 |
try: |
# try: |
349 |
self._authenticatedUsers[connection] = loginData['_username'] |
# self._authenticatedUsers[base] = loginData['_username'] |
350 |
except KeyError: |
# except KeyError: |
351 |
self._authenticatedUsers[connection] = None |
# self._authenticatedUsers[base] = None |
352 |
|
|
353 |
if authenticator: |
if authenticator: |
354 |
dataObject.connect(authenticator.login(loginData)) |
connection.connect(authenticator.login(loginData)) |
355 |
else: |
else: |
356 |
dataObject.connect(loginData) |
connection.connect(loginData) |
|
GDebug.printMesg(5, 'I had enough information to connect to %s without asking the user' % connection_name) |
|
|
# Save the newly opened connection for future datasources |
|
|
self._openConnections[connection_name] = dataObject.getDataConnection() |
|
357 |
|
|
358 |
else: |
else: |
359 |
attempts = 4 |
attempts = 4 |
367 |
|
|
368 |
# Ask the UI to prompt for our login data |
# Ask the UI to prompt for our login data |
369 |
loginData.update(self._loginHandler.getLogin( |
loginData.update(self._loginHandler.getLogin( |
370 |
[connection_name, |
[connection_base, |
371 |
self.getConnectionParameter(connection_name,'comment',''), |
self.getConnectionParameter(connection_base,'comment',''), |
372 |
checkFields], errortext)) |
checkFields], errortext)) |
373 |
|
|
374 |
# Add to authenticated user list |
# Add to authenticated user list |
379 |
|
|
380 |
# Ask the data object to connect to the database |
# Ask the data object to connect to the database |
381 |
if authenticator: |
if authenticator: |
382 |
dataObject.connect(authenticator.login(loginData)) |
connection.connect(authenticator.login(loginData)) |
383 |
else: |
else: |
384 |
dataObject.connect(loginData) |
connection.connect(loginData) |
|
|
|
|
# Save the newly opened connection for future datasources |
|
|
self._openConnections[connection_name] = \ |
|
|
dataObject.getDataConnection() |
|
385 |
|
|
386 |
# We're done! |
# We're done! |
387 |
attempts = 0 |
attempts = 0 |
388 |
self._loginHandler.destroyLoginDialog() |
self._loginHandler.destroyLoginDialog() |
389 |
|
|
390 |
except GDataObjects.LoginError, error: |
except Exceptions.LoginError, error: |
391 |
# Oops, they must have entered an invalid user/password. |
# Oops, they must have entered an invalid user/password. |
392 |
# Those silly users. |
# Those silly users. |
393 |
# user: Hey! Who are you calling silly?!!! |
# user: Hey! Who are you calling silly?!!! |
394 |
|
# Ok, then "those d@mn users" |
395 |
attempts = attempts - 1 |
attempts = attempts - 1 |
396 |
errortext = string.replace("%s" % error,'\n','') |
errortext = string.replace("%s" % error,'\n','') |
397 |
self._loginHandler.destroyLoginDialog() |
self._loginHandler.destroyLoginDialog() |
400 |
# Four times is plenty... |
# Four times is plenty... |
401 |
#self._loginHandler.destroyLoginDialog() |
#self._loginHandler.destroyLoginDialog() |
402 |
tmsg = _("Unable to log in after 4 attempts.\n\nError: %s") % error |
tmsg = _("Unable to log in after 4 attempts.\n\nError: %s") % error |
403 |
raise GDataObjects.LoginError, tmsg |
raise Exceptions.LoginError, tmsg |
404 |
|
|
405 |
except GLoginHandler.UserCanceledLogin: |
except GLoginHandler.UserCanceledLogin: |
406 |
# Guess they changed their minds. Treat as a login error. |
# Guess they changed their minds. Treat as a login error. |
407 |
self._loginHandler.destroyLoginDialog() |
self._loginHandler.destroyLoginDialog() |
408 |
tmsg = _("User canceled the login request.") |
tmsg = _("User canceled the login request.") |
409 |
raise GDataObjects.LoginError, tmsg |
raise Exceptions.LoginError, tmsg |
410 |
|
|
411 |
|
# Create the introspection instance |
412 |
|
try: |
413 |
|
behavior = connection.behavior |
414 |
|
except AttributeError: |
415 |
|
behavior = connection.defaultBehavior |
416 |
|
connection.introspector = behavior(connection) |
417 |
|
|
418 |
|
# Done |
419 |
|
connection.__connected = 1 |
420 |
|
|
421 |
|
|
422 |
def getAuthenticatedUser(self, connection=None): |
def getAuthenticatedUser(self, connection=None): |
423 |
try: |
try: |
433 |
# |
# |
434 |
# Load the correct DBdriver from gnue/common/datasources/drivers/*/ |
# Load the correct DBdriver from gnue/common/datasources/drivers/*/ |
435 |
# |
# |
|
def _load_dbdriver(parameters, type, connectionManager): |
|
|
|
|
|
|
|
|
driver = parameters['provider'].lower().replace('/','.') |
|
|
behavior = parameters.get('behavior','').lower().replace('/','.') |
|
|
|
|
|
d = driver.split('.') |
|
|
basedriver = d[0] |
|
|
if len(d) > 1: |
|
|
extradriver = "." + string.join(d[1:],'.') |
|
|
else: |
|
|
extradriver = "" |
|
|
|
|
|
path = [] |
|
|
|
|
|
dbdriver = None |
|
|
|
|
|
basemodule = _find_base_driver(basedriver, ALLDRIVERS) |
|
|
GDebug.printMesg(1,'Using %s as base driver for %s' % (basemodule, driver)) |
|
|
|
|
|
if basemodule: |
|
|
dbdriver = _get_dbdriver(basemodule + extradriver) |
|
|
|
|
|
if not dbdriver: |
|
|
tmsg = _("No database driver found for provider type '%s'") % driver |
|
|
raise GDataObjects.ProviderNotSupportedError, tmsg |
|
|
|
|
|
try: |
|
|
dd = dbdriver.supportedDataObjects[type]() |
|
|
GDebug.printMesg (1,'Attaching to %s (%s)' % (driver,dd.__class__.__name__)) |
|
|
return dd |
|
|
except KeyError: |
|
|
tmsg = _("DB Driver '%s' does not support source type '%s'") % (driver, type) |
|
|
raise GDataObjects.ObjectTypeNotAvailableError, tmsg |
|
|
|
|
436 |
|
|
437 |
def _find_base_driver (driver, modules, path=[]): |
def _find_base_driver (driver, modules, path=[]): |
438 |
if driver in modules: |
if driver in modules: |
439 |
return 'gnue.common.datasources.drivers.' + string.join(path + [driver],'.') |
return 'gnue.common.datasources.drivers.' + string.join(path + [driver],'.') |
440 |
else: |
else: |
441 |
for module in modules: |
for module in modules: |
442 |
|
print "trying module: %s" % module |
443 |
try: |
try: |
444 |
m = dyn_import ('gnue.common.datasources.drivers.' + string.join(path + [module],'.')).DRIVERS |
m = dyn_import ('gnue.common.datasources.drivers.' + string.join(path + [module],'.')).DRIVERS |
445 |
rs = _find_base_driver(driver, m, path + [module]) |
rs = _find_base_driver(driver, m, path + [module]) |
448 |
except (AttributeError, ImportError), err: |
except (AttributeError, ImportError), err: |
449 |
pass |
pass |
450 |
##print "Not in " + 'gnue.common.datasources.drivers.' + string.join(path + [module],'.') |
##print "Not in " + 'gnue.common.datasources.drivers.' + string.join(path + [module],'.') |
451 |
|
except AdapterNotInstalled: |
452 |
|
GDebug.printMesg(1,'%s does not have all dependencies installed' % driver) |
453 |
|
|
454 |
|
|
455 |
def _get_dbdriver (driver): |
def _get_dbdriver (driver): |
456 |
dbdriver = None |
dbdriver = None |
457 |
|
|
458 |
try: |
try: |
459 |
dbdriver = dyn_import("%s.Driver" % (driver)) |
dbdriver = dyn_import("%s" % (driver)) |
460 |
|
dbdriver.Connection |
461 |
except: |
except: |
462 |
GDebug.printMesg(1,'%s is not a dbdriver' % ( driver)) |
GDebug.printMesg(1,'%s is not a dbdriver' % ( driver)) |
463 |
try: |
try: |
468 |
return dbdriver |
return dbdriver |
469 |
except (ImportError, AttributeError): |
except (ImportError, AttributeError): |
470 |
GDebug.printMesg(1,'%s does not contain dbdrivers' % (driver)) |
GDebug.printMesg(1,'%s does not contain dbdrivers' % (driver)) |
471 |
|
except AdapterNotInstalled: |
472 |
|
GDebug.printMesg(1,'%s does not have all dependencies installed' % driver) |
473 |
|
|
474 |
return dbdriver |
return dbdriver |
475 |
|
|