prop_err.py :  » Development » SnapLogic » snaplogic » common » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » SnapLogic 
SnapLogic » snaplogic » common » prop_err.py
# $SnapHashLicense:
# 
# SnapLogic - Open source data services
# 
# Copyright (C) 2009, SnapLogic, Inc.  All rights reserved.
# 
# See http://www.snaplogic.org for more information about
# the SnapLogic project. 
# 
# This program is free software, distributed under the terms of
# the GNU General Public License Version 2. See the LEGAL file
# at the top of the source tree.
# 
# "SnapLogic" is a trademark of SnapLogic, Inc.
# 
# 
# $
# $Id: prop_err.py 10183 2009-12-16 23:58:55Z grisha $

import re

from snaplogic.common.snap_exceptions import *
from snaplogic.snapi_base.resdef import ResDef,list_of_field_types
from snaplogic.snapi_base import keys
from snaplogic.cc import prop
from snaplogic.common import component_prop_defs

FIELD_AND_VIEW_NAME_PATTERN = re.compile(r'[^a-zA-Z0-9_]+')

class SimplePropErr(object):
    """
    This class is used in reporting error about simple property type.
    It provides a method for setting an error message and retrieving the error message.
    
    """
    
    def __init__(self, property_label = None):
        """
        Initializes a simple type error object.
        
        """
        self._err_msg = None
        self._property_label = property_label
    
    def __str__(self):
        return "%s" % self._err_msg
    
    def set_message(self, err_msg = None):
        """
        Sets an error message.
        
        @param err_msg: Error message
        @type err_msg:  str
        
        """
        
        self._err_msg = err_msg
        
    def get_error(self):
        """
        Returns error message currently set. Can be None or a string
        
        @return: Error message
        @rtype:  str
        
        """
        return self._err_msg
    
    def _to_resdef(self):
        
        if self._err_msg is not None:
            return {keys.LABEL: self._property_label, keys.ERROR_MESSAGE: self._err_msg}
        else:
            return None

class ListPropErr(list):
    """
    A list property error object is used for reporting errors on a list property.
    This class provides a container for holding error object for each entry in the list property.
    
    """
    
    def __init__(self, read_only, property_label = None):
        """
        Initializes a list type error object.
        
        """
        list.__init__(self)
        
        self._read_only = read_only
        self._err_msg = None
        self._property_label = property_label
    
    def __str__(self):
        s = []
        s.append("List_err(%s) [ " % self._err_msg)
        for v in self:
            s.append("%s, " % v)
        s.append("]")
        return "".join(s)
    
    def set_message(self, err_msg = None):
        """
        Sets an error message.
        
        @param err_msg: Error message
        @type err_msg:  str
        
        """
        
        self._err_msg = err_msg
        
    def get_error(self):
        """
        Returns error message currently set. Can be None or a string
        
        @return: Error message
        @rtype:  str
        
        """
        return self._err_msg
    
    
    def __setitem__(self, index, value):
        """
        Intercept the l[index]=value operations.
        
        @param index: The index value
        @type index:  int or long
        
        @param value: The SimplePropErr or ListPropErr or DictPropErr definition
        @type value:  L{SimplePropErr} or L{ListPropErr} or L{DictPropErr} or None
        
        """
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        if (value != None and (not isinstance(value, SimplePropErr)) and (not isinstance(value, DictPropErr))
                                                   and (not isinstance(value, ListPropErr))):
            raise SnapObjTypeError("The value needs to be a SimplePropErr/ListPropErr/DictPropErr object")
        
        list.__setitem__(self, index, value)
    
    def __setslice__(self, i, j, sequence):
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        c = 1
        for s in sequence:
            if ((not isinstance(s, SimplePropErr)) and (not isinstance(s, DictPropErr))
                                                   and (not isinstance(s, ListPropErr))):
                raise SnapObjTypeError(
                       "The value #%s in the sequence is not a SimplePropErr/ListPropErr/DictPropErr object" % c)
            c += 1
        
        list.__setslice__(self, i, j, sequence)

    def __getslice__(self, i, j):
        """
        Returns ListPropErr with the specified slice range.
        
        @param i: Beginning of the index range
        @type i:  int or long
        
        @param j: End of the index range
        @type j:  int or long
        
        @return: Returns ListPropErr defintion for the specified slice.
        @rtype:  L{ListPropErr}
        
        """
        
        # The slice has to be same type as the sequence from which it is derived
        slice_val = ListPropErr()
        slice_val.extend(list.__getslice__(self, i, j))
        
        return slice_val
    
    def append(self, value):
        """
        Append error object to list error object.
        
        @param value: New entry for the list
        @param value: Either L{SimplePropErr} or L{ListPropErr} or L{DictPropErr} or None
        
        """
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        if (value != None and (not isinstance(value, SimplePropErr)) and (not isinstance(value, DictPropErr))
                                                   and (not isinstance(value, ListPropErr))):
            raise SnapObjTypeError("The value needs to be a SimplePropErr/ListPropErr/DictPropErr object")
        list.append(self,value)
    
    def extend(self, new_vals):
        """
        Append list of new error objects to list property.
        
        @param new_vals: List of new error objects.
        @type new_vals:  List of L{SimplePropErr}, L{ListPropErr} and L{DictPropErr} or None
        
        """
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        i = 1
        for s in new_vals:
            if (s != None and (not isinstance(s, SimplePropErr)) and (not isinstance(s, DictPropErr))
                                                   and (not isinstance(s, ListPropErr))):
                raise SnapObjTypeError(
                           "The value #%s in the iterable is not a SimplePropErr/ListPropErr/DictPropErr object" % i)
            i += 1
        list.extend(self, new_vals)
    
    def insert(self, i, value):
        """
        Insert new error object at the specified index.
        
        @param i: Index number
        @type i:  int or long
        
        @param value: Definition to be inserted.
        @type value:  L{SimplePropErr}, L{ListPropErr}, L{DictPropErr} or None
        
        """
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
          
        if (value != None and (not isinstance(value, SimplePropErr)) and (not isinstance(value, DictPropErr))
                                                   and (not isinstance(value, ListPropErr))):
            raise SnapObjTypeError("The entry needs to be a SimplePropErr/ListPropErr/DictPropErr object")
        list.insert(self, i, value)
        
    def __delitem__(self, key):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        list.__delitem__(self, key)
        
    def __delslice__(self, i, j):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        list.__delslice__(self, i, j)
    
    def pop(self):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        return list.pop(self)
    
    def remove(self, i):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        list.remove(self, i)
    
    def reverse(self):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        list.reverse(self)
        
    def sort(self, cmpfunc=None):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The list membership cannot be modified")
        
        list.sort(self, cmpfunc)
        
    def _to_resdef(self):
        l = []
        err_flag = False
        for i in self:
            ret = i._to_resdef()
            l.append(ret)
            if ret is not None:
                err_flag = True
        
        if err_flag or self._err_msg is not None:
            return {keys.LABEL: self._property_label, keys.ERROR_MESSAGE : self._err_msg, keys.LIST_ERROR: l}
        else:
            return None
        
    
class DictPropErr(dict):
    """
    A dict property error object is used for reporting errors on a dict property.
    This class provides a container for holding error object for each entry in the dict property.
    
    """
    def __init__ (self, read_only, property_label = None):
        """
        Initializes a dict type property defintion.
        
        """
        dict.__init__(self)
        self._read_only = read_only
        self._err_msg = None
        self._property_label = property_label
    
    def __str__(self):
        s = []
        s.append("Dict_err(%s) { " % self._err_msg)
        for k in self:
            s.append("\"%s\" : %s, " % (k, self[k]))
        s.append("}")
        return "".join(s)
    
    def set_message(self, err_msg = None):
        """
        Sets an error message.
        
        @param err_msg: Error message
        @type err_msg:  str
        
        """
        
        self._err_msg = err_msg
        
    def get_error(self):
        """
        Returns error message currently set. Can be None or a string
        
        @return: Error message
        @rtype:  str
        
        """
        return self._err_msg
    
    def __setitem__(self, key, value):
        """
        Intercept the l[key]=value operations.
        
        @param key: Key for the entry
        @type key:  str
        
        @param value: Value for the entry
        @type value:  Varies, can  be SimpleProp or a more complex property like DictProp or ListProp.
        
        """
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified")
        
        if ((not isinstance(value, SimplePropErr)) and (not isinstance(value, DictPropErr))
                                                   and (not isinstance(value, ListPropErr))):
            raise SnapObjTypeError("The value needs to be a SimplePropErr/ListPropErr/DictPropErr object")
        dict.__setitem__(self, key, value)
    
    def update(self, update_dict):
        """
        Update method of a dictionary container.
        
        @param update_dict: The dictionary being used for update
        @type update_dict:  L{DictPropErr}
        
        """
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified")
        
        i = 0
        for key, value in update_dict.items():
            if key not in self:
                i += 1
            if ((not isinstance(value, SimplePropErr)) and (not isinstance(value, DictPropErr))
                                                       and (not isinstance(value, ListPropErr))):
                raise SnapObjTypeError("The value needs to be a SimplePropErr/ListPropErr/DictPropErr object")
        dict.update(self, update_dict)
    
    def setdefault(self, key, value):
        """
        The setdefault functionality of a dictionary.
        Unlike normal dictionary setdefault() method, value param cannot be None. It has to be
        object of type SimplePropErr, DictPropErr or ListPropErr.
        
        @param key: Key for the setdefault call
        @type key:  str
        
        @param value: The default value. If not specified or set to None, then the default_entry_type is
            used.
        @type value:  None or L{SimplePropErr}, L{DictPropErr} or L{ListPropErr}
        
        @return: The value at the key of default entry.
        @rtype:  L{SimplePropErr} or L{DictPropErr} or L{ListPropErr}
        
        """
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified")
        
        if value is None:
            raise SnapValueError("Default value cannot be None")
        elif ((not isinstance(value, SimplePropErr)) and (not isinstance(value, DictPropErr))
                                                   and (not isinstance(value, ListPropErr))):
            raise SnapObjTypeError("The value needs to be a SimplePropErr/ListPropErr/DictPropErr object")

        return dict.setdefault(self, key, value)
    
    def __delitem__(self, key):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified")
        
        dict.__delitem__(self, key)
    
    def clear(self):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified")
        
        dict.clear(self)
        
    def pop(self, k, x=None):
         
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified") 
        
        return dict.pop(self, k, x)
    
    def popitem(self):
        
        if self._read_only[0]:
            raise SnapObjPermissionError("The dictionary membership cannot be modified")
        
        return dict.popitem(self)
    
    def _to_resdef(self):
        d = {}
        for i in self:
            if self[i]._to_resdef() is not None:
                d[i] = self[i]._to_resdef()
        
        if len(d) or self._err_msg is not None:     
            return {keys.LABEL: self._property_label, keys.ERROR_MESSAGE : self._err_msg, keys.DICT_ERROR: d}
        else:
            None


def create_err_obj(inp_prop, read_only, prop_def = None, partial_data = False, dynamic_constraints = None):
    """
    Create error object corresponding to the structure of the property.
    
    @param inp_prop: Property for which the error object must be created.
    @type inp_prop:  simple value/list/dict.
    
    @param read_only: A list that should have a single entry, with the value False. This list entry can
        later be set to True, to prevent users from modifying the structure of the error objects.
    @type read_only:  list
    
    @param prop_def: If we want to validate the property value against a property definition, as we create 
         the error object, then the property definition should be provided in this param
    @type prop_def:  SimpleProp/ListProp/DictProp
    
    @param partial_data: If set to True, then don't return error if all the required values have not
            been provided.
    @type partial_data:  bool
    
    @param dynamic_constraints: Dictionary mapping dynamic constraint name to constraint value.
         For example, dynamic constraint "input field" may look like:
         {keys.CONSTRAINT_LOV_INPUT_FIELD : ['city', 'state', 'zip'] }
         Meaning that there are three input fields: city, state, and zip.
    @type all_dynamic_constraints: dict
    
    @return: Error object which corresponds in structure to the input property.
    @rtype:  L{SimplePropErr}, L{ListPropErr} or L{DictPropErr}
    
    """
    
    prop_stack = []
    prop_stack.append((None, None, inp_prop, prop_def))
    root_err_obj = None
    while len(prop_stack) > 0:
        (parent_err_obj, my_key, prop_val, prop_def) = prop_stack.pop()
        if prop_def is not None:
            property_label = prop_def.label_str
        else:
            property_label = None
            
        if isinstance(prop_val, dict):
            err_obj = DictPropErr(read_only, property_label)
            # If a prop_def is not available, then it is assumed that there is no predefined
            # structure for that branch of the property definition (and hence not much validation that
            # can be done.)
            if prop_def is not None:
                ret = prop_def.validate(prop_val, my_key, partial_data)
                if ret is not None:
                    err_obj.set_message(ret)
            
            # We won't dive into a dict, if it has already been found to be structurally unsound.
            err = err_obj._to_resdef()
            if err is None:
                for k in prop_val:
                    # Again, we do not expect propdef to be present. If it is
                    # available, we will walk the definition.
                    if prop_def is not None:
                        elem_def = prop_def.get_item_type(k)
                    else:
                        elem_def = None
                    prop_stack.append((err_obj, k,  prop_val[k], elem_def))
            
            
        elif isinstance(prop_val, list) or isinstance(prop_val, tuple):
            err_obj = ListPropErr(read_only, property_label)
            if prop_def is not None:
                ret = prop_def.validate(prop_val, my_key, partial_data)
                if ret is not None:
                    err_obj.set_message(ret)
                 
            # We won't dive into a list, if it has already been found to be structurally unsound.
            err = err_obj._to_resdef()
            if err is None:   
                for i in range(len(prop_val)):
                    # Prefill the list with empty slots.
                    err_obj.append(None)
                    # Again, we do not expect propdef to be present. If it is
                    # available, we will walk the definition.
                    if prop_def is not None:
                        elem_def = prop_def.get_item_type(i)
                    else:
                        elem_def = None
                    prop_stack.append((err_obj, i, prop_val[i], elem_def))
                    
        else:
            err_obj = SimplePropErr(property_label)
            if prop_def is not None:
                ret = prop_def.validate(prop_val, my_key, partial_data, dynamic_constraints)
                if ret is not None:
                    err_obj.set_message(ret)
            
        if parent_err_obj is not None:
            # This setitem should work for both dict and list, since list has been pre-filled with empty slots.    
            parent_err_obj[my_key] = err_obj
        else:
            root_err_obj = err_obj
                
    return root_err_obj

class ComponentResourceErr(object):
    """
    This class provides an interface for setting validation errors on a component's resdef.
    
    """
    
    def __init__(self, resdef_dict, partial_data = False):
        """
        Initialize error object for resource defintion. 
        
        """
        self._err_msg = None
        self._read_only = [False]
        
        # Populate the dictionary mapping dynamic constraint names to actual constraint values.
        # LOVs can be a static list of values or can be a more dynamic list, consist of list of view names or 
        # list of field names. Here we prepare those dynamic lists to support proper validation of property values
        # against such dynamic LOVs.
        #
        # For example, dynamic constraint "input field" may look like:
        # {keys.CONSTRAINT_LOV_INPUT_FIELD : ['city', 'state', 'zip'] }
        # Meaning that there are three input fields: city, state, and zip.
        dynamic_constraints = {}
        
        # Expand the dynamic constraints 
        for (view_type, view_constraint, field_constraint) in \
                [[keys.INPUT_VIEWS, keys.CONSTRAINT_LOV_INPUT_VIEW, keys.CONSTRAINT_LOV_INPUT_FIELD],
                 [keys.OUTPUT_VIEWS, keys.CONSTRAINT_LOV_OUTPUT_VIEW, keys.CONSTRAINT_LOV_OUTPUT_FIELD]]:
            # Collect view names in an array and sort them alphabetically, so it's easier to write QA tests  
            view_names = resdef_dict[view_type].keys()
            view_names.sort()
            
            # Store the list of views constraint 
            dynamic_constraints[view_constraint] = view_names
            
            # Do we have multiple views?  If so view name prefix is required.
            multiple_views = len(view_names) > 1 
            field_names = []
            
            # Collect all views' fields
            for view_name in view_names:
                
                # If there are no fields (e.g. binary view) move on
                if keys.VIEW_FIELDS not in resdef_dict[view_type][view_name]:
                    continue
                
                # If there are multiple input views, or multiple output views, the field name
                # must be prefixed with the view name.
                if multiple_views:
                    prefix = view_name + "." 
                else:
                    prefix = ""
                     
                for field in resdef_dict[view_type][view_name][keys.VIEW_FIELDS]:
                    field_name = field[keys.FIELD_NAME]
                    if field_name is not None:
                        field_names.append(prefix + field[keys.FIELD_NAME])
                    else:
                        # Special treatment for None (can't append anything to it)
                        field_names.append(field[keys.FIELD_NAME])
                    
            # Store the list of fields constraint 
            dynamic_constraints[field_constraint] = field_names
            
        d = prop.DictProp("Property")
        self._prop_err  = DictPropErr(self._read_only, "Properties")
        for prop_name in resdef_dict[keys.PROPERTY_DEFS]:
            d[prop_name] = prop.create_property_from_resdef(
                                            resdef_dict[keys.PROPERTY_DEFS][prop_name][keys.PROPERTY_DEFINITION])
            if prop_name not in resdef_dict[keys.PROPERTY_VALS]:
                resdef_dict[keys.PROPERTY_VALS][prop_name] = None
            self._prop_err[prop_name] = create_err_obj(resdef_dict[keys.PROPERTY_VALS][prop_name],
                                                           self._read_only, d[prop_name], partial_data, 
                                                           dynamic_constraints)
            
        prop.validate_param_notations(resdef_dict[keys.PARAMS].keys(), resdef_dict[keys.PROPERTY_VALS],
                                      resdef_dict[keys.PROPERTY_DEFS], self._prop_err)
        
        # We won't be setting partial_data flag for these objects, since they must have a valid structure
        # at all times.   
        self._input_view_err   = create_err_obj(resdef_dict[keys.INPUT_VIEWS], self._read_only,
                                                component_prop_defs.INPUT_VIEWS_PROP)
        self._output_view_err  = create_err_obj(resdef_dict[keys.OUTPUT_VIEWS], self._read_only,
                                                component_prop_defs.OUTPUT_VIEWS_PROP)
        self._param_err        = create_err_obj(resdef_dict[keys.PARAMS], self._read_only,
                                                component_prop_defs.PARAMS_PROP)
        self._pass_through_err = create_err_obj(resdef_dict[keys.OUTPUT_VIEW_PASSTHROUGH], self._read_only,
                                                component_prop_defs.PASSTHROUGH_PROP)
        categories = resdef_dict.get(keys.RESOURCE_CATEGORY)
        if categories is not None:
            self._category_err = create_err_obj(categories, self._read_only, component_prop_defs.CATEGORIES_PROP)
        else:
            self._category_err = None
            
        res_ref = resdef_dict.get(keys.RESOURCE_REF)
        if res_ref is not None:
            self._resource_ref_err = create_err_obj(res_ref, self._read_only, component_prop_defs.RESOURCE_REF_PROP)
        else:
            self._resource_ref_err = None
            
        # Capabilities check needs to be mindful of partial data
        self._validate_resdef_capabilities(resdef_dict, partial_data)
        self._validate_views(resdef_dict)
        self._read_only[0] = True

        
    def _validate_resdef_capabilities(self, res_dict, partial_data = False):
        """
        Validates that the resdef does not violate any constraints specified in capabilities dict.
        
        @param res_dict: Resdef as a dictionary.
        @type res_dict:  dict
        
        @param partial_data: If set to True, then don't return error if all the required values have not
            been provided.
        @type partial_data:  bool
        
        """
         
        cap = res_dict[keys.CAPABILITIES]
        
        for k in [keys.CAPABILITY_INPUT_VIEW_LOWER_LIMIT, keys.CAPABILITY_INPUT_VIEW_UPPER_LIMIT,
                  keys.CAPABILITY_OUTPUT_VIEW_LOWER_LIMIT, keys.CAPABILITY_OUTPUT_VIEW_UPPER_LIMIT,
                  keys.CAPABILITY_INPUT_VIEW_ALLOW_BINARY, keys.CAPABILITY_OUTPUT_VIEW_ALLOW_BINARY,
                  keys.CAPABILITY_ALLOW_PASS_THROUGH]:
            if k not in cap:
                self.set_message("Capability '%s' not specified in the resource definition" % k)
                return
        
        l = len(res_dict[keys.INPUT_VIEWS])  
        if (not partial_data) and l < cap[keys.CAPABILITY_INPUT_VIEW_LOWER_LIMIT]:
            self._input_view_err.set_message(
                         "Number of input views '%s' is less than the component lower limit for input views '%s'" %
                         (l, cap[keys.CAPABILITY_INPUT_VIEW_LOWER_LIMIT]))
        elif l > cap[keys.CAPABILITY_INPUT_VIEW_UPPER_LIMIT]:
            self._input_view_err.set_message(
                         "Number of input views '%s' is greater than the component upper limit for input views '%s'"
                         % (l, cap[keys.CAPABILITY_INPUT_VIEW_UPPER_LIMIT]))
        
        if not cap[keys.CAPABILITY_INPUT_VIEW_ALLOW_BINARY]:
            # Make sure that none of the input views violate this binary restriction
            for inp_name in res_dict[keys.INPUT_VIEWS]:
                if not res_dict[keys.INPUT_VIEWS][inp_name][keys.VIEW_IS_RECORD]:
                    self._input_view_err[inp_name].set_message(
                       "Component does not support binary input views, but input view '%s' is in binary mode" %
                       inp_name)
        
        l = len(res_dict[keys.OUTPUT_VIEWS])   
        if (not partial_data) and l < cap[keys.CAPABILITY_OUTPUT_VIEW_LOWER_LIMIT]:
            self._output_view_err.set_message(
                          "Number of output views '%s' is less than the component lower limit for output views '%s'"
                          % (l, cap[keys.CAPABILITY_OUTPUT_VIEW_LOWER_LIMIT]))
        elif l > cap[keys.CAPABILITY_OUTPUT_VIEW_UPPER_LIMIT]:
            self._output_view_err.set_message(
                      "Number of output views '%s' is greater than the component upper limit for output views '%s'"
                      % (l, cap[keys.CAPABILITY_OUTPUT_VIEW_UPPER_LIMIT]))   
            
        if not cap[keys.CAPABILITY_OUTPUT_VIEW_ALLOW_BINARY]:
            # Make sure that none of the output views violate this binary restriction
            for out_name in res_dict[keys.OUTPUT_VIEWS]:
                if not res_dict[keys.OUTPUT_VIEWS][out_name][keys.VIEW_IS_RECORD]:
                    self._output_view_err[out_name].set_message(
                       "Component does not support binary output views, but output view '%s' is in binary mode" %
                       out_name)
                
        if (not cap[keys.CAPABILITY_ALLOW_PASS_THROUGH]):
            if keys.OUTPUT_VIEW_PASSTHROUGH in res_dict and len(res_dict[keys.OUTPUT_VIEW_PASSTHROUGH]) > 0:
                self._pass_through_err.set_message(
                       "Component does not support pass-through, but output view(s) '%s' have been set as pass-through"
                        % ", ".join(res_dict[keys.OUTPUT_VIEW_PASSTHROUGH].keys()))
                    
        
    def _validate_views(self, res_dict):
        """
        Validate that the views meet certain requirements like no duplicate field names.
        
        @param res_dict: Resdef as a dictionary.
        @type res_dict:  dict
        
        """
        
        for inp_name in res_dict[keys.INPUT_VIEWS]:
            m = FIELD_AND_VIEW_NAME_PATTERN.search(inp_name)
            if m is not None:
                self._input_view_err[inp_name].set_message("Input view name '%s' has invalid character(s) '%s'" % 
                                                           (inp_name, m.group(0)))
                
            view = res_dict[keys.INPUT_VIEWS][inp_name]
            if view[keys.VIEW_IS_RECORD]:
                fields = view[keys.VIEW_FIELDS]
                l = []
                for (i, f) in enumerate(fields):
                    if f[1] not in list_of_field_types:
                        self._input_view_err[inp_name][keys.VIEW_FIELDS][i][1].set_message(
                                                                "Field type '%s' is invalid" % f[1])
                        
                    if f[0] is None or len(f[0]) == 0:
                        self._input_view_err[inp_name][keys.VIEW_FIELDS][i][0].set_message(
                                                                "Field name '%s' is invalid" % f[0])
                    else:   
                        m = FIELD_AND_VIEW_NAME_PATTERN.search(f[0])
                        if m is not None:
                            self._input_view_err[inp_name][keys.VIEW_FIELDS][i][0].set_message(
                                                "Field name '%s' has invalid character(s) '%s'" % (f[0], m.group(0)))
                        elif f[0] in l:
                                self._input_view_err[inp_name][keys.VIEW_FIELDS][i].set_message(
                                                                "Field '%s' specified more than once" % f[0])
                    l.append(f[0])
                    
        for out_name in res_dict[keys.OUTPUT_VIEWS]:
            m = FIELD_AND_VIEW_NAME_PATTERN.search(out_name)
            if m is not None:
                self._output_view_err[out_name].set_message("Output view name '%s' has invalid character(s) '%s'" % 
                                                            (out_name, m.group(0)))
                
            view = res_dict[keys.OUTPUT_VIEWS][out_name]
            if view[keys.VIEW_IS_RECORD]:
                fields = view[keys.VIEW_FIELDS]
                l = []
                for (i, f) in enumerate(fields):
                    if f[1] not in list_of_field_types:
                        self._output_view_err[out_name][keys.VIEW_FIELDS][i][1].set_message(
                                                                "Field type '%s' is invalid" % f[1])
                    if f[0] is None or len(f[0]) == 0:
                        self._output_view_err[out_name][keys.VIEW_FIELDS][i][0].set_message(
                                                                "Field name '%s' is invalid" % f[0])
                    else:
                        m = FIELD_AND_VIEW_NAME_PATTERN.search(f[0])
                        if m is not None:
                            self._output_view_err[out_name][keys.VIEW_FIELDS][i][0].set_message(
                                                "Field name '%s' has invalid character(s) '%s'" % (f[0], m.group(0)))
                        elif f[0] in l:
                            self._output_view_err[out_name][keys.VIEW_FIELDS][i].set_message(
                                                                "Field '%s' specified more than once" % f[0])
                    l.append(f[0])
        
        # Validate pass-through settings in the resdef dictionary.            
        output_view_names = res_dict[keys.OUTPUT_VIEWS].keys()
        input_view_names = res_dict[keys.INPUT_VIEWS]
        for out_name in res_dict[keys.OUTPUT_VIEW_PASSTHROUGH]:
            input_views = res_dict[keys.OUTPUT_VIEW_PASSTHROUGH][out_name][keys.INPUT_VIEWS]
            pass_err = self._pass_through_err[out_name]
            if out_name not in output_view_names:
                pass_err.set_message(
                   "Nonexistent output view '%s' specified in pass-through section of resource definition" % out_name)
                continue                          
            
            view = res_dict[keys.OUTPUT_VIEWS][out_name]
            if not view[keys.VIEW_IS_RECORD]:
                pass_err.set_message("Output view '%s' specified in pass-through is not a record mode view" % out_name)
        
            if len(input_views) == 0:
                pass_err.set_message("Input view names list in pass-through entry for output view '%s' is empty" %
                                     out_name)
                continue
            
            for (i, inp_name) in enumerate(input_views):
                if inp_name not in input_view_names:
                    pass_err[keys.PT_INPUT_VIEWS][i].set_message(
                                    "Nonexistent input view '%s' specified in pass-through entry for output view '%s'"
                                    % (inp_name, out_name))
                    continue
                        
                      
                        
    def __str__(self):
        l = []
        s = str(self._prop_err)
        if s:
            l.append('Property Error(s):\n%s\n' % s)
        
        s = str(self._input_view_err)
        if s:
            l.append('Input View Error(s):\n%s\n' % s)
            
        s = str(self._output_view_err)
        if s:
            l.append('Output View Error(s):\n%s\n' % s)
            
        s = str(self._param_err)
        if s:
            l.append('Parameter Error(s):\n%s\n' % s)
        
        s = str(self._pass_through_err)
        if s:
            l.append('Parameter Error(s):\n%s\n' % s)
            
        s = str(self._category_err)
        if s:
            l.append('Category Error(s):\n%s\n' % s)
            
        s = str(self._resource_ref_err)
        if s:
            l.append('Resource Ref Error(s):\n%s\n' % s)
        
        return "".join(l)
    
    def _to_resdef(self):
        """
        Gathers all the error messages set and returns them in a dictionary.
        
        @return: Error message dictionary.
        @rtype:  dict
        
        """
        
        ret_dict = {}
        err_dict = self._prop_err._to_resdef()
        if err_dict is not None:
            ret_dict[keys.PROPERTY_VALS] = err_dict
        
        err_dict = self._input_view_err._to_resdef()    
        if err_dict is not None:
            ret_dict[keys.INPUT_VIEWS] = err_dict
        
        err_dict = self._output_view_err._to_resdef()
        if err_dict is not None:
            ret_dict[keys.OUTPUT_VIEWS] = err_dict
        
        err_dict = self._param_err._to_resdef()
        if err_dict is not None:
            ret_dict[keys.PARAMS] = err_dict
        
        err_dict = self._pass_through_err._to_resdef()
        if err_dict is not None:
            ret_dict[keys.OUTPUT_VIEW_PASSTHROUGH] = err_dict
        
        if self._category_err is not None:
            err_dict = self._category_err._to_resdef()
            if err_dict is not None:
                ret_dict[keys.RESOURCE_CATEGORY] = err_dict
        
        if self._resource_ref_err is not None:
            err_dict = self._resource_ref_err._to_resdef()
            if err_dict is not None:
                ret_dict[keys.RESOURCE_REF] = err_dict
        
        if not len(ret_dict):
            ret_dict = None
        
        if ret_dict is None and self._err_msg is None:
            return None
        
        return {keys.LABEL: "Resource", keys.ERROR_MESSAGE : self._err_msg, keys.DICT_ERROR : ret_dict}
        
    def set_message(self, err_msg = None):
        """
        Sets an error message.
        
        @param err_msg: Error message
        @type err_msg:  str
        
        """
        
        self._err_msg = err_msg
        
    def get_property_err(self, prop_name):
        """
        This function returns an error object which reflects the current contents of the property.
        
        If the property is a dictionary, then the error object has one too, with the current key names.
        If the property is a list, then the error object has a corresponding list with same number of entries.
        This error object will allow error message to be associated with the whole property or even with
        specific list/dictionary entry within the property via set_message() methods.
        
        For example, consider a complex property called 'Company' which has nested dictionaries and lists:
        v = {}
        v['name'] = 'Acme'
        v['Employees'] = {}
        v['Employees']['John Doe'] = {'Sex':'M',
                                      'Age':39
                                      'Phone': ['408-555-1234', '650-555-12']
                                     }
        v['Employees']['Jane 9 Doe'] = {'Sex':'F',
                                        'Age':25
                                        'Phone': ['408-555-4567']
                                     }
        self.set_property_value('Company', v)
        
        During validation, one can set error for this complex property as follows:
        
        # Retrieve the error object for the property
        err_obj = self.get_property_err('Company')
        # Set an error for the whole property if you like
        err_obj.set_message('This company information is wrong')
        # Or, one can set very specific error messages for a nested value in the property
        err_obj['Employees']['John Doe']['Phone'][1].set_message('Phone number must have 10 digits')
        # Here is another example
        err_obj['Employees']['Jane 9 Doe'].set_message('Name cannot have a numeric value')

        In this manner, one can associate error messages not only with the whole property, but also
        with specific values inside a complex property. This capability is especially useful for
        displaying error message in the GUI, right next to the incorrect value.
         
        @param property_name: Name of the property
        @type property_name:  str
        
        @return: Property error object
        @rtype:  Error object
         
        @param prop_name: Property name
        @type prop_name:  str
        
        @return: Error object
        @rtype:  L{SimplePropErr}, L{ListPropErr} or L{DictPropErr}
        
        """
        if prop_name not in self._prop_err:
            raise SnapObjNotFoundError("Property '%s' not found" % prop_name)
        
        return self._prop_err[prop_name]
    
    def get_input_view_err(self, view_name = None):
        """
        Get error object for the specified input view name or input views in general.
        If  no view name is specified, error object for all views is returned.
        
        @param view_name: View name for which error object is being requested.
        @type prop_name:  str
        
        @return: Error object
        @rtype:  L{DictPropErr}
        
        """
        if view_name is None:
            return self._input_view_err
        
        elif view_name in self._input_view_err:
            return self._input_view_err[view_name]
        else:
            raise SnapObjNotFoundError("Input view '%s' not found" % view_name)
    
    def get_output_view_err(self, view_name = None):
        """
        Get error object for the specified output view name or output views in general.
        If  no view name is specified, error object for all output views is returned.
        
        @param view_name: View name for which error object is being requested.
        @type view_name:  str
        
        @return: Error object
        @rtype:  L{DictPropErr}
        
        """
        if view_name is None:
            return self._output_view_err
        
        elif view_name in self._output_view_err:
            return self._output_view_err[view_name]
        else:
            raise SnapObjNotFoundError("Output view '%s' not found" % view_name)
        
    def get_pass_through_err(self, output_view_name = None):
        """
        Get error object for pass through setting of the specified output view or pass through in general.
        If no output view name is specified, then error object for pass through in general is returned.
        
        @param output_view_name: Output view name for which error object is being requested.
        @type output_view_name:  str
        
        @return: Error object
        @rtype:  L{DictPropErr}
        
        """
        if output_view_name is None:
            return self._pass_through_err
        
        elif output_view_name in self._pass_through_err:
            return self._pass_through_err[output_view_name]
        else:
            raise SnapObjNotFoundError("Output view '%s' not found" % output_view_name)
    
    def get_parameter_err(self, param_name = None):
        """
        Get error object for specified param or params in general.
        If no param name is specified, then error object for params in general is returned.
        
        @param param_name: Parma name for which error object is being requested.
        @type param_name:  str
        
        @return: Error object
        @rtype:  L{DictPropErr}
        
        """
        if param_name is None:
            return self._param_err
        elif param_name in self._param_err:
            return self._param_err[param_name]
        else:
            raise SnapObjNotFoundError("Parameter '%s' not found" % param_name)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.