#!/usr/bin/env python
#############################################################################
##
## This file is part of Taurus
##
## http://taurus-scada.org
##
## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
## Taurus is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## Taurus is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with Taurus. If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################
"""
simfactory.py:
"""
import os, imp, operator, types
from taurus import Factory, Database, Manager
from taurus.core.taurusexception import TaurusException
from taurus.core.taurusbasetypes import OperationMode, MatchLevel, \
TaurusAttrValue, TaurusEventType
from taurus.core.util.singleton import Singleton
from taurus.core.util.log import Logger
from taurus.core.taurusfactory import TaurusFactory
from taurus.core.taurusattribute import TaurusAttribute
from taurus.core.taurusdevice import TaurusDevice
from taurus.core.taurusdatabase import TaurusDatabase
from taurus.core.taurusconfiguration import TaurusConfiguration
[docs]class ModuleDict(dict):
def __init__(self, mod):
self.__mod = mod
def __getitem__(self, name):
return self.__mod.__getattribute__(name)
[docs]class ResourcesFactory(Singleton, TaurusFactory, Logger):
"""A Singleton class designed to provide Simulation related objects."""
#: the list of schemes that this factory supports. For this factory: 'res'
#: and 'resources' are the supported schemes
schemes = ("res", "resource",)
#: the default resource file name
DftResourceName = 'taurus_resources.py'
#: priority for the default resource
DftResourcePriority = 10
def __init__(self):
""" Initialization. Nothing to be done here for now."""
pass
[docs] def init(self, *args, **kwargs):
"""Singleton instance initialization.
**For internal usage only**"""
name = self.__class__.__name__
self.call__init__(Logger, name)
self.call__init__(TaurusFactory)
self._resource_map = {}
self._resource_priority = {}
self._resource_priority_keys = []
self._resource_count = 0
[docs] def reloadResource(self, obj=None, priority=1, name=None):
"""(Re)Loads the given resource.
:param obj: (dict or file or None) the resource object. Default is
None meaning in will (re)load the default resource:
taurus_resources.py from the application directory
:param priority: (int) the resource priority. Default is 1 meaning
maximum priority
:param name: (str) an optional name to give to the resource
:return: (dict) a dictionary version of the given resource object
"""
if operator.isMappingType(obj):
name = name or 'DICT%02d' % priority
elif type(obj) in types.StringTypes or obj is None:
name, obj = self.__reloadResource(obj)
obj = ModuleDict(obj)
else:
raise TypeError
if self._resource_map.get(name) is None:
self._resource_count += 1
self._resource_map[name] = obj
if self._resource_count == 1:
self._first_resource = obj
pl = self._resource_priority.get(priority)
if pl is None:
self._resource_priority[priority] = pl = []
pl.append(name)
self._resource_priority_keys = self._resource_priority.keys()
self._resource_priority_keys.sort()
return obj
loadResource = reloadResource
loadResource.__doc__ = reloadResource.__doc__
def __reloadResource(self, name=None):
path = os.path.curdir
if name is None:
file_name = ResourcesFactory.DftResourceName
else:
path, file_name = os.path.split(name)
if not path: path = os.path.curdir
path = os.path.abspath(path)
full_name = os.path.join(path, file_name)
if not os.path.isfile(full_name):
raise ImportError
module_name, ext = os.path.splitext(file_name)
m, file = None, None
try:
file, pathname, desc = imp.find_module(module_name, [path])
self.info("(re)loading resource %s", pathname)
m = imp.load_module(module_name, file, pathname, desc)
if file: file.close()
except Exception, e:
if file: file.close()
raise e
if m is None:
self.warning("failed to (re)load resource %s" % module_name)
raise ImportError
return full_name, m
def __get(self, alias):
if self._resource_count == 0:
self.reloadResource(priority = ResourcesFactory.DftResourcePriority)
# optimization: many applications contain only one resource: in that
# case avoid the loop
if self._resource_count == 1:
return self._first_resource[alias]
for p in self._resource_priority_keys:
for resource_name in self._resource_priority[p]:
resource = self._resource_map[resource_name]
try: return resource[alias]
except: pass
def __splitResourceName(self, alias):
for i, c in enumerate(alias):
if not c.isalnum():
return i, c, alias.split(c, 1)
return None, '', [alias]
def __splitScheme(self, alias):
try:
i = alias.index('://')
return alias[:i], alias[i+3:]
except:
return '', alias
[docs] def getValue(self, key):
"""Returns the value for a given key
:param key: (str) a key
:return: (str) the value for the given key
"""
alias = self.__splitScheme(key)
if alias[0] and not alias[0] in ResourcesFactory.schemes:
return None
i, c, alias = self.__splitResourceName(alias[1])
alias[0] = self.__get(alias[0]) or ''
return c.join(alias)
[docs] def findObjectClass(self, absolute_name):
"""
Obtain the class object corresponding to the given name.
:param absolute_name: (str) the object absolute name string
:return: (taurus.core.taurusmodel.TaurusModel) a class object that should be a subclass of a taurus.core.taurusmodel.TaurusModel
:raise: (taurus.core.taurusexception.TaurusException) if the given name is invalid.
"""
objType = None
return objType
[docs] def getDatabase(self, alias=None):
"""
Obtain the object corresponding to the given database name or the
default database if db_name is None.
If the corresponding database object already exists, the existing
instance is returned. Otherwise a new instance is stored and returned.
:param alias: (str) database name string alias. If None, the
default database is used
:return: (taurus.core.taurusdatabase.TaurusDatabase) database object
:raise: (NameError) if the alias does not exist
:raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid.
"""
if alias is None:
return Database()
alias = self.getValue(alias)
if not alias:
raise NameError(alias)
return Manager().getDatabase(alias)
[docs] def getDevice(self, alias):
"""
Obtain the object corresponding to the given device name. If the
corresponding device already exists, the existing instance is returned.
Otherwise a new instance is stored and returned.
:param alias: device name string alias.
:return: (taurus.core.taurusdevice.TaurusDevice) device object
:raise: (NameError) if the alias does not exist
:raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid.
"""
alias = self.getValue(alias)
if not alias:
raise NameError(alias)
return Manager().getDevice(alias)
[docs] def getAttribute(self, alias):
"""
Obtain the object corresponding to the given attribute name.
If the corresponding attribute already exists, the existing instance
is returned. Otherwise a new instance is stored and returned.
:param alias: (str) attribute name string alias
:return: (taurus.core.taurusattribute.TaurusAttribute) attribute object
:raise: (NameError) if the alias does not exist
:raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid.
"""
alias = self.getValue(alias)
if not alias:
raise NameError(alias)
return Manager().getAttribute(alias)
[docs] def getConfiguration(self, alias):
"""
Obtain the object corresponding to the given attribute or full name.
If the corresponding configuration already exists, the existing instance
is returned. Otherwise a new instance is stored and returned.
:param alias: (str) configuration name string alias
:return: (taurus.core.taurusconfiguration.TaurusConfiguration) configuration object
:raise: (NameError) if the alias does not exist
:raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid.
"""
alias = self.getValue(alias)
if not alias:
raise NameError(alias)
return Manager().getConfiguration(alias)