class AdhocAction(): sort_order_map = None common = Common() def removeRenameFieldInJRXMLFile(self, filename, fieldname, newfieldname, log): log.debug('Preparing to remove field(s) from JRXML file: ' + filename[filename.rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(filename, 'r', encoding='utf-8') as h: report_xml = h.read() report_tuple = self.common.removeDeclarationNode(xml_string=report_xml) report_xml = report_tuple[1] parser = etree.XMLParser(strip_cdata=False) # remove queryString node that contains an extra XML declaration to avoid syntax error try: begin_index = report_xml.index('<?xml', 2) except ValueError: log.debug('Report does not contain a domain query. Skipping...') begin_index = -1 if begin_index > 0: end_index = report_xml.find(']]>', begin_index) report_xml_outer = report_xml[0:begin_index] + report_xml[ end_index:len(report_xml)] report_xml_inner = report_xml[begin_index:end_index] report_root = etree.fromstring(report_xml_outer, parser) self.removeRenameFieldInJRXML(root=report_root, fieldname=fieldname, newfieldname=newfieldname, log=log) # remove the <?xml ?> declaration from the beginning because lxml fromstring() can't handle the encoding query_tag_index = report_xml_inner.find('<' + Common.QUERY) report_xml_inner = report_xml_inner[query_tag_index:] query_root = etree.fromstring(report_xml_inner) self.removeRenameQueryFieldInAdhocQuery(root=query_root, fieldname=fieldname, newfieldname=newfieldname, log=log) # re-insert domain query back into topic query_bytea = etree.tostring(query_root, pretty_print=True, encoding='UTF-8') query_str = "".join(map(chr, query_bytea)) self.reinsertQueryIntoMainBody(root=report_root, query_str=query_str) else: report_root = etree.fromstring(report_xml, parser) self.removeRenameFieldInJRXML(root=report_root, fieldname=fieldname, newfieldname=newfieldname, log=log) report_bytea = etree.tostring(report_root, pretty_print=True, encoding='UTF-8') report_xml = "".join(map(chr, report_bytea)) # re-insert original XML declaration report_xml = report_tuple[0] + report_xml with open(filename, 'w', encoding='utf-8') as h: h.write(report_xml) def removeRenameFieldInJRXML(self, root, fieldname, newfieldname, log): semantic_tree_sort_order = None semantic_tree_sort_order_set = False semantic_tree_sort_order_deleted = False # if field is a parameter for param in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.PARAMETER, namespaces=Common.JRXML_NAMESPACE): nameValue = param.get(Common.NAME) if nameValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming parameter ' + nameValue + ' to ' + nameValue.replace(fieldname, newfieldname)) param.attrib[Common.NAME] = nameValue.replace( fieldname, newfieldname) else: log.debug('removing parameter: ' + nameValue) param.getparent().remove(param) # remove or rename field for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.FIELD, namespaces=Common.JRXML_NAMESPACE): nameValue = field.get(Common.NAME) if semantic_tree_sort_order_set == False and semantic_tree_sort_order_deleted == False: for child in field: if child.get(Common.NAME) == Common.SORT_ORDER: if newfieldname is not None and newfieldname != '_' and child.text is not None and child.text.find( fieldname) >= 0: child.text = etree.CDATA( child.text.replace(fieldname, newfieldname)) semantic_tree_sort_order_set = True else: semantic_tree_sort_order = self.fixSortOrder( fieldname=fieldname, semantic_tree_sort_order=child.text) # Fix any other property values where the fieldname appears elif newfieldname is not None and newfieldname != '_' and child.get( Common.VALUE) is not None and child.get( Common.VALUE).find(fieldname) >= 0: childValue = child.get(Common.VALUE) log.debug('changing value for property ' + child.get(Common.NAME) + ' from ' + childValue + ' to ' + childValue.replace(fieldname, newfieldname)) child.attrib[Common.VALUE] = childValue.replace( fieldname, newfieldname) if nameValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming field ' + nameValue + ' to ' + nameValue.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = nameValue.replace( fieldname, newfieldname) else: log.debug('removing field: ' + nameValue) field.getparent().remove(field) semantic_tree_sort_order_deleted = True else: for child in field: if (child.get(Common.NAME) == Common.SORT_ORDER): if semantic_tree_sort_order_set == False: if (child.get(Common.VALUE) != None): del child.attrib[Common.VALUE] if semantic_tree_sort_order != None: child.text = etree.CDATA( semantic_tree_sort_order) semantic_tree_sort_order_set = True elif newfieldname is None or newfieldname == '_': field_key = field.get(Common.NAME) if field_key.find('.') >= 0: field_key = field_key[field_key.rfind('.') + 1:] child.attrib[Common.VALUE] = self.sort_order_map[ '"' + field_key + '"'] # Fix any other property values where the fieldname appears if newfieldname is not None and newfieldname != '_': for child in field: if (child.get(Common.NAME) != Common.SORT_ORDER) and child.get( Common.VALUE) is not None and child.get( Common.VALUE).find(fieldname) >= 0: childValue = child.get(Common.VALUE) log.debug('changing value for property ' + child.get(Common.NAME) + ' from ' + childValue + ' to ' + childValue.replace(fieldname, newfieldname)) child.attrib[Common.VALUE] = childValue.replace( fieldname, newfieldname) def fixSortOrder(self, fieldname, semantic_tree_sort_order): if semantic_tree_sort_order != None: # Strip the curly braces and convert to a map semantic_tree_sort_order = semantic_tree_sort_order[ semantic_tree_sort_order.find('{') + 1:semantic_tree_sort_order.find('}')] self.sort_order_map = dict( item.split(':') for item in semantic_tree_sort_order.split(',')) if '"' + fieldname + '"' in self.sort_order_map.keys(): del self.sort_order_map['"' + fieldname + '"'] self.fixSortingValues() semantic_tree_sort_order = ','.join( '%s:%d' % (k, int(v)) for k, v in self.sort_order_map.items()) return '{' + semantic_tree_sort_order + '}' else: return None def fixSortingValues(self): if self.sort_order_map != None: smallest_value = 99999 for value in self.sort_order_map.values(): if int(value) < smallest_value: smallest_value = int(value) value_diff = smallest_value - 1 for key in self.sort_order_map.keys(): self.sort_order_map[key] = str( int(self.sort_order_map[key]) - value_diff) def removeRenameQueryFieldInAdhocQuery(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:' + Common.QUERY_FIELD, namespaces=Common.DOMAIN_QUERY_NAMESPACE): idValue = field.get(Common.ID) if idValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming field ' + idValue + ' to ' + idValue.replace(fieldname, newfieldname)) field.attrib[Common.ID] = idValue.replace( fieldname, newfieldname) else: log.debug('removing field: ' + idValue) field.getparent().remove(field) def reinsertQueryIntoMainBody(self, root, query_str): query_str = '<?xml version="1.0" encoding="UTF-8"?>\n' + query_str for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.QUERY_STRING, namespaces=Common.JRXML_NAMESPACE): field.text = etree.CDATA(query_str) return query_str def removeRenameFieldInStateFile(self, filename, fieldname, newfieldname, log): log.debug('Preparing to remove field(s) from state file: ' + filename[filename.rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(filename, 'r', encoding='utf-8') as h: state_xml = h.read() state_tuple = self.common.removeDeclarationNode(xml_string=state_xml) state_root = etree.fromstring(state_tuple[1]) self.removeRenameFieldInState(root=state_root, fieldname=fieldname, newfieldname=newfieldname, log=log) state_bytea = etree.tostring(state_root, pretty_print=True, encoding='UTF-8') state_xml = "".join(map(chr, state_bytea)) # re-insert original XML declaration state_xml = state_tuple[0] + state_xml if state_xml.endswith('\n'): state_xml = state_xml[0:len(state_xml) - 1] with open(filename, 'w', encoding='utf-8') as h: h.write(state_xml) def removeRenameFieldInState(self, root, fieldname, newfieldname, log): # if the field is a measure for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.MEASURE): fieldnameValue = field.get(Common.FIELD_NAME) nameValue = field.get(Common.NAME) if fieldnameValue != None and fieldnameValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming measure from ' + fieldnameValue + ' to ' + fieldnameValue.replace(fieldname, newfieldname)) field.attrib[Common.FIELD_NAME] = fieldnameValue.replace( fieldname, newfieldname) if nameValue.find(fieldname) >= 0: log.debug('renaming measure name attribute from ' + nameValue + ' to ' + nameValue.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = nameValue.replace( fieldname, newfieldname) # check and rename the labelOverride property if necessary labelOverride = field.get(Common.LABEL_OVERRIDE) if labelOverride is not None and labelOverride.find( fieldname) >= 0: log.debug( 'changing labelOverride property from ' + labelOverride + ' to ' + labelOverride.replace(fieldname, newfieldname)) field.attrib[ Common.LABEL_OVERRIDE] = labelOverride.replace( fieldname, newfieldname) else: log.debug('removing measure: ' + fieldnameValue) field.getparent().remove(field) # if the field is a dimension for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.QUERY_DIMENSION): fieldnameValue = field.get(Common.FIELD_NAME) nameValue = field.get(Common.NAME) if fieldnameValue != None and fieldnameValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming dimension from ' + fieldnameValue + ' to ' + fieldnameValue.replace(fieldname, newfieldname)) field.attrib[Common.FIELD_NAME] = fieldnameValue.replace( fieldname, newfieldname) if nameValue.find(fieldname) >= 0: log.debug('renaming measure name attribute from ' + nameValue + ' to ' + nameValue.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = nameValue.replace( fieldname, newfieldname) else: log.debug('removing dimension: ' + fieldnameValue) field.getparent().remove(field) # if the field is a field for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.FIELD, namespaces=Common.DOMAIN_QUERY_NAMESPACE): idValue = field.get(Common.ID) if idValue != None and idValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming field ' + idValue + ' to ' + idValue.replace(fieldname, newfieldname)) field.attrib[Common.ID] = idValue.replace( fieldname, newfieldname) else: log.debug('removing field: ' + idValue) field.getparent().remove(field) # if the field is used in a parameter for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.EXPRESSION_STRING): if field.text.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': textValue = field.text log.debug('changing expressionString ' + textValue + ' to ' + textValue.replace(fieldname, newfieldname)) field.text = textValue.replace(fieldname, newfieldname) sibling = field.getnext() if sibling is not None and sibling.text.find( fieldname) >= 0: textField2 = sibling.text log.debug('changing parameterizedExpressionString ' + textField2 + ' to ' + textField2.replace(fieldname, newfieldname)) sibling.text = textField2.replace( fieldname, newfieldname) else: parent = field.getparent() log.debug('removing parameter: ' + parent.get(Common.ID)) parent.getparent().remove(parent) # fix visible levels self.common.fixVisibleLevels(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) def removeRenameField(self, state_filename, jrxml_filename, fieldname, newfieldname, log): if isinstance(fieldname, list): if newfieldname is None: newfieldname = [] for _ in fieldname: newfieldname.append('_') for s1, s2 in zip(fieldname, newfieldname): self.removeRenameFieldInJRXMLFile(jrxml_filename, s1, s2, log) self.removeRenameFieldInStateFile(state_filename, s1, s2, log) else: self.removeRenameFieldInJRXMLFile(jrxml_filename, fieldname, newfieldname, log) self.removeRenameFieldInStateFile(state_filename, fieldname, newfieldname, log) def removeRenameInputControlInMetadata(self, root, fieldname, newfieldname, log): # remove entire IC or fix query value and visible columns for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + 'queryValueColumn'): textValue = field.text if textValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('Changing queryValueColumn ' + textValue + ' to ' + textValue.replace(fieldname, newfieldname)) field.text = textValue.replace(fieldname, newfieldname) sibling = field.getprevious() if sibling is not None and sibling.text.find( fieldname) >= 0: textValue2 = sibling.text log.debug('Changing queryVisibleColumn ' + textValue2 + ' to ' + textValue2.replace(fieldname, newfieldname)) sibling.text = textValue2.replace( fieldname, newfieldname) else: parent = field.getparent() log.debug('removing input control: ' + parent[Common.ID_NODE_INDEX].text) parent.getparent().remove(parent) # fix query if newfieldname is not None and newfieldname != '_': for query in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + 'queryString'): queryText = query.text if queryText.find(fieldname) >= 0: log.debug('Changing query to ' + queryText.replace(fieldname, newfieldname)) query.text = queryText.replace(fieldname, newfieldname) # fix name for name in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + Common.NAME): nameText = name.text if nameText.find(fieldname) >= 0: log.debug('Changing name ' + nameText + ' to ' + nameText.replace(fieldname, newfieldname)) name.text = nameText.replace(fieldname, newfieldname) # fix folder for folder in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + 'folder'): folderText = folder.text if folderText is not None and folderText.find(fieldname) >= 0: log.debug('Changing folder ' + folderText + ' to ' + folderText.replace(fieldname, newfieldname)) folder.text = folderText.replace(fieldname, newfieldname) def removeRenameInputControlInMetadataFile(self, metadata_filename, fieldname, newfieldname, log): log.debug('Checking metadata file for input controls to remove: ' + metadata_filename[metadata_filename. rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(metadata_filename) as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( xml_string=metadata_xml) metadata_xml = metadata_tuple[1] metadata_root = etree.fromstring(metadata_xml) if isinstance(fieldname, list): if newfieldname is None: newfieldname = [] for _ in fieldname: newfieldname.append('_') for s1, s2 in zip(fieldname, newfieldname): self.removeRenameInputControlInMetadata(root=metadata_root, fieldname=s1, newfieldname=s2, log=log) else: self.removeRenameInputControlInMetadata(root=metadata_root, fieldname=fieldname, newfieldname=newfieldname, log=log) metadata_bytea = etree.tostring(metadata_root, pretty_print=True, encoding='UTF-8') metadata_xml = "".join(map(chr, metadata_bytea)) # re-insert original XML declaration metadata_xml = metadata_tuple[0] + metadata_xml if metadata_xml.endswith('\n'): metadata_xml = metadata_xml[0:len(metadata_xml) - 1] with open(metadata_filename, 'w') as h: h.write(metadata_xml)
class FileFinderTest(unittest.TestCase): common = Common() DOMAIN_SCHEMA_FILE = """<?xml version="1.0" encoding="UTF-8"?> <semanticLayerDataSource> <folder></folder> <name>Domain_Test</name> <schema> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="schema.data" xsi:type="fileResource"> <folder></folder> </localResource> </schema> </semanticLayerDataSource> """ ADHOC_TOPIC_FILE = """<?xml version="1.0" encoding="UTF-8"?> <dataDefinerUnit> <folder></folder> <name>Adhoc_Topic_Test</name> <mainReport> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="slJRXML.data" xsi:type="fileResource"> <folder></folder> </localResource> </mainReport> <dataSource> <uri>/Domain_Test</uri> </dataSource> <resource> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="domainQuery.xml.data" xsi:type="fileResource"> <folder></folder> </localResource> </resource> </dataDefinerUnit> """ ADHOC_VIEW_FILE = """<?xml version="1.0" encoding="UTF-8"?> <adhocDataView exportedWithPermissions="true"> <folder></folder> <name>Adhoc_View_Test</name> <dataSource> <uri>/Adhoc_Topic_Test</uri> </dataSource> <inputControl> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" xsi:type="inputControl"> <folder>/Adhoc_View_Test_files</folder> <name>store_country_1</name> <label>Country</label> <type>4</type> <mandatory>false</mandatory> <readOnly>false</readOnly> <visible>true</visible> <query> <localResource exportedWithPermissions="false" xsi:type="query"> <folder>/Adhoc_View_Test_files/store_country_1_files</folder> <name>store_country_1</name> <version>0</version> <label>Country</label> <language>domain</language> <queryString><?xml version="1.0" encoding="UTF-8"?> <query xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema"> <groupList> <group columnName="store_country" /> </groupList> <queryFields> <queryField id="public_store.store_country" /> <queryField id="store_country" /> </queryFields> </query> </queryString> <dataSource> <uri>/Domain_Test</uri> </dataSource> </localResource> </query> <queryVisibleColumn>store_country</queryVisibleColumn> <queryValueColumn>store_country</queryValueColumn> </localResource> </inputControl> <resource> <uri>/domainQuery.xml</uri> </resource> <resource> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="topicJRXML.data" xsi:type="fileResource"> <folder></folder> <name>topicJRXML</name> </localResource> </resource> <resource> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="stateXML.data" xsi:type="fileResource"> <folder></folder> <name>stateXML</name> </localResource> </resource> </adhocDataView> """ REPORT_FILE = """<?xml version="1.0" encoding="UTF-8"?> <reportUnit exportedWithPermissions="true"> <folder></folder> <name>Report_Test</name> <mainReport> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="mainReportJrxml.data" xsi:type="fileResource"> <folder></folder> <name>mainReportJrxml</name> </localResource> </mainReport> <dataSource> <uri>/Adhoc_View_Test</uri> </dataSource> <resource> <localResource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exportedWithPermissions="false" dataFile="stateXML.data" xsi:type="fileResource"> <folder></folder> <name>stateXML</name> </localResource> </resource> </reportUnit> """ XML_EXT = '.xml' DOMAIN_NAME = 'Domain_Test' ADHOC_TOPIC_NAME = 'Adhoc_Topic_Test' ADHOC_VIEW_NAME = 'Adhoc_View_Test' REPORT_NAME = 'Report_Test' TMPPATH = 'tmp' def setUp(self): self.fileFinder = FileFinder() self.log = self.common.configureLogging() curr_folder = Common.REPO_PATH_SEPARATOR + self.TMPPATH self.fileFinder.resources_folder = curr_folder self.domain_metadata_file_path = curr_folder + Common.REPO_PATH_SEPARATOR + self.DOMAIN_NAME + self.XML_EXT self.adhoc_topic_metadata_file_path = curr_folder + Common.REPO_PATH_SEPARATOR + self.ADHOC_TOPIC_NAME + self.XML_EXT self.adhoc_view_metadata_file_path = curr_folder + Common.REPO_PATH_SEPARATOR + self.ADHOC_VIEW_NAME + self.XML_EXT self.report_metadata_file_path = curr_folder + Common.REPO_PATH_SEPARATOR + self.REPORT_NAME + self.XML_EXT directory = os.path.dirname(self.domain_metadata_file_path) if not os.path.exists(directory): os.makedirs(directory) with open(self.domain_metadata_file_path, 'w') as h1: h1.write(self.DOMAIN_SCHEMA_FILE) with open(self.adhoc_topic_metadata_file_path, 'w') as h2: h2.write(self.ADHOC_TOPIC_FILE) with open(self.adhoc_view_metadata_file_path, 'w') as h3: h3.write(self.ADHOC_VIEW_FILE) with open(self.report_metadata_file_path, 'w') as h4: h4.write(self.REPORT_FILE) def tearDown(self): try: os.remove(self.report_metadata_file_path) os.remove(self.adhoc_view_metadata_file_path) os.remove(self.adhoc_topic_metadata_file_path) os.remove(self.domain_metadata_file_path) except OSError: pass def testCheckDatasource(self): mock_root = MagicMock(name = 'mock_root') mock_root.tag.find.return_value = 0 mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = 0 mock_root.__getitem__.return_value = mock_node1 self.assertTrue(self.fileFinder.checkDatasource(mock_root)) def testCheckDatasourceDoesNotMatch(self): mock_root = MagicMock(name = 'mock_root') mock_root.tag.find.return_value = 0 mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = -1 mock_root.__getitem__.return_value = mock_node1 self.assertFalse(self.fileFinder.checkDatasource(mock_root)) def testCheckDatasourceCheckParent(self): self.fileFinder.domain_id = self.DOMAIN_NAME mock_root = MagicMock(name = 'mock_root'); mock_root.tag.find.side_effect = [-1, 0] mock_node1 = MagicMock(name='mock_node1') mock_node1_text = PropertyMock(return_value=Common.REPO_PATH_SEPARATOR + self.DOMAIN_NAME) type(mock_node1).text = mock_node1_text node_list = [mock_node1] mock_root.xpath = MagicMock(side_effect=[node_list]) self.assertTrue(self.fileFinder.checkDatasource(mock_root)) def testFindDomainSchema(self): schema_filename = 'schema.data' self.fileFinder.domain_id = self.DOMAIN_NAME mock_grandchild = MagicMock(name='mock_grandchild') mock_grandchild_text = PropertyMock(return_value='') type(mock_grandchild).text = mock_grandchild_text mock_root = MagicMock(name = 'mock_root') mock_node1 = MagicMock(name = 'mock_node1') mock_node1.get.return_value = schema_filename mock_node1.__getitem__.return_value = mock_grandchild node_list = [mock_node1] mock_root.xpath = MagicMock(side_effect=[node_list]) found_file = self.fileFinder.findDomainSchema(root=mock_root, log=self.log) self.assertIsNotNone(found_file, 'findDomainSchemaFile should not return none') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + schema_filename, found_file, 'domain schema file not found') def testFindDomainSchemaFile(self): found_file = self.fileFinder.findDomainSchemaFile(metadata_filename=self.domain_metadata_file_path, log=self.log) self.assertIsNotNone(found_file, 'findDomainSchema should not return none') test_domain_schema_file = '/tmp/schema.data' self.assertEqual(test_domain_schema_file, found_file, 'domain schema file names do not match') def testFindAdHocTopic(self): state_file = 'stateXML.data' jrxml_file = 'slJRXML.data' self.fileFinder.domain_id = self.DOMAIN_NAME self.fileFinder.adhoc_topic_files_list = [] mock_grandchild = MagicMock(name='mock_grandchild') mock_grandchild_text = PropertyMock(return_value=self.DOMAIN_NAME) type(mock_grandchild).text = mock_grandchild_text mock_grandchild.text = MagicMock(return_value=self.DOMAIN_NAME) mock_grandchild2 = MagicMock(name='mock_grandchild2') mock_grandchild2_text = PropertyMock(return_value=None) type(mock_grandchild2).text = mock_grandchild2_text mock_root = MagicMock(name = 'mock_root') mock_root_tag = PropertyMock(return_value=Common.DOMAIN_METADATA_TAG) type(mock_root).tag = mock_root_tag mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = 0 mock_node2 = MagicMock(name = 'mock_node2') mock_node2.__getitem__.return_value = mock_grandchild2 mock_node2.get.return_value = jrxml_file mock_node2.text.find.return_value = 0 node_list1 = [mock_node2] mock_node3 = MagicMock(name = 'mock_node3') mock_node3.__getitem__.return_value = mock_grandchild2 mock_node3.get.return_value = state_file node_list2 = [mock_node3] mock_node4 = MagicMock(name='mock_node4') mock_node4_text = PropertyMock(return_value=self.ADHOC_TOPIC_NAME) type(mock_node4).text = mock_node4_text mock_root.__getitem__.side_effect = [mock_node1, mock_grandchild] mock_root.xpath = MagicMock(side_effect = [node_list1, node_list2]) self.fileFinder.findAdhocTopic(root=mock_root, adhoc_topic_id=self.ADHOC_TOPIC_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.adhoc_topic_files_list, 'Ad Hoc topic files not found') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + state_file, self.fileFinder.adhoc_topic_files_list[0][0], 'state file not found') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + jrxml_file, self.fileFinder.adhoc_topic_files_list[0][1], 'jrxml file not found') def testFindAdHocTopicIDDoesNotMatch(self): self.fileFinder.adhoc_topic_files_list = [] mock_root = MagicMock(name = 'mock_root') mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = -1 mock_root.__getitem__.return_value = mock_node1 self.fileFinder.findAdhocTopic(root=mock_root, adhoc_topic_id=self.ADHOC_TOPIC_NAME, log=self.log) self.assertEqual([], self.fileFinder.adhoc_topic_files_list, 'ad hoc topic files should not be found') def testFindAdHocTopicFiles(self): self.fileFinder.adhoc_topic_files_list = [] self.fileFinder.domain_id = self.DOMAIN_NAME self.fileFinder.findAdhocTopicFiles(metadata_filename=self.adhoc_topic_metadata_file_path, adhoc_topic_id=self.ADHOC_TOPIC_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.adhoc_topic_files_list, 'Ad Hoc topic files list is empty') test_adhoc_topic_state_file = '/tmp/domainQuery.xml.data' self.assertEqual(test_adhoc_topic_state_file, self.fileFinder.adhoc_topic_files_list[0][0], 'ad hoc topic state file names do not match') test_adhoc_topic_report_file = '/tmp/slJRXML.data' self.assertEqual(test_adhoc_topic_report_file, self.fileFinder.adhoc_topic_files_list[0][1], 'jrxml report file names do not match') def testFindAdHocTopicFilesIDDoesNotMatch(self): self.fileFinder.adhoc_topic_files_list = [] self.fileFinder.domain_id = self.DOMAIN_NAME self.fileFinder.findAdhocTopicFiles(metadata_filename=self.adhoc_topic_metadata_file_path, adhoc_topic_id='Some_Other_Topic', log=self.log) self.assertEqual([], self.fileFinder.adhoc_topic_files_list, 'Ad Hoc topic files should not be found') def testFindAdHocView(self): state_filename = 'stateXML.data' jrxml_filename = 'topicJRXML.data' self.fileFinder.adhoc_view_files_list = [] self.fileFinder.domain_id = self.DOMAIN_NAME mock_grandchild = MagicMock(name='mock_grandchild') mock_grandchild_text = PropertyMock(return_value='') type(mock_grandchild).text = mock_grandchild_text mock_root = MagicMock(name = 'mock_root') mock_root.tag.find.return_value = 0 mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = 0 mock_node1.get.return_value = state_filename mock_node2 = MagicMock(name = 'mock_node2') mock_node2.get.return_value = jrxml_filename mock_node3 = MagicMock(name = 'mock_node3') mock_node3_text = PropertyMock(return_value=state_filename) type(mock_node3).text = mock_node3_text mock_node4 = MagicMock(name = 'mock_node4') mock_node4_text = PropertyMock(return_value=jrxml_filename) type(mock_node4).text = mock_node4_text mock_node1.__getitem__.side_effect = [mock_node3, mock_grandchild] mock_node2.__getitem__.side_effect = [mock_node4, mock_grandchild] node_list = [mock_node1, mock_node2] mock_root.__getitem__.side_effect = [mock_node1, mock_node1] mock_root.xpath = MagicMock(side_effect = [node_list, []]) self.fileFinder.findAdhocView(root=mock_root, adhoc_view_id=self.ADHOC_VIEW_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.adhoc_view_files_list, 'Ad Hoc view files not found') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + state_filename, self.fileFinder.adhoc_view_files_list[0][0], 'state file not found') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + jrxml_filename, self.fileFinder.adhoc_view_files_list[0][1], 'jrxml file not found') def testFindAdHocViewIDDoesNotMatch(self): mock_root = MagicMock(name = 'mock_root') mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = -1 mock_root.__getitem__.return_value = mock_node1 self.fileFinder.findAdhocView(root=mock_root, adhoc_view_id=self.ADHOC_VIEW_NAME, log=self.log) self.assertEqual([], self.fileFinder.adhoc_view_files_list, 'ad hoc view files should not have been found') def testFindAdHocViewFiles(self): self.fileFinder.domain_id = self.DOMAIN_NAME self.fileFinder.adhoc_view_files_list = [] self.fileFinder.findAdhocViewFiles(metadata_filename=self.adhoc_view_metadata_file_path, adhoc_view_id=self.ADHOC_VIEW_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.adhoc_view_files_list, 'Ad Hoc view files not found') test_adhoc_view_state_file = '/tmp/stateXML.data' self.assertEqual(test_adhoc_view_state_file, self.fileFinder.adhoc_view_files_list[0][0], 'ad hoc view state file names do not match') test_adhoc_view_report_file = '/tmp/topicJRXML.data' self.assertEqual(test_adhoc_view_report_file, self.fileFinder.adhoc_view_files_list[0][1], 'jrxml report file names do not match') def testFindAdHocViewFilesIDDoesNotMatch(self): self.fileFinder.findAdhocViewFiles(metadata_filename=self.adhoc_view_metadata_file_path, adhoc_view_id='Some_Other_View', log=self.log) self.assertEqual([], self.fileFinder.adhoc_view_files_list, 'Ad Hoc view files should not be found') def testFindReport(self): state_filename = 'stateXML.data' jrxml_filename = 'mainReportJrxml.data' self.fileFinder.report_list = [] mock_grandchild = MagicMock(name='mock_grandchild') mock_grandchild_text = PropertyMock(return_value=self.TMPPATH) type(mock_grandchild).text = mock_grandchild_text mock_grandchild2 = MagicMock(name='mock_grandchild2') mock_grandchild2_text = PropertyMock(return_value=None) type(mock_grandchild2).text = mock_grandchild2_text mock_root = MagicMock(name = 'mock_root') mock_root.tag.find.return_value = 0 mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = 0 mock_node2 = MagicMock(name = 'mock_node2') mock_node2.text.find.return_value = 0 mock_node2.get.return_value = state_filename mock_node2.__getitem__.return_value = mock_grandchild2 node_list1 = [mock_node2] mock_node3 = MagicMock(name = 'mock_node3') mock_node3.get.return_value = jrxml_filename mock_node3.__getitem__.return_value = mock_grandchild2 mock_root.__getitem__.return_value = mock_node1 node_list2 = [mock_node3] mock_root.xpath = MagicMock(side_effect = [node_list2, node_list1]) self.fileFinder.findReport(root=mock_root, report_id=self.REPORT_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.report_list, 'Report files not found') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + state_filename, self.fileFinder.report_list[0][0], 'state filenames do not match') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + jrxml_filename, self.fileFinder.report_list[0][1], 'report filenames do not match') def testFindStaticReport(self): jrxml_filename = 'main_jrxml.data' self.fileFinder.report_list = [] mock_grandchild = MagicMock(name='mock_grandchild') mock_grandchild.text = MagicMock(return_value=self.TMPPATH) mock_grandchild2 = MagicMock(name='mock_grandchild2') mock_grandchild2_text = PropertyMock(return_value=None) type(mock_grandchild2).text = mock_grandchild2_text mock_root = MagicMock(name = 'mock_root') mock_root.tag.find.return_value = 0 mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = 0 mock_node2 = MagicMock(name = 'mock_node3') mock_node2.get.return_value = jrxml_filename mock_node2.__getitem__.return_value = mock_grandchild2 mock_root.__getitem__.return_value = mock_node1 node_list1 = [mock_node2] mock_root.xpath = MagicMock(side_effect = [node_list1, []]) self.fileFinder.findReport(root=mock_root, report_id=self.REPORT_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.report_list, 'Report files not found') self.assertIsNone(self.fileFinder.report_list[0][0], 'state filename is not None') self.assertEqual(Common.REPO_PATH_SEPARATOR + self.TMPPATH + Common.REPO_PATH_SEPARATOR + jrxml_filename, self.fileFinder.report_list[0][1], 'jrxml filenames do not match') def testFindReportIDDoesNotMatch(self): self.fileFinder.adhoc_view_files_list = [] self.fileFinder.report_list = [] mock_root = MagicMock(name = 'mock_root') mock_node1 = MagicMock(name = 'mock_node1') mock_node1.text.find.return_value = -1 mock_root.__getitem__.return_value = mock_node1 self.fileFinder.findReport(root=mock_root, report_id=self.REPORT_NAME, log=self.log) self.assertEqual([], self.fileFinder.report_list, 'report files should not have been found') def testFindReportFiles(self): self.fileFinder.domain_id = self.DOMAIN_NAME self.fileFinder.findReportFiles(metadata_filename=self.report_metadata_file_path, report_id=self.REPORT_NAME, log=self.log) self.assertNotEqual([], self.fileFinder.report_list, 'report files not found') test_report_state_file = '/tmp/stateXML.data' self.assertEqual(test_report_state_file, self.fileFinder.report_list[0][0], 'report state file names do not match') test_report_jrxml_file = '/tmp/mainReportJrxml.data' self.assertEqual(test_report_jrxml_file, self.fileFinder.report_list[0][1], 'jrxml report file names do not match')
class DomainAction(): common = Common() def renameOrRemoveFieldFromSchema(self, root, fieldname, newfieldname, newdbcolname, log): # if field is foreign key for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.JOIN_STRING, namespaces=Common.DOMAIN_QUERY_NAMESPACE): if field.text.find(fieldname) >= 0: raise ValueError('We will probably be able to handle removing key fields in the future, but for now it is not allowed') # if field is an item for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.ITEM, namespaces=Common.DOMAIN_QUERY_NAMESPACE): idValue = field.get(Common.ID) if idValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming item ' + idValue + ' to ' + idValue.replace(fieldname, newfieldname)) field.attrib[Common.ID] = idValue.replace(fieldname, newfieldname) field.attrib[Common.RESOURCE_ID] = field.get(Common.RESOURCE_ID).replace(fieldname, newfieldname) # change the label only if the label ID property isn't set (ignore if using I18N) if len(field.get(Common.LABEL_ID)) == 0: field.attrib[Common.LABEL] = field.get(Common.LABEL).replace(fieldname, newfieldname) else: log.debug('removing item: ' + idValue) field.getparent().remove(field) # if field is a field for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.FIELD, namespaces=Common.DOMAIN_QUERY_NAMESPACE): idValue = field.get(Common.ID) if idValue.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming field ' + idValue + ' to ' + idValue.replace(fieldname, newfieldname)) field.attrib[Common.ID] = idValue.replace(fieldname, newfieldname) if newdbcolname is not None and newdbcolname != '_': log.debug('Renaming field DB column name to: ' + newdbcolname) field.attrib[Common.FIELD_DB_NAME] = newdbcolname else: log.debug('removing field: ' + idValue) field.getparent().remove(field) def removeOrRenameField(self, filename, fieldname, newfieldname, newdbcolname, log): log.debug('Preparing to remove field(s) from domain schema file: ' + filename[filename.rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(filename, 'r', encoding='utf-8') as h: schema_xml = h.read() schema_tuple = self.common.removeDeclarationNode(xml_string=schema_xml) schema_root = etree.fromstring(schema_tuple[1]) if isinstance(fieldname, list): if newfieldname is None: newfieldname = [] for _ in fieldname: newfieldname.append('_') if newdbcolname is None: newdbcolname = [] for _ in fieldname: newdbcolname.append('_') for s1, s2, s3 in zip(fieldname, newfieldname, newdbcolname): self.renameOrRemoveFieldFromSchema(root=schema_root, fieldname=s1, newfieldname=s2, newdbcolname=s3, log=log) else: self.renameOrRemoveFieldFromSchema(root=schema_root, fieldname=fieldname, newfieldname=newfieldname, newdbcolname=newdbcolname, log=log) schema_bytea = etree.tostring(schema_root, pretty_print=True, encoding='UTF-8') schema_xml = "".join(map(chr, schema_bytea)) schema_xml = schema_tuple[0] + schema_xml with open(filename, 'w', encoding='utf-8') as h: h.write(schema_xml)
class DomainMetadataModHelper(): common = Common() server_URL = None server_pass = None session = None folderpath = None domain_id = None fieldname = None newfieldname = None newdbcolname = None def connectToServer(self, log): self.session = requests.post(self.server_URL + Common.LOGIN_PATH, data={Common.J_USERNAME:'******', Common.J_PASSWORD:self.server_pass}) if self.session.status_code == 401: log.error('Error logging into JasperReports Server: Unauthorized') quit() elif self.session.status_code == 404: log.error('Error logging into JasperReports Server: no server found at location ' + self.server_URL) quit() elif self.session.status_code == 302: log.error('Error logging into JasperReports Server: License expired') quit() elif self.session.status_code != 200: self.session.raise_for_status() quit() def downloadExport(self, log): log.debug('starting repository export...') descriptor = { 'parameters':['everything']} startResult = requests.post(self.server_URL + Common.EXPORT_START_PATH, json=descriptor, cookies=self.session.cookies) if startResult.status_code == 200: startResultText = startResult.text startResultTuple = self.common.removeDeclarationNode(startResultText) startResultXml = etree.fromstring(startResultTuple[1]) for node in startResultXml.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.ID): exportProcessID = node.text break if exportProcessID != None: log.debug('export process id: ' + exportProcessID) phase = Common.PHASE_INPROGRESS_STATUS while phase != Common.PHASE_READY_STATUS: log.debug('waiting 5 seconds...') time.sleep(Common.FIVE_SECONDS) pollingResult = requests.get(self.server_URL + Common.REPO_PATH_SEPARATOR + Common.REST_V2 + Common.REPO_PATH_SEPARATOR + Common.EXPORT + Common.REPO_PATH_SEPARATOR + exportProcessID + Common.REPO_PATH_SEPARATOR + Common.STATE, cookies=self.session.cookies) if pollingResult.status_code == 200: pollingResultText = pollingResult.text pollingResultTuple = self.common.removeDeclarationNode(pollingResultText) pollingResultXml = etree.fromstring(pollingResultTuple[1]) for node in pollingResultXml.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.PHASE): phase = node.text break else: pollingResult.raise_for_status() quit() if phase == Common.PHASE_FAILURE_STATUS: for node in pollingResultXml.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.MESSAGE): message = node.text break log.error('Error while exporting the repository: ' + message) quit() if phase == Common.PHASE_READY_STATUS: _, tmpfile = tempfile.mkstemp() tmpfilefile = tmpfile[tmpfile.rfind(Common.REPO_PATH_SEPARATOR) + 1:] # check to see if we're on Windows if tmpfilefile.find(Common.WINDOWS_PATH_SEPARATOR) >= 0: tmpfilefile = tmpfilefile[tmpfilefile.rfind(Common.WINDOWS_PATH_SEPARATOR) + 1:] log.debug('export finished, starting download to ' + tmpfile) downloadRestCall = (self.server_URL + Common.REPO_PATH_SEPARATOR + Common.REST_V2 + Common.REPO_PATH_SEPARATOR + Common.EXPORT + Common.REPO_PATH_SEPARATOR + exportProcessID + Common.REPO_PATH_SEPARATOR + tmpfilefile) log.debug('download rest API call: ' + downloadRestCall) savingResult = requests.get(downloadRestCall, cookies=self.session.cookies) if savingResult.status_code != 200: savingResult.raise_for_status() quit() else: with open(tmpfile, 'wb') as h: h.write(savingResult.content) tmpdir = tempfile.mkdtemp() zipRef = zipfile.ZipFile(tmpfile, 'r') log.debug('extracting zip archive ' + tmpfile + ' to ' + tmpdir) zipRef.extractall(tmpdir) zipRef.close() log.debug('finished extracting, removing zip archive') try: os.remove(tmpfile) except OSError as err: log.error('unable to remove zip archive: {0}'.format(err)) log.debug('setting folderpath: ' + tmpdir) self.folderpath = tmpdir def uploadImport(self, log): _, tmpfile = tempfile.mkstemp() log.debug('creating import archive at: ' + tmpfile) shutil.make_archive(tmpfile, 'zip', self.folderpath) log.debug('importing zip file into repository...') params = {'update':'true','skipUserUpdate':'true','includeAccessEvents':'false','includeAuditEvents':'false','includeMonitoringEvents':'false','includeServerSetting':'false'} if tmpfile.rfind('/') == -1: tmpfilename = tmpfile[tmpfile.rfind('\\')+1:] else: tmpfilename = tmpfile[tmpfile.rfind('/')+1:] headers = {'Content-Disposition':'form-data; name="File"; filename="' + tmpfilename + '"','Content-Type':'application/zip','X-Remote-Domain':'true'} with open(tmpfile + Common.ZIP_EXT, 'rb') as h: data = h.read() startResult = requests.post(self.server_URL + Common.IMPORT_START_PATH, params=params, headers=headers, data=data, cookies=self.session.cookies) if startResult.status_code == 200: startResultText = startResult.text startResultTuple = self.common.removeDeclarationNode(startResultText) startResultXml = etree.fromstring(startResultTuple[1]) for node in startResultXml.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.ID): importProcessID = node.text break if importProcessID != None: log.debug('import process id: ' + importProcessID) phase = Common.PHASE_INPROGRESS_STATUS while phase != Common.PHASE_READY_STATUS: log.debug('waiting 5 seconds...') time.sleep(Common.FIVE_SECONDS) pollingResult = requests.get(self.server_URL + Common.REPO_PATH_SEPARATOR + Common.REST_V2 + Common.REPO_PATH_SEPARATOR + Common.IMPORT + Common.REPO_PATH_SEPARATOR + importProcessID + Common.REPO_PATH_SEPARATOR + Common.STATE, cookies=self.session.cookies) if pollingResult.status_code == 200: pollingResultText = pollingResult.text pollingResultTuple = self.common.removeDeclarationNode(pollingResultText) pollingResultXml = etree.fromstring(pollingResultTuple[1]) for node in pollingResultXml.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.PHASE): phase = node.text break else: pollingResult.raise_for_status() quit() if phase == Common.PHASE_FAILURE_STATUS: for node in pollingResultXml.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.MESSAGE): message = node.text break log.error('Error while exporting the repository: ' + message) quit() if phase == Common.PHASE_READY_STATUS: log.debug('import complete, cleaning up temporary files...') shutil.rmtree(self.folderpath) os.remove(tmpfile) os.remove(tmpfile + Common.ZIP_EXT) def processInputs(self, inputs): log = self.common.configureLogging() log.debug('inputs provided: ' + str(inputs)) if len(inputs) < 5: raise ValueError(Common.NOT_ENOUGH_VALUES) if inputs[1].find('http') == -1: raise ValueError(Common.PROTOCOL_MISSING) quit() else: self.server_URL = inputs[1] self.server_pass = inputs[2] self.domain_id = inputs[3] self.fieldname = inputs[4] if self.fieldname.find(',') > 0: self.fieldname = self.fieldname.split(',') if len(inputs) >= 6: self.newfieldname = inputs[5] if self.newfieldname.find(',') > 0: self.newfieldname = self.newfieldname.split(',') if not isinstance(self.fieldname, list): raise ValueError('Both the old and new field name parameters must be comma-separated lists') if len(self.newfieldname) != len(self.fieldname): raise ValueError('both the old and new field name parameter lists must be the same length') if len(inputs) >= 7: self.newdbcolname = inputs[6] if self.newdbcolname.find(',') > 0: self.newdbcolname = self.newdbcolname.split(',') if not isinstance(self.fieldname, list) or not isinstance(self.newfieldname, list): raise ValueError('Old and new field name and database column name parameters must be comma-separated lists') if len(self.newdbcolname) != len(self.fieldname) or len(self.newdbcolname) != len(self.newfieldname): raise ValueError('Old and new field name and database column name parameter lists must be the same length') else: # use the new field name items as the database column items self.newdbcolname = self.newfieldname return log
class FileFinder(): common = Common() domainAction = DomainAction() adhocAction = AdhocAction() reportAction = ReportAction() domain_id = None resources_folder = None adhoc_topic_files_list = [] adhoc_view_files_list = [] report_list = [] def findDomainSchema(self, root, log): for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' domainSchemaFile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found domain schema file: ' + domainSchemaFile) return domainSchemaFile def findDomainSchemaFile(self, metadata_filename, log): with open(metadata_filename) as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( xml_string=metadata_xml) metadata_root = etree.fromstring(metadata_tuple[1]) return self.findDomainSchema(root=metadata_root, log=log) def findAdhocTopic(self, root, adhoc_topic_id, log): jrxmlfile = None statefile = None adhoc_topic_id_node = root[Common.ID_NODE_INDEX] if adhoc_topic_id_node.text.find( adhoc_topic_id) >= 0 and self.checkDatasource(root=root): for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'mainReport' + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' jrxmlfile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found JRXML file: ' + jrxmlfile) for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'resource' + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' statefile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found state file: ' + statefile) if statefile is not None and jrxmlfile is not None: self.adhoc_topic_files_list.append([statefile, jrxmlfile]) def findAdhocTopicFiles(self, metadata_filename, adhoc_topic_id, log): with open(metadata_filename) as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( xml_string=metadata_xml) metadata_root = etree.fromstring(metadata_tuple[1]) self.findAdhocTopic(root=metadata_root, adhoc_topic_id=adhoc_topic_id, log=log) def findAdhocView(self, root, adhoc_view_id, log): jrxmlfile = None statefile = None reportJrxmlfile = None reportStatefile = None adhoc_view_id_node = root[Common.ID_NODE_INDEX] if adhoc_view_id_node.text.find( adhoc_view_id) >= 0 and self.checkDatasource(root): for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.ADHOC_VIEW_TAG + Common.REPO_PATH_SEPARATOR + Common.RESOURCE_TAG + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): secondchild = child[Common.ID_NODE_INDEX] folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' if secondchild.text.find(Common.STATE_XML) >= 0: statefile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found state file: ' + statefile) elif secondchild.text.find(Common.TOPIC_JRXML) >= 0: jrxmlfile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found jrxml file: ' + jrxmlfile) # check to see if there's a nested report used for a dashboard for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.ADHOC_VIEW_TAG + Common.REPO_PATH_SEPARATOR + 'reports' + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + Common.RESOURCE_TAG + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): secondchild = child[Common.ID_NODE_INDEX] folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' if secondchild.text.find(Common.STATE_XML) >= 0: reportStatefile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found dashboard report state file: ' + reportStatefile) elif secondchild.text.find(Common.MAIN_REPORT_JRXML) >= 0: reportJrxmlfile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found dashboard report jrxml file: ' + jrxmlfile) if statefile is not None and jrxmlfile is not None: self.adhoc_view_files_list.append([statefile, jrxmlfile]) if reportStatefile is not None and reportJrxmlfile is not None: self.report_list.append([reportStatefile, reportJrxmlfile]) return True else: return False def findAdhocViewFiles(self, metadata_filename, adhoc_view_id, log): with open(metadata_filename) as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( xml_string=metadata_xml) metadata_root = etree.fromstring(metadata_tuple[1]) return self.findAdhocView(root=metadata_root, adhoc_view_id=adhoc_view_id, log=log) def findReport(self, root, report_id, log): jrxmlfile = None statefile = None report_id_node = root[Common.ID_NODE_INDEX] if report_id_node.text.find(report_id) >= 0 and self.checkDatasource( root): for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'mainReport' + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' jrxmlfile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found jrxml file: ' + jrxmlfile) for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'resource' + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE): if child.get(Common.DATA_FILE) == Common.STATE_DATAFILE: folderPath = child[Common.STATE_FILE_NODE_INDEX].text if folderPath is None: folderPath = '' statefile = self.resources_folder + folderPath + Common.REPO_PATH_SEPARATOR + child.get( Common.DATA_FILE) log.debug('found state file: ' + statefile) break if statefile is not None and jrxmlfile is not None: self.report_list.append([statefile, jrxmlfile]) return False elif jrxmlfile is not None: # static report with domain data source self.report_list.append([None, jrxmlfile]) return True else: return False def findReportFiles(self, metadata_filename, report_id, log): with open(metadata_filename) as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( xml_string=metadata_xml) metadata_root = etree.fromstring(metadata_tuple[1]) return self.findReport(root=metadata_root, report_id=report_id, log=log) def checkRootNodeTag(self, root_tag): if root_tag.find(Common.DOMAIN_METADATA_TAG) >= 0 or root_tag.find( Common.ADHOC_TOPIC_TAG) >= 0 or root_tag.find( Common.ADHOC_VIEW_TAG) >= 0 or root_tag.find( Common.REPORT_TAG) >= 0: return True else: return False def checkDatasource(self, root): if root.tag.find(self.common.DOMAIN_METADATA_TAG) >= 0: if root[Common.ID_NODE_INDEX].text.find(self.domain_id) >= 0: return True else: return False else: # check parent for child in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.DATA_SOURCE + Common.REPO_PATH_SEPARATOR + 'uri'): with open(self.resources_folder + child.text + '.xml') as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( metadata_xml) metadata_root = etree.fromstring(metadata_tuple[1]) return self.checkDatasource(metadata_root) def walk(self, dmmHelper, log): self.walk2(folderpath=dmmHelper.folderpath, domain_id=dmmHelper.domain_id, fieldname=dmmHelper.fieldname, newfieldname=dmmHelper.newfieldname, newdbcolname=dmmHelper.newdbcolname, log=log) def walk2(self, folderpath, domain_id, fieldname, newfieldname, newdbcolname, log): self.domain_id = domain_id for root, _, files in os.walk(folderpath, topdown=True): for filename in files: if filename.find(Common.PROPERTIES_EXT) == -1: xml_file = None filepath = os.path.join(root, filename) log.info('Inspecting file: ' + filepath) if self.resources_folder is None and str(root).find( Common.RESOURCES_FOLDER) > -1: self.resources_folder = str( root)[:str(root).find(Common.RESOURCES_FOLDER) + len(Common.RESOURCES_FOLDER)] with open(filepath) as h: try: xml_file = h.read() except UnicodeDecodeError: log.debug('Ignoring non-text file: ' + filepath) if xml_file != None: xml_tuple = self.common.removeDeclarationNode( xml_string=xml_file) root_node = None try: root_node = etree.fromstring(xml_tuple[1]) except etree.XMLSyntaxError: log.debug('Ignoring non-XML file: ' + filepath) if root_node != None: root_tag = root_node.tag if self.checkRootNodeTag(root_tag): id_value = root_node[Common.ID_NODE_INDEX] id_name = id_value.text if root_tag.find( Common.DOMAIN_METADATA_TAG ) >= 0 and id_name == domain_id: log.info('Processing domain: ' + id_name) domain_schemafile = self.findDomainSchemaFile( metadata_filename=filepath, log=log) if domain_schemafile is not None: self.domainAction.removeOrRenameField( filename=domain_schemafile, fieldname=fieldname, newfieldname=newfieldname, newdbcolname=newdbcolname, log=log) elif root_tag.find( Common.ADHOC_TOPIC_TAG) >= 0: log.info('Processing Ad Hoc Topic: ' + id_name) self.findAdhocTopicFiles( metadata_filename=filepath, adhoc_topic_id=id_name, log=log) elif root_tag.find(Common.ADHOC_VIEW_TAG) >= 0: log.info('Processing Ad Hoc View: ' + id_name) if self.findAdhocViewFiles( metadata_filename=filepath, adhoc_view_id=id_name, log=log): self.adhocAction.removeRenameInputControlInMetadataFile( metadata_filename=filepath, fieldname=fieldname, newfieldname=newfieldname, log=log) elif root_tag.find(Common.REPORT_TAG) >= 0: log.info('Processing Report: ' + id_name) if self.findReportFiles( metadata_filename=filepath, report_id=id_name, log=log): # check metadata for input control(s) if report is static self.reportAction.removeRenameInputControlInMetadataFile( metadata_filename=filepath, fieldname=fieldname, log=log) self.processFiles(fieldname, newfieldname, log) def processFiles(self, fieldname, newfieldname, log): for files in self.adhoc_topic_files_list: self.adhocAction.removeRenameField(files[0], files[1], fieldname, newfieldname, log) for files in self.adhoc_view_files_list: self.adhocAction.removeRenameField(files[0], files[1], fieldname, newfieldname, log) for files in self.report_list: self.reportAction.removeRenameField(files[0], files[1], fieldname, newfieldname, log)
def setUp(self): self.common = Common() self.log = self.common.configureLogging() self.test_datasource_name = 'test_domain'
class CommonTest(unittest.TestCase): def setUp(self): self.common = Common() self.log = self.common.configureLogging() self.test_datasource_name = 'test_domain' def tearDown(self): pass def testRemoveDeclarationNode(self): some_tag_xml = '<someTag/>' xml_declaration = '<?xml version="1.0" encoding="UTF-8"?>' report_xml = xml_declaration + '\n' + some_tag_xml report_tuple = self.common.removeDeclarationNode(report_xml) self.assertEqual(xml_declaration + '\n', report_tuple[0], 'xml declaration does not match') self.assertEqual(some_tag_xml, report_tuple[1], 'xml body does not match') def testRemoveDeclarationNodeNoDeclarationNode(self): some_tag_xml = '<someTag/>' report_xml = some_tag_xml report_tuple = self.common.removeDeclarationNode(report_xml) self.assertEqual('', report_tuple[0], 'xml declaration should be empty') self.assertEqual(some_tag_xml, report_tuple[1], 'xml body does not match') def testFixVisibleLevels(self): fieldname = 'name1' newfieldname = 'name2' mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1_text = PropertyMock(return_value=fieldname) type(mock_node1).text = mock_node1_text mock_root.xpath = MagicMock(side_effect=[[mock_node1]]) self.common.fixVisibleLevels(root=mock_root, fieldname=fieldname, newfieldname=newfieldname, log=self.log) mock_node1_text.assert_called_with(newfieldname) def testFixVisibleLevelsDoesNotMatch(self): fieldname = 'name1' newfieldname = 'name2' mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1_text = PropertyMock(return_value='something else') type(mock_node1).text = mock_node1_text mock_root.xpath = MagicMock(side_effect=[[mock_node1]]) self.common.fixVisibleLevels(root=mock_root, fieldname=fieldname, newfieldname=newfieldname, log=self.log) mock_node1_text.assert_called_once_with() def testFixVisibleLevelsIsRemove(self): fieldname = 'name1' mock_root = MagicMock(name='mock_root') self.common.fixVisibleLevels(root=mock_root, fieldname=fieldname, newfieldname=None, log=self.log) mock_root.assert_not_called()
class ReportAction(): common = Common() def removeRenameParameter(self, root, fieldname, newfieldname, log): for param in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.PARAMETER, namespaces=Common.JRXML_NAMESPACE): paramName = param.get(Common.NAME) if paramName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming parameter ' + paramName + ' to ' + paramName.replace(fieldname, newfieldname)) param.attrib[Common.NAME] = paramName.replace( fieldname, newfieldname) for child in param: if child.tag.find('parameterDescription') >= 0: childtext = child.text if childtext.find(fieldname) >= 0: log.debug( 'changing parameter description to: ' + childtext.replace(fieldname, newfieldname)) child.text = etree.CDATA( childtext.replace(fieldname, newfieldname)) else: log.debug('removing parameter: ' + paramName) param.getparent().remove(param) def removeRenameFieldInFieldList(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.FIELD, namespaces=Common.JRXML_NAMESPACE): fieldName = field.get(Common.NAME) if fieldName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming field ' + fieldName + ' to ' + fieldName.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = fieldName.replace( fieldname, newfieldname) # rename associated level property for child in field: childvalue = child.get(Common.VALUE) if childvalue is not None and childvalue.find( fieldname) >= 0: log.debug( 'renaming field level property to ' + childvalue.replace(fieldname, newfieldname)) child.attrib[Common.VALUE] = childvalue.replace( fieldname, newfieldname) elif child.tag.find('fieldDescription') >= 0: childtext = child.text if childtext is not None and childtext.find( fieldname) >= 0: log.debug( 'changing field description to ' + childtext.replace(fieldname, newfieldname)) child.text = etree.CDATA( childtext.replace(fieldname, newfieldname)) else: log.debug('removing field: ' + fieldName) field.getparent().remove(field) def removeRenameQueryFieldInReportQuery(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.QUERY_FIELD): fieldID = field.get(Common.ID) if fieldID.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming query field ' + fieldID + ' to ' + fieldID.replace(fieldname, newfieldname)) field.attrib[Common.ID] = fieldID.replace( fieldname, newfieldname) else: log.debug('removing field from query: ' + fieldID) field.getparent().remove(field) for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'queryFilterString'): filterString = field.text if filterString.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('changing query filter string to ' + filterString.replace(fieldname, newfieldname)) field.text = filterString.replace(fieldname, newfieldname) else: # Break up the filter into parts separated by AND and OR filterList = re.split('AND |OR ', filterString) for clause in filterList: if clause.find(fieldname) >= 0: filterString = filterString.replace(clause, '') # Fix this kludgy mess filterString = filterString.replace( 'AND AND', 'AND') filterString = filterString.replace('AND OR', 'OR') filterString = filterString.replace( 'OR AND', 'AND') filterString = filterString.replace('OR OR', 'OR') filterString = filterString.strip() if filterString.startswith( 'AND') or filterString.endswith('AND'): filterString = filterString.replace( 'AND', '').strip() elif filterString.startswith( 'OR') or filterString.endswith('OR'): filterString = filterString.replace( 'OR', '').strip() log.debug('modified query filter string: ' + filterString) field.text = filterString if filterString is None or filterString == '': field.getparent().remove(field) def reinsertQueryIntoReport(self, root, query_str): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.QUERY_STRING, namespaces=Common.JRXML_NAMESPACE): field.text = etree.CDATA(query_str) return query_str def removeRenameDetailFieldInTable(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.TEXTFIELD_EXPR_TAG, namespaces=Common.JRXML_NAMESPACE): fieldText = field.text if fieldText.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming detail field ' + fieldText + ' to ' + fieldText.replace(fieldname, newfieldname)) field.text = etree.CDATA( fieldText.replace(fieldname, newfieldname)) # Fix the patternExpression node text if there is one sibling = field.getnext() if sibling is not None and sibling.tag.find( 'patternExpression') >= 0: siblingText = sibling.text if siblingText is not None and siblingText.find( fieldname) >= 0: log.debug( 'renaming field name in pattern expression to ' + siblingText.replace(fieldname, newfieldname)) sibling.text = etree.CDATA( siblingText.replace(fieldname, newfieldname)) else: log.debug('removing detail field: ' + fieldText) ggparentfield = field.getparent().getparent().getparent() # subtract field width from parent field_width_str = ggparentfield.get(Common.WIDTH) if field_width_str != None: # This report was created from an Ad Hoc view field_width = int(field_width_str) gggparentfield = ggparentfield.getparent() gggparentfield.attrib[Common.WIDTH] = str( int(gggparentfield.get(Common.WIDTH)) - field_width) gggparentfield.remove(ggparentfield) # Fix the width in the reportElement in the header for reportGroupField in root.xpath( Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:reportElement', namespaces=Common.JRXML_NAMESPACE): reportGroupGGParent = reportGroupField.getparent( ).getparent().getparent() if reportGroupGGParent.tag.find( 'groupHeader') >= 0: reportGroupField.attrib[ Common.WIDTH] = gggparentfield.get( Common.WIDTH) else: # This is a static report created using Jaspersoft Studio parent = field.getparent() parent.getparent().remove(parent) def removeRenameFieldInGroup(self, root, fieldname, newfieldname, log): for group in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.GROUP, namespaces=Common.JRXML_NAMESPACE): fieldName = group.get(Common.NAME) if fieldName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming group ' + fieldName + ' to ' + fieldName.replace(fieldname, newfieldname)) group.attrib[Common.NAME] = fieldName.replace( fieldname, newfieldname) # change groupExpression groupExpression = group[0].text if groupExpression.find(fieldname) >= 0: log.debug( 'changing groupExpression ' + groupExpression + ' to ' + groupExpression.replace(fieldname, newfieldname)) group[0].text = etree.CDATA( groupExpression.replace(fieldname, newfieldname)) else: log.debug('removing group: ' + fieldName) group.getparent().remove(group) for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.CGROUPHEADER, namespaces=Common.JRXML_COMPONENTS_NAMESPACE): fieldGroupName = field.get(Common.GROUPNAME) if fieldGroupName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming column group ' + fieldGroupName + ' to ' + fieldGroupName.replace(fieldname, newfieldname)) field.attrib[Common.GROUPNAME] = fieldGroupName.replace( fieldname, newfieldname) else: log.debug('removing column group: ' + fieldGroupName) field.getparent().remove(field) def insertDummyRowGroup(self, root, log): # Inserting dummy row group for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:crosstabDataset', namespaces=Common.JRXML_NAMESPACE): parent = field.getparent() parser = etree.XMLParser(strip_cdata=False) dummy_row_group_xml = etree.fromstring(Common.DUMMY_ROW_GROUP, parser) log.debug('inserting dummy row group at position: ' + str(parent.index(field) + 1)) parent.insert(parent.index(field) + 1, dummy_row_group_xml) # Removing crosstab header node for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:crosstabHeader', namespaces=Common.JRXML_NAMESPACE): log.debug('removing crosstabHeader node') field.getparent().remove(field) def removeRenameRowGroupInCrosstab(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.ROWGROUP, namespaces=Common.JRXML_NAMESPACE): fieldName = field.get(Common.NAME) if fieldName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming row group ' + fieldName + ' to ' + fieldName.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = fieldName.replace( fieldname, newfieldname) self.fixGroupChildNodes(field=field, fieldname=fieldname, newfieldname=newfieldname, log=log) else: log.debug('removing row group: ' + fieldName) field.getparent().remove(field) # fix row group count for param in root.xpath( Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:crosstabParameter[@name="CrosstabRowGroupsCount"]', namespaces=Common.JRXML_NAMESPACE): rowGroupText = param[Common.STATE_FILE_NODE_INDEX].text rowGroupCount = int( rowGroupText[rowGroupText.find('(') + 1:rowGroupText.find(')')]) - 1 if rowGroupCount == 0: self.insertDummyRowGroup(root=root, log=log) else: param[Common. STATE_FILE_NODE_INDEX].text = etree.CDATA( 'new Integer(' + str(rowGroupCount) + ')') def removeRenameColumnGroupInCrosstab(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.COLUMNGROUP, namespaces=Common.JRXML_NAMESPACE): fieldName = field.get(Common.NAME) if fieldName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming column group ' + fieldName + ' to ' + fieldName.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = fieldName.replace( fieldname, newfieldname) self.fixGroupChildNodes(field=field, fieldname=fieldname, newfieldname=newfieldname, log=log) else: log.debug('removing column group: ' + fieldName) field.getparent().remove(field) # fix column group count for param in root.xpath( Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:crosstabParameter[@name="CrosstabColumnGroupsCount"]', namespaces=Common.JRXML_NAMESPACE): rowGroupText = param[Common.STATE_FILE_NODE_INDEX].text rowGroupCount = int( rowGroupText[rowGroupText.find('(') + 1:rowGroupText.find(')')]) - 1 param[Common.STATE_FILE_NODE_INDEX].text = etree.CDATA( 'new Integer(' + str(rowGroupCount) + ')') def fixGroupChildNodes(self, field, fieldname, newfieldname, log): # Fix bucket expression for bucket in field.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:bucketExpression', namespaces=Common.JRXML_NAMESPACE): bucketText = bucket.text if bucketText.find(fieldname) >= 0: log.debug('changing bucketExpression to: ' + bucketText.replace(fieldname, newfieldname)) bucket.text = etree.CDATA( bucketText.replace(fieldname, newfieldname)) # fix hyperlinkTooltipExpression for tooltipExpr in field.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:hyperlinkTooltipExpression', namespaces=Common.JRXML_NAMESPACE): textFieldExprText = tooltipExpr.text if textFieldExprText.find(fieldname) >= 0: log.debug('changing hyperlinkTooltipExpression to: ' + textFieldExprText.replace(fieldname, newfieldname)) tooltipExpr.text = etree.CDATA( textFieldExprText.replace(fieldname, newfieldname)) # fix reportElement style for reportElementExpr in field.xpath( Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:reportElement', namespaces=Common.JRXML_NAMESPACE): reportElementExprStyle = reportElementExpr.get(Common.STYLE_TAG) if reportElementExprStyle.find(fieldname) >= 0: log.debug( 'changing reportElement style to: ' + reportElementExprStyle.replace(fieldname, newfieldname)) reportElementExpr.attrib[ Common.STYLE_TAG] = reportElementExprStyle.replace( fieldname, newfieldname) def removeRenameFieldInMeasureExpression(self, exprText, fieldname, newfieldname, log): if exprText.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming field in measure expression to' + exprText.replace(fieldname, newfieldname)) exprText = exprText.replace(fieldname, newfieldname) else: log.debug('removing field ' + fieldname + 'from measureExpression: ' + exprText) exprText = exprText.replace( '$F{' + fieldname + '__DISCRIMINATOR}', '') if exprText.find('|| ||') >= 0: exprText = exprText.replace('|| ||', '||') elif exprText.endswith(' || '): exprText = self.rreplace(exprText, ' || ', '') return exprText def removeRenameFieldInMeasureExpressionWrapper(self, root, fieldname, newfieldname, log): for expr in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:measureExpression', namespaces=Common.JRXML_NAMESPACE): expr.text = etree.CDATA( self.removeRenameFieldInMeasureExpression( exprText=expr.text, fieldname=fieldname, newfieldname=newfieldname, log=log)) def fixConditionalStyleExpression(self, root, fieldname, newfieldname, log): for expr in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:conditionExpression', namespaces=Common.JRXML_NAMESPACE): exprText = expr.text if exprText.find(fieldname) >= 0: grandparent = expr.getparent().getparent() if grandparent.tag.find(Common.STYLE_TAG) >= 0: grandparentName = grandparent.get(Common.NAME) if grandparentName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug( 'changing conditional style expression to: ' + exprText.replace(fieldname, newfieldname)) expr.text = etree.CDATA( exprText.replace(fieldname, newfieldname)) log.debug('changing style name to: ' + grandparentName.replace( fieldname, newfieldname)) grandparent.attrib[ Common.NAME] = grandparentName.replace( fieldname, newfieldname) else: log.debug('removing style: ' + grandparentName) grandparent.getparent().remove(grandparent) # check parent style for style in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + 'n:' + Common.STYLE_TAG, namespaces=Common.JRXML_NAMESPACE): parentStyle = style.get(Common.STYLE_TAG) if parentStyle is not None and parentStyle.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('changing parent style name to: ' + parentStyle.replace(fieldname, newfieldname)) style.attrib[Common.STYLE_TAG] = parentStyle.replace( fieldname, newfieldname) else: log.debug('removing style ' + style.get(Common.NAME) + ' with parent style: ' + parentStyle) style.getparent().remove(style) def removeRenameFieldInJRXML(self, root, fieldname, newfieldname, log): self.removeRenameParameter(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameFieldInFieldList(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameDetailFieldInTable(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameFieldInGroup(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameRowGroupInCrosstab(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameColumnGroupInCrosstab(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameFieldInMeasureExpressionWrapper( root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) self.fixConditionalStyleExpression(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) def removeRenameFieldInJRXMLFile(self, jrxml_filename, fieldname, newfieldname, log): if jrxml_filename.find(Common.PROPERTIES_EXT) == -1: log.debug('Preparing to remove field(s) from JRXML file: ' + jrxml_filename[jrxml_filename. rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(jrxml_filename, 'r', encoding='utf-8') as h: report_xml = h.read() report_tuple = self.common.removeDeclarationNode( xml_string=report_xml) report_xml = report_tuple[1] parser = etree.XMLParser(strip_cdata=False) # remove queryString node that contains an extra XML declaration to avoid syntax error try: begin_index = report_xml.index('<' + Common.QUERY + '>') except ValueError: log.debug( 'Report does not contain a domain query. Skipping...') begin_index = -1 if begin_index > 0: end_index = report_xml.find(']]>', begin_index) report_xml_outer = report_xml[0:begin_index] + report_xml[ end_index:len(report_xml)] report_xml_inner = report_xml[begin_index:end_index] report_root = etree.fromstring(report_xml_outer, parser) self.removeRenameFieldInJRXML(root=report_root, fieldname=fieldname, newfieldname=newfieldname, log=log) query_root = etree.fromstring(report_xml_inner) self.removeRenameQueryFieldInReportQuery( root=query_root, fieldname=fieldname, newfieldname=newfieldname, log=log) # re-insert domain query back into topic query_bytea = etree.tostring(query_root, pretty_print=True, encoding='UTF-8') query_str = "".join(map(chr, query_bytea)) self.reinsertQueryIntoReport(root=report_root, query_str=query_str) else: report_root = etree.fromstring(report_xml, parser) self.removeRenameFieldInJRXML(root=report_root, fieldname=fieldname, newfieldname=newfieldname, log=log) report_bytea = etree.tostring(report_root, pretty_print=True, encoding='UTF-8') report_xml = "".join(map(chr, report_bytea)) # re-insert original XML declaration report_xml = report_tuple[0] + report_xml with open(jrxml_filename, 'w', encoding='utf-8') as h: h.write(report_xml) def removeRenameFieldInState(self, root, fieldname, newfieldname, log): # if the field is a measure for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.MEASURE): fieldFieldName = field.get(Common.FIELD_NAME) if fieldFieldName != None and fieldFieldName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming measure fieldName attribute ' + fieldFieldName + ' to ' + fieldFieldName.replace(fieldname, newfieldname)) field.attrib[Common.FIELD_NAME] = fieldFieldName.replace( fieldname, newfieldname) # check and rename the "name" attribute if necessary fieldName = field.get(Common.NAME) if fieldName is not None and fieldName.find( fieldname) >= 0: log.debug('renaming measure name attribute ' + fieldName + ' to ' + fieldName.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = fieldName.replace( fieldname, newfieldname) # check and rename the labelOverride property if necessary labelOverride = field.get(Common.LABEL_OVERRIDE) if labelOverride is not None and labelOverride.find( fieldname) >= 0: log.debug( 'changing labelOverride property from ' + labelOverride + ' to ' + labelOverride.replace(fieldname, newfieldname)) field.attrib[ Common.LABEL_OVERRIDE] = labelOverride.replace( fieldname, newfieldname) else: log.debug('removing measure: ' + fieldFieldName) field.getparent().remove(field) # if the field is a dimension for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.QUERY_DIMENSION): fieldFieldName = field.get(Common.FIELD_NAME) if fieldFieldName != None and fieldFieldName.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming dimension fieldName attribute ' + fieldFieldName + ' to ' + fieldFieldName.replace(fieldname, newfieldname)) field.attrib[Common.FIELD_NAME] = fieldFieldName.replace( fieldname, newfieldname) # check and rename the "name" attribute if necessary fieldName = field.get(Common.NAME) if fieldName is not None and fieldName.find( fieldname) >= 0: log.debug('renaming measure name attribute ' + fieldName + ' to ' + fieldName.replace(fieldname, newfieldname)) field.attrib[Common.NAME] = fieldName.replace( fieldname, newfieldname) else: log.debug('removing dimension: ' + fieldFieldName) field.getparent().remove(field) # if the field is a subfilter for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.EXPRESSION_STRING): fieldText = field.text if fieldText.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming subfilter ' + fieldText + ' to ' + fieldText.replace(fieldname, newfieldname)) field.text = fieldText.replace(fieldname, newfieldname) # check and fix parameterizedExpressionString if necessary sibling = field.getnext() if sibling is not None and sibling.tag == 'parameterizedExpressionString': siblingText = sibling.text if siblingText is not None and siblingText.find( fieldname) >= 0: log.debug( 'renaming column(s) in parameterizedExpressionString to ' + siblingText.replace(fieldname, newfieldname)) sibling.text = siblingText.replace( fieldname, newfieldname) else: parent = field.getparent() log.debug('removing subfilter: ' + parent.get(Common.ID)) parent.getparent().remove(parent) # fix visible levels self.common.fixVisibleLevels(root=root, fieldname=fieldname, newfieldname=newfieldname, log=log) def removeRenameFieldInStateFile(self, state_filename, fieldname, newfieldname, log): if state_filename is not None and state_filename.find( Common.PROPERTIES_EXT) == -1: log.debug('Preparing to remove field(s) from state file: ' + state_filename[state_filename. rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(state_filename, 'r', encoding='utf-8') as h: try: state_xml = h.read() except UnicodeDecodeError: log.debug('Ignoring non-text file: ' + state_filename) return state_tuple = self.common.removeDeclarationNode( xml_string=state_xml) state_root = etree.fromstring(state_tuple[1]) self.removeRenameFieldInState(root=state_root, fieldname=fieldname, newfieldname=newfieldname, log=log) state_bytea = etree.tostring(state_root, pretty_print=True, encoding='UTF-8') state_xml = "".join(map(chr, state_bytea)) # re-insert original XML declaration state_xml = state_tuple[0] + state_xml with open(state_filename, 'w', encoding='utf-8') as h: h.write(state_xml) def removeRenameField(self, state_filename, jrxml_filename, fieldname, newfieldname, log): if isinstance(fieldname, list): if newfieldname is None: newfieldname = [] for _ in fieldname: newfieldname.append('_') for s1, s2 in zip(fieldname, newfieldname): self.removeRenameFieldInStateFile( state_filename=state_filename, fieldname=s1, newfieldname=s2, log=log) self.removeRenameFieldInJRXMLFile( jrxml_filename=jrxml_filename, fieldname=s1, newfieldname=s2, log=log) else: self.removeRenameFieldInStateFile(state_filename=state_filename, fieldname=fieldname, newfieldname=newfieldname, log=log) self.removeRenameFieldInJRXMLFile(jrxml_filename=jrxml_filename, fieldname=fieldname, newfieldname=newfieldname, log=log) def removeRenameInputControlInMetadata(self, root, fieldname, newfieldname, log): for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + 'queryValueColumn'): fieldText = field.text if fieldText.find(fieldname) >= 0: if newfieldname is not None and newfieldname != '_': log.debug('renaming input control ' + fieldText + ' to ' + fieldText.replace(fieldname, newfieldname)) field.text = fieldText.replace(fieldname, newfieldname) # change the queryVisibleColumn field value sibling = field.getprevious() if sibling is not None and sibling.tag.find( 'queryVisibleColumn') >= 0: siblingText = sibling.text if siblingText.find(fieldname) >= 0: log.debug( 'renaming queryVisibleColumn value ' + siblingText + ' to ' + siblingText.replace(fieldname, newfieldname)) sibling.text = siblingText.replace( fieldname, newfieldname) # replace any occurences in the query string for query in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + 'queryString'): queryText = query.text if queryText.find(fieldname) >= 0: log.debug('replacing all occurences of ' + fieldname + ' in query string with ' + newfieldname) query.text = queryText.replace( fieldname, newfieldname) # change folder and name properties for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + 'folder'): fieldText = field.text if fieldText.find(fieldname) >= 0: log.debug( 'changing folder property from ' + fieldText + ' to ' + fieldText.replace(fieldname, newfieldname)) field.text = fieldText.replace( fieldname, newfieldname) sibling = field.getnext() if sibling is not None and sibling.tag.find( Common.NAME) >= 0: siblingText = sibling.text if siblingText.find(fieldname) >= 0: log.debug('changing name property from ' + siblingText + ' to ' + siblingText.replace( fieldname, newfieldname)) sibling.text = siblingText.replace( fieldname, newfieldname) # update the label if necessary labelProp = sibling.getnext().getnext() if labelProp is not None and labelProp.tag.find( Common.LABEL) >= 0: labelText = labelProp.text if labelText.find(fieldname) >= 0: log.debug( 'changing label property from ' + labelText + ' to ' + labelText.replace( fieldname, newfieldname)) labelProp.text = labelText.replace( fieldname, newfieldname) # change any name properties we may have missed for field in root.xpath(Common.REPO_PATH_SEPARATOR + Common.REPO_PATH_SEPARATOR + Common.LOCAL_RESOURCE + Common.REPO_PATH_SEPARATOR + Common.NAME): fieldText = field.text if fieldText.find(fieldname) >= 0: log.debug( 'changing name property from ' + fieldText + ' to ' + fieldText.replace(fieldname, newfieldname)) field.text = fieldText.replace( fieldname, newfieldname) else: parent = field.getparent() log.debug('removing input control: ' + parent[Common.ID_NODE_INDEX].text) parent.getparent().remove(parent) def removeRenameInputControlInMetadataFile(self, metadata_filename, fieldname, newfieldname, log): log.debug('Checking metadata file for input controls to remove: ' + metadata_filename[metadata_filename. rfind(Common.REPO_PATH_SEPARATOR) + 1:]) with open(metadata_filename) as h: metadata_xml = h.read() metadata_tuple = self.common.removeDeclarationNode( xml_string=metadata_xml) metadata_root = etree.fromstring(metadata_tuple[1]) self.removeRenameInputControlInMetadata(root=metadata_root, fieldname=fieldname, newfieldname=newfieldname, log=log) metadata_bytea = etree.tostring(metadata_root, pretty_print=True, encoding='UTF-8') metadata_xml = "".join(map(chr, metadata_bytea)) # re-insert original XML declaration metadata_xml = metadata_tuple[0] + metadata_xml if metadata_xml.endswith('\n'): metadata_xml = metadata_xml[0:len(metadata_xml) - 1] with open(metadata_filename, 'w') as h: h.write(metadata_xml) def rreplace(self, s, old, new): li = s.rsplit(old, 1) return new.join(li)
class DomainActionTest(unittest.TestCase): common = Common() DOMAIN_SCHEMA = """<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0"> <dataSources> </dataSources> <items> <item description="name1" descriptionId="" id="name1" label="name1" labelId="" resourceId="JoinTree_1.table1.name1" /> <item description="name2" descriptionId="" id="name2" label="name2" labelId="Something Else" resourceId="JoinTree_1.table2.name2" /> <item description="name3" descriptionId="" id="name3" label="name3" labelId="" resourceId="JoinTree_1.table3.name3" /> </items> <resources> <jdbcTable id="table1" datasourceId="SomeDataSourceJNDI" tableName="schema1.table1"> <fieldList> <field id="table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="name1" fieldDBName="name1" type="java.lang.String" /> </fieldList> </jdbcTable> <jdbcTable id="table2" datasourceId="SomeDataSourceJNDI" tableName="schema1.table2"> <fieldList> <field id="table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="name2" fieldDBName="name2" type="java.math.BigDecimal" /> </fieldList> </jdbcTable> <jdbcTable id="table3" datasourceId="SomeDataSourceJNDI" tableName="schema1.table3"> <fieldList> <field id="table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> </jdbcTable> <jdbcTable id="JoinTree_1" datasourceId="SomeDataSourceJNDI" tableName="schema1.fact_table1"> <fieldList> <field id="public_table1.table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="public_table1.name1" fieldDBName="name1" type="java.lang.String" /> <field id="public_table2.table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="public_table2.name2" fieldDBName="name2" type="java.math.BigDecimal" /> <field id="public_table3.table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="public_table3.name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> <joinInfo alias="public_fact_table1" referenceId="public_fact_table1" /> <joinedDataSetList> <joinedDataSetRef> <joinString>join public_table1 public_table1 on (public_fact_table1.table1_id == public_table1.table1_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table2 public_table2 on (public_fact_table1.table2_id == public_table2.table2_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table3 public_table3 on (public_fact_table1.table3_id == public_table3.table3_id)</joinString> </joinedDataSetRef> </joinedDataSetList> </jdbcTable> </resources> </schema> """ DOMAIN_SCHEMA_WITHOUT_NAME1 = """<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0"> <dataSources> </dataSources> <items> <item description="name2" descriptionId="" id="name2" label="name2" labelId="Something Else" resourceId="JoinTree_1.table2.name2" /> <item description="name3" descriptionId="" id="name3" label="name3" labelId="" resourceId="JoinTree_1.table3.name3" /> </items> <resources> <jdbcTable id="table1" datasourceId="SomeDataSourceJNDI" tableName="schema1.table1"> <fieldList> <field id="table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> </fieldList> </jdbcTable> <jdbcTable id="table2" datasourceId="SomeDataSourceJNDI" tableName="schema1.table2"> <fieldList> <field id="table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="name2" fieldDBName="name2" type="java.math.BigDecimal" /> </fieldList> </jdbcTable> <jdbcTable id="table3" datasourceId="SomeDataSourceJNDI" tableName="schema1.table3"> <fieldList> <field id="table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> </jdbcTable> <jdbcTable id="JoinTree_1" datasourceId="SomeDataSourceJNDI" tableName="schema1.fact_table1"> <fieldList> <field id="public_table1.table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="public_table2.table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="public_table2.name2" fieldDBName="name2" type="java.math.BigDecimal" /> <field id="public_table3.table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="public_table3.name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> <joinInfo alias="public_fact_table1" referenceId="public_fact_table1" /> <joinedDataSetList> <joinedDataSetRef> <joinString>join public_table1 public_table1 on (public_fact_table1.table1_id == public_table1.table1_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table2 public_table2 on (public_fact_table1.table2_id == public_table2.table2_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table3 public_table3 on (public_fact_table1.table3_id == public_table3.table3_id)</joinString> </joinedDataSetRef> </joinedDataSetList> </jdbcTable> </resources> </schema> """ DOMAIN_SCHEMA_WITHOUT_NAME1_OR_NAME2 = """<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0"> <dataSources> </dataSources> <items> <item description="name3" descriptionId="" id="name3" label="name3" labelId="" resourceId="JoinTree_1.table3.name3" /> </items> <resources> <jdbcTable id="table1" datasourceId="SomeDataSourceJNDI" tableName="schema1.table1"> <fieldList> <field id="table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> </fieldList> </jdbcTable> <jdbcTable id="table2" datasourceId="SomeDataSourceJNDI" tableName="schema1.table2"> <fieldList> <field id="table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> </fieldList> </jdbcTable> <jdbcTable id="table3" datasourceId="SomeDataSourceJNDI" tableName="schema1.table3"> <fieldList> <field id="table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> </jdbcTable> <jdbcTable id="JoinTree_1" datasourceId="SomeDataSourceJNDI" tableName="schema1.fact_table1"> <fieldList> <field id="public_table1.table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="public_table2.table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="public_table3.table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="public_table3.name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> <joinInfo alias="public_fact_table1" referenceId="public_fact_table1" /> <joinedDataSetList> <joinedDataSetRef> <joinString>join public_table1 public_table1 on (public_fact_table1.table1_id == public_table1.table1_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table2 public_table2 on (public_fact_table1.table2_id == public_table2.table2_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table3 public_table3 on (public_fact_table1.table3_id == public_table3.table3_id)</joinString> </joinedDataSetRef> </joinedDataSetList> </jdbcTable> </resources> </schema> """ DOMAIN_SCHEMA_RENAME_NAME1_TO_NAME4_RENAME_DB = """<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0"> <dataSources> </dataSources> <items> <item description="name1" descriptionId="" id="name4" label="name4" labelId="" resourceId="JoinTree_1.table1.name4" /> <item description="name2" descriptionId="" id="name2" label="name2" labelId="Something Else" resourceId="JoinTree_1.table2.name2" /> <item description="name3" descriptionId="" id="name3" label="name3" labelId="" resourceId="JoinTree_1.table3.name3" /> </items> <resources> <jdbcTable id="table1" datasourceId="SomeDataSourceJNDI" tableName="schema1.table1"> <fieldList> <field id="table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="name4" fieldDBName="name4" type="java.lang.String" /> </fieldList> </jdbcTable> <jdbcTable id="table2" datasourceId="SomeDataSourceJNDI" tableName="schema1.table2"> <fieldList> <field id="table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="name2" fieldDBName="name2" type="java.math.BigDecimal" /> </fieldList> </jdbcTable> <jdbcTable id="table3" datasourceId="SomeDataSourceJNDI" tableName="schema1.table3"> <fieldList> <field id="table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> </jdbcTable> <jdbcTable id="JoinTree_1" datasourceId="SomeDataSourceJNDI" tableName="schema1.fact_table1"> <fieldList> <field id="public_table1.table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="public_table1.name4" fieldDBName="name4" type="java.lang.String" /> <field id="public_table2.table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="public_table2.name2" fieldDBName="name2" type="java.math.BigDecimal" /> <field id="public_table3.table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="public_table3.name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> <joinInfo alias="public_fact_table1" referenceId="public_fact_table1" /> <joinedDataSetList> <joinedDataSetRef> <joinString>join public_table1 public_table1 on (public_fact_table1.table1_id == public_table1.table1_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table2 public_table2 on (public_fact_table1.table2_id == public_table2.table2_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table3 public_table3 on (public_fact_table1.table3_id == public_table3.table3_id)</joinString> </joinedDataSetRef> </joinedDataSetList> </jdbcTable> </resources> </schema> """ DOMAIN_SCHEMA_RENAME_NAME1_TO_NAME4_AND_NAME2_TO_NAME5 = """<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0"> <dataSources> </dataSources> <items> <item description="name1" descriptionId="" id="name4" label="name4" labelId="" resourceId="JoinTree_1.table1.name4" /> <item description="name2" descriptionId="" id="name5" label="name2" labelId="Something Else" resourceId="JoinTree_1.table2.name5" /> <item description="name3" descriptionId="" id="name3" label="name3" labelId="" resourceId="JoinTree_1.table3.name3" /> </items> <resources> <jdbcTable id="table1" datasourceId="SomeDataSourceJNDI" tableName="schema1.table1"> <fieldList> <field id="table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="name4" fieldDBName="name1" type="java.lang.String" /> </fieldList> </jdbcTable> <jdbcTable id="table2" datasourceId="SomeDataSourceJNDI" tableName="schema1.table2"> <fieldList> <field id="table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="name5" fieldDBName="name2" type="java.math.BigDecimal" /> </fieldList> </jdbcTable> <jdbcTable id="table3" datasourceId="SomeDataSourceJNDI" tableName="schema1.table3"> <fieldList> <field id="table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> </jdbcTable> <jdbcTable id="JoinTree_1" datasourceId="SomeDataSourceJNDI" tableName="schema1.fact_table1"> <fieldList> <field id="public_table1.table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="public_table1.name4" fieldDBName="name1" type="java.lang.String" /> <field id="public_table2.table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="public_table2.name5" fieldDBName="name2" type="java.math.BigDecimal" /> <field id="public_table3.table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="public_table3.name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> <joinInfo alias="public_fact_table1" referenceId="public_fact_table1" /> <joinedDataSetList> <joinedDataSetRef> <joinString>join public_table1 public_table1 on (public_fact_table1.table1_id == public_table1.table1_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table2 public_table2 on (public_fact_table1.table2_id == public_table2.table2_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table3 public_table3 on (public_fact_table1.table3_id == public_table3.table3_id)</joinString> </joinedDataSetRef> </joinedDataSetList> </jdbcTable> </resources> </schema> """ DOMAIN_SCHEMA_RENAME_NAME1_TO_NAME4_AND_NAME2_TO_NAME5_RENAME_DB = """<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0"> <dataSources> </dataSources> <items> <item description="name1" descriptionId="" id="name4" label="name4" labelId="" resourceId="JoinTree_1.table1.name4" /> <item description="name2" descriptionId="" id="name5" label="name2" labelId="Something Else" resourceId="JoinTree_1.table2.name5" /> <item description="name3" descriptionId="" id="name3" label="name3" labelId="" resourceId="JoinTree_1.table3.name3" /> </items> <resources> <jdbcTable id="table1" datasourceId="SomeDataSourceJNDI" tableName="schema1.table1"> <fieldList> <field id="table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="name4" fieldDBName="name4" type="java.lang.String" /> </fieldList> </jdbcTable> <jdbcTable id="table2" datasourceId="SomeDataSourceJNDI" tableName="schema1.table2"> <fieldList> <field id="table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="name5" fieldDBName="name5" type="java.math.BigDecimal" /> </fieldList> </jdbcTable> <jdbcTable id="table3" datasourceId="SomeDataSourceJNDI" tableName="schema1.table3"> <fieldList> <field id="table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> </jdbcTable> <jdbcTable id="JoinTree_1" datasourceId="SomeDataSourceJNDI" tableName="schema1.fact_table1"> <fieldList> <field id="public_table1.table1_id" fieldDBName="table1_id" type="java.lang.Integer" /> <field id="public_table1.name4" fieldDBName="name4" type="java.lang.String" /> <field id="public_table2.table2_id" fieldDBName="table2_id" type="java.lang.Integer" /> <field id="public_table2.name5" fieldDBName="name5" type="java.math.BigDecimal" /> <field id="public_table3.table3_id" fieldDBName="table3_id" type="java.lang.Integer" /> <field id="public_table3.name3" fieldDBName="name3" type="java.util.Date" /> </fieldList> <joinInfo alias="public_fact_table1" referenceId="public_fact_table1" /> <joinedDataSetList> <joinedDataSetRef> <joinString>join public_table1 public_table1 on (public_fact_table1.table1_id == public_table1.table1_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table2 public_table2 on (public_fact_table1.table2_id == public_table2.table2_id)</joinString> </joinedDataSetRef> <joinedDataSetRef> <joinString>join public_table3 public_table3 on (public_fact_table1.table3_id == public_table3.table3_id)</joinString> </joinedDataSetRef> </joinedDataSetList> </jdbcTable> </resources> </schema> """ fieldDBName = 'fieldDBName' def setUp(self): self.domain_action = DomainAction() self.log = self.common.configureLogging() self.curr_folder = '/tmp' self.test_domain_name = 'test_domain' files_path = Common.REPO_PATH_SEPARATOR + self.test_domain_name + '_files' self.schema_filepath = self.curr_folder + files_path + Common.REPO_PATH_SEPARATOR + 'schema.data' directory = os.path.dirname(self.schema_filepath) if not os.path.exists(directory): os.makedirs(directory) with open(self.schema_filepath, 'w') as h1: h1.write(self.DOMAIN_SCHEMA) def tearDown(self): try: os.remove(self.schema_filepath) except OSError: pass def testRemoveFieldFromSchemaIsFK(self): mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1.text.find.return_value = -1 mock_node1.get.return_value = 'name1' mock_node2 = MagicMock(name='mock_node2') mock_node2.text.find.return_value = 14 node_list = [mock_node1, mock_node2] mock_root.xpath = MagicMock(side_effect=[node_list, '', '']) try: self.domain_action.renameOrRemoveFieldFromSchema(root=mock_root, fieldname='name2', newfieldname=None, newdbcolname=None, log=self.log) raise ValueError('This method call should not have worked') except ValueError as e: self.assertEqual( 'We will probably be able to handle removing key fields in the future, but for now it is not allowed', e.args[0], 'incorrect error message') def testRemoveFieldFromSchemaIsItem(self): mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1.text.find.return_value = -1 mock_node1.get.return_value = 'name1' mock_node2 = MagicMock(name='mock_node2') mock_node2.text.find.return_value = -1 mock_node2.get.return_value = 'name2' mock_node2.getparent.return_value = mock_root node_list = [mock_node1, mock_node2] mock_root.xpath = MagicMock(side_effect=['', node_list, '']) self.domain_action.renameOrRemoveFieldFromSchema(root=mock_root, fieldname='name2', newfieldname=None, newdbcolname=None, log=self.log) mock_root.remove.assert_called_with(mock_node2) def testRemoveFieldFromSchemaIsField(self): mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1.text.find.return_value = -1 mock_node1.get.return_value = 'name1' mock_node2 = MagicMock(name='mock_node2') mock_node2.text.find.return_value = -1 mock_node2.get.return_value = 'name2' mock_node2.getparent.return_value = mock_root node_list = [mock_node1, mock_node2] mock_root.xpath = MagicMock(side_effect=['', '', node_list]) self.domain_action.renameOrRemoveFieldFromSchema(root=mock_root, fieldname='name2', newfieldname=None, newdbcolname=None, log=self.log) mock_root.remove.assert_called_with(mock_node2) def testRenameFieldInSchemaIsItem(self): mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1.get.return_value = 'name1' mock_node2 = MagicMock(name='mock_node2') mock_node2.get.return_value = 'name2' node_list = [mock_node1, mock_node2] mock_root.xpath = MagicMock(side_effect=[[], node_list, []]) self.domain_action.renameOrRemoveFieldFromSchema(root=mock_root, fieldname='name2', newfieldname='name4', newdbcolname=None, log=self.log) mock_node2.attrib.__setitem__.assert_called_with( Common.RESOURCE_ID, 'name4') def testRenameFieldInSchemaIsField(self): mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1.get.return_value = 'name1' mock_node2 = MagicMock(name='mock_node2') mock_node2.get.return_value = 'name2' node_list = [mock_node1, mock_node2] mock_root.xpath = MagicMock(side_effect=[[], [], node_list]) self.domain_action.renameOrRemoveFieldFromSchema(root=mock_root, fieldname='name2', newfieldname='name4', newdbcolname=None, log=self.log) mock_node2.attrib.__setitem__.assert_called_once_with( Common.ID, 'name4') def testRenameFieldInSchemaIsFieldWithDBCol(self): mock_root = MagicMock(name='mock_root') mock_node1 = MagicMock(name='mock_node1') mock_node1.get.return_value = 'name1' mock_node2 = MagicMock(name='mock_node2') mock_node2.get.return_value = 'name2' node_list = [mock_node1, mock_node2] mock_root.xpath = MagicMock(side_effect=[[], [], node_list]) self.domain_action.renameOrRemoveFieldFromSchema(root=mock_root, fieldname='name2', newfieldname='name4', newdbcolname='name4', log=self.log) mock_node2.attrib.__setitem__.assert_called_with( Common.FIELD_DB_NAME, 'name4') def testRemoveField(self): field_name = 'name1' self.domain_action.removeOrRenameField(filename=self.schema_filepath, fieldname=field_name, newfieldname=None, newdbcolname=None, log=self.log) with open(self.schema_filepath) as h: schema_xml = h.read() self.assertEqual(self.DOMAIN_SCHEMA_WITHOUT_NAME1.replace(' ', ''), schema_xml.replace(' ', ''), 'Domain schema file does not match expected') def testRemoveFieldIsKey(self): field_name = 'table1_id' try: self.domain_action.removeOrRenameField( filename=self.schema_filepath, fieldname=field_name, newfieldname=None, newdbcolname=None, log=self.log) raise ValueError('This method call should not have worked') except ValueError as e: self.assertEqual( 'We will probably be able to handle removing key fields in the future, but for now it is not allowed', e.args[0], 'incorrect error message') def testRenameDBField(self): oldfieldname = 'name1' newfieldname = 'name4' self.domain_action.removeOrRenameField(filename=self.schema_filepath, fieldname=oldfieldname, newfieldname=newfieldname, newdbcolname=newfieldname, log=self.log) with open(self.schema_filepath) as h: schema_xml = h.read() self.assertEqual( self.DOMAIN_SCHEMA_RENAME_NAME1_TO_NAME4_RENAME_DB.replace( ' ', ''), schema_xml.replace(' ', ''), 'Domain schema file does not match expected') def testRemoveMultipleFields(self): field_name = ['name1', 'name2'] self.domain_action.removeOrRenameField(filename=self.schema_filepath, fieldname=field_name, newfieldname=None, newdbcolname=None, log=self.log) with open(self.schema_filepath) as h: schema_xml = h.read() self.assertEqual( self.DOMAIN_SCHEMA_WITHOUT_NAME1_OR_NAME2.replace(' ', ''), schema_xml.replace(' ', ''), 'Domain schema file does not match expected') def testRenameMultipleFields(self): oldfieldname = ['name1', 'name2'] newfieldname = ['name4', 'name5'] self.domain_action.removeOrRenameField(filename=self.schema_filepath, fieldname=oldfieldname, newfieldname=newfieldname, newdbcolname=None, log=self.log) with open(self.schema_filepath) as h: schema_xml = h.read() self.assertEqual( self.DOMAIN_SCHEMA_RENAME_NAME1_TO_NAME4_AND_NAME2_TO_NAME5. replace(' ', ''), schema_xml.replace(' ', ''), 'Domain schema file does not match expected') def testRenameMultipleFieldsWithDB(self): oldfieldname = ['name1', 'name2'] newfieldname = ['name4', 'name5'] newdbcolname = ['name4', 'name5'] self.domain_action.removeOrRenameField(filename=self.schema_filepath, fieldname=oldfieldname, newfieldname=newfieldname, newdbcolname=newdbcolname, log=self.log) with open(self.schema_filepath) as h: schema_xml = h.read() self.assertEqual( self. DOMAIN_SCHEMA_RENAME_NAME1_TO_NAME4_AND_NAME2_TO_NAME5_RENAME_DB .replace(' ', ''), schema_xml.replace(' ', ''), 'Domain schema file does not match expected')