Changeset 6544


Ignore:
Timestamp:
09/02/10 15:36:46 (9 years ago)
Author:
sdonegan
Message:

Updated version of MEDIN ingest - will ingest NEODC DIFs, convert to ISO then load ISO into DB - all original NDG3 functionality inc configurable ingest now included.

Location:
TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/DeleteRecord.py

    r5687 r6544  
    111111            record = RecordToDelete(recordFilename,None) 
    112112            logging.info("Getting discoveryId from database for  %s" %recordFilename)      
    113             dao = PostgresDAO(record, self.pgc)               
     113            dao = PostgresDAO(record, None, None, None, self.pgc)               
    114114            self.createRecordObject(record,dao,recordFilename) 
    115115             
     
    118118            record = RecordToDelete(None,discoveryID) 
    119119            logging.info("Getting discoveryId from database for  %s" %discoveryID)      
    120             dao = PostgresDAO(record, self.pgc)               
     120            dao = PostgresDAO(record, None, None, None, self.pgc)               
    121121            self.createRecordObject(record,dao,recordFilename) 
    122122         
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/ExtractISO.py

    r6451 r6544  
    3838                 
    3939                logging.info("") 
     40                logging.info("********************************************************************************************************************************************") 
    4041                logging.info("****************** Creating ISO data structure from " + self.inputXMLfile + "****************** ") 
     42                logging.info("********************************************************************************************************************************************") 
    4143                logging.info("") 
    4244                 
     
    158160                logging.info("Format chosen: " + format) 
    159161                 
    160                 if format == 'MEDINv2.3': 
    161                          
    162                         from difConvertedto_ISO19139 import difConvertedto_ISO19139 as dif2iso 
    163                          
    164                 ''' 
    165                 "Stub" iso profile based on MEDIN profile - non complete ISO from GCMD DIF metadata converted via NDG xquery (v?) 
    166                 '''      
    167                 if format == 'dif2stubIso': 
    168                          
    169                         from difConvertedto_ISO19139 import difConvertedto_ISO19139 as dif2iso 
    170                          
    171                 ''' 
    172                 Other ISO profiles to support: NERC Discovery; CEH ISO etc etc, WPCC 
    173                 ''' 
    174  
    175                 self.isoModel = dif2iso() 
     162                 
     163                 
     164                #Dynamically import module of correct profile... 
     165                import_string = "from " + format + " import " + format + " as iso" 
     166                 
     167                try: 
     168                        exec import_string 
     169                except: 
     170                        logging.error("Could not import xpath class for: " + format) 
     171                        sys.exit() 
     172                 
     173                self.isoModel = iso() 
    176174                 
    177175                 
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/PostgresDAO.py

    r6368 r6544  
    44C Byrom Apr 08 
    55''' 
    6 import sys, os, logging 
     6import sys, os, logging, datetime 
    77from SpatioTemporalData import * 
    88from ndg.common.src.clients.reldb.postgres.postgresclient import PostgresClient as pgc 
     
    1010class PostgresDAO: 
    1111     
    12     def __init__(self, record, isoDataModel, pgClient = None): 
     12    def __init__(self, record, isoDataModel,transformationDir, pgClient = None): 
    1313        ''' 
    1414        Constructor - to initialise the DAL and do some initial setting up 
     
    3030 
    3131        self._record = record 
    32         import pdb 
    33         pdb.set_trace() 
    34          
    35         self.isoDataModel = isoDataModel 
     32         
     33        self.isoDataModel = isoDataModel         
     34        self.discovery_dir = transformationDir 
     35         
     36         
    3637         
    3738 
     
    111112        @return result: True if record created/updated, false if otherwise 
    112113        ''' 
     114        
    113115        self.getRecordID() 
    114116        returnCode=0 # 0 if failed, 1 if update, 2 if create 
    115          
    116         if self._record.db_id:           
    117             if self.updateRecord(): 
     117          
     118        if self._record.db_id:                
     119            if self.updateRecord():              
    118120                returnCode = 1 
    119         else:             
     121        else: 
     122                #create the record!           
    120123            if self.createRecord(): 
    121124                returnCode = 2 
     
    149152        logging.info("Record already existing in DB - performing updates") 
    150153        result = False 
     154         
    151155        # firstly, check the document is actually new - i.e. not just a repeat of the same data 
    152156        if self._checkIsUpdatedRecord(): 
    153  
     157             
    154158            # firstly, update the original record 
    155159            self._updateOriginalRecord() 
    156          
     160             
    157161            # now update the actual documents contained by the record - i.e. the original doc + 
    158162            # the various transforms required 
    159163            self._updateMetadataRecords() 
    160  
     164             
    161165            # If doing an update of an existing record, clear out existing spatiotemporal 
    162166            # data, rather than updating it, to keep things simple 
    163167            logging.info("Clearing out existing data for record - to allow clean update") 
     168             
    164169            self._deleteSpatioTemporalData() 
    165170            self._insertSpatioTemporalData() 
     
    167172 
    168173        logging.info("Finish processing document...") 
     174         
    169175        return result 
     176         
    170177         
    171178         
     
    218225        self.pgc.runSQLCommand(sqlCmd) 
    219226        logging.info("Spatiotemporal data deleted successfully") 
     227         
    220228 
    221229 
     
    223231        ''' 
    224232        Create a single row record in the postgres DB based on the 
    225         input data 
     233        input data.  Updated to operate with dictionary methods for coords and timeRange as part of MEDIN ISO upgrade 
    226234        @param coords: a Coords object representing NSWE coords 
    227235        @param timeRange: a TimeRange object representing a start/end date  
    228236        ''' 
    229237        logging.info("Adding spatiotemporal row to DB") 
    230          
     238                
    231239        sqlCmd = "SELECT add_spatiotemporal_row('" + str(self._record.db_id) + "', '" + \ 
    232             str(coords.north) + "', '" + str(coords.south) + "', '" + str(coords.west) + "', '" + \ 
    233             str(coords.east) + "', '" + timeRange.start + "', '" + timeRange.end + "');" 
     240            str(coords['north']) + "', '" + str(coords['south']) + "', '" + str(coords['west']) + "', '" + \ 
     241            str(coords['east']) + "', '" + timeRange['start'] + "', '" + timeRange['end'] + "');" 
    234242             
    235243        # fix any null strings 
    236244        sqlCmd = sqlCmd.replace("'null'", "null") 
     245         
     246         
    237247 
    238248        self.pgc.runSQLCommand(sqlCmd) 
    239249        logging.info("Spatiotemporal row added successfully") 
    240250         
     251         
    241252     
    242253    def _insertSpatioTemporalData(self): 
     
    244255        Create a record in the postgres DB based on the spatiotemporal data  
    245256        specified in the PostgresRecord object 
     257         
     258        Note updated to work with ISO metadata object where coords and times already defined as individual items. 
     259         
    246260        ''' 
    247261        logging.info("Adding spatiotemporal data to DB record") 
     
    249263        # Work out the relationship between the spatial and temporal data and handle appropriately 
    250264         
    251         # error here! SJD - added a try/except to set timedata to null for instances where no temporal data in xml 
    252         # - should be caught elsewhere, but easiest fudge is to put it in here. 23/09/08 SJD. 
    253         try: 
    254             timeData = self._record.getTemporalData()  
    255         except: 
    256              
    257             timeData = [ TimeRange('null', 'null') ] 
    258              
    259         spatialData = self._record.getSpatialData() 
     265         
     266        TimeRange = self._record.parseTemporalInfo(self._record.datasetTemporalData) 
     267        SpatialCoords = self._record.parseSpatialInfo(self._record.datasetSpatialData) 
    260268        
    261         # check if we have any spatiotemporal data to add; escape if not 
    262         if not timeData and not spatialData: 
    263             logging.info("No spatiotemporal data found for record - skipping") 
    264             return 
    265          
    266         # setup dummy, null data if required 
    267         if not timeData: 
    268             timeData = [ TimeRange('null', 'null') ] 
    269          
    270         if not spatialData: 
    271             spatialData = [ Coords('null', 'null', 'null', 'null') ] 
    272         
    273         # if both arrays of data are the same length, assume they map together 
     269                 
     270        if (len(TimeRange) == 0) and (len(SpatialCoords) == 0): 
     271                logging.info("No spatiotemporal data found for record - skipping") 
     272                return 
     273         
     274         
     275        # if both arrays of data are the same length, assume they map together         
    274276        i = 0 
    275         if len(timeData) == len(spatialData): 
     277        if len(TimeRange) == len(SpatialCoords): 
    276278            logging.info("Spatial data is the same size as temporal data; assuming these map together one to one") 
    277             for timeRange in timeData: 
    278                 self._insertSpatioTemporalRow(spatialData[i], timeRange) 
     279            for times in TimeRange: 
     280                self._insertSpatioTemporalRow(SpatialCoords[i], times) 
    279281                i += 1 
    280282 
     
    282284        else: 
    283285            logging.info("Spatial and temporal data are of different sizes; map everything to everything") 
    284             for timeRange in timeData: 
    285                 for coords in spatialData: 
    286                     self._insertSpatioTemporalRow(coords, timeRange) 
     286            for times in TimeRange: 
     287                for coords in SpatialCoords: 
     288                     
     289                    self._insertSpatioTemporalRow(coords, times) 
     290                     
    287291        logging.info("Spatiotemporal data added to DB record") 
    288              
     292         
     293         
    289294     
    290295    def _insertOriginalRecord(self): 
     
    294299        logging.info("Inserting new original document in Postgres DB") 
    295300         
    296         import pdb 
    297         pdb.set_trace() 
    298          
    299         ''' 
     301         
     302        ''' ndg3 style command 
    300303        sqlCmd = "SELECT create_document('" + self._record.shortFilename + "', '" + \ 
    301304            self._record.discovery_id + "', '" + self._record.docType + "', '" + \ 
     
    305308                     
    306309        ''' 
     310        
     311         
     312        sqlCmd = "SELECT create_document('" + self._record.shortFilename + "', '" + \ 
     313            self._record.discovery_id + "', '" + self._record.docType + "', '" + \ 
     314            self._record.originalFormat + "', '" + self._record.getAuthorsInfo() + "', '" + \ 
     315            self._record.getParametersInfo() + "', '" + self._record.getScopeInfo() + "', '" + \ 
     316            self._record.dataset_name + "', '" + self._record.datacentre_name + "', '" + \ 
     317            self._record.dataset_lastEdit + "', '" + self._record.datasetStartNom + "', '" + self._record.datasetEndNom + "');" 
     318         
     319         
     320        #sort out any nulls.. 
    307321        sqlCmd = sqlCmd.replace("'NULL'","NULL") 
    308  
     322         
     323        #sort out any Nones 
     324        sqlCmd = sqlCmd.replace("'None'","NULL") 
     325         
    309326        id = self.pgc.runSQLCommand(sqlCmd) 
    310327        if len(id) == 0: 
     
    312329         
    313330        self._record.db_id = id[0][0]  
     331        
    314332        logging.info("Original document inserted in Postgres DB") 
    315333             
     
    337355            self._record.getParametersInfo() + "', '" + self._record.getScopeInfo() + "', '" + str(self._record.scn) + "', '" + self._record.dataset_name + "', '" + self._record.datacentre_name + "', '" + self._record.dataset_lastEdit + "', '" + self._record.datasetStartNom + "', '" + self._record.datasetEndNom + "');"  
    338356             
    339              
    340             
     357         
    341358        #sort out any NULL values" 
    342359        sqlCmd = sqlCmd.replace("'NULL'","NULL") 
    343360         
    344         logging.info("SQl command:   " + sqlCmd)          
     361        #sort out any Nones 
     362        sqlCmd = sqlCmd.replace("'None'","NULL")         
     363         
     364        logging.info("Submitting SQL command") 
     365        #logging.info("SQl command:   " + sqlCmd)          
    345366         
    346367        self.pgc.runSQLCommand(sqlCmd) 
     
    357378        ''' 
    358379        logging.info("Inserting transformed documents for original document, %s, in Postgres DB", self._record.shortFilename) 
     380         
     381        
    359382        if self._record.db_id is None: 
    360383            logging.info("No DB ID for the original record exists; cannot add associated transformed docs") 
    361384            return 
    362385         
    363         for docType, doc in self._record.getAllDocs(): 
     386        for docType, doc in self._record.getAllDocs(self.discovery_dir): 
     387             
     388            #if docType is original input xml then put that in rather than some lossy transformed guff. 
     389            if docType == self._record.docType: 
     390                doc = self._record.originalXMLdoc 
     391             
     392                                   
    364393            sqlCmd = "INSERT INTO TRANSFORMED_DOCUMENT (transformed_document_id, " \ 
    365394                "original_document_id, transformed_format, " \ 
     
    368397                docType + "', '" + doc + "', current_timestamp, 1);" 
    369398             
     399             
    370400            self.pgc.runSQLCommand(sqlCmd) 
    371401         
     
    377407        Update the metadata docs into the postgres DB 
    378408        ''' 
     409         
    379410        logging.info("Updating transformed documents for original document, %s, in Postgres DB", self._record.shortFilename) 
    380411        if self._record.db_id is None: 
     
    382413            return 
    383414         
    384         for docType, doc in self._record.getAllDocs(): 
     415        for docType, doc in self._record.getAllDocs(self.discovery_dir): 
     416             
     417            #if docType is original input xml then put that in rather than some lossy transformed guff. 
     418            if docType == self._record.docType: 
     419                doc = self.originalXMLdoc              
     420             
    385421            sqlCmd = "UPDATE TRANSFORMED_DOCUMENT SET transformed_document = '" + doc + \ 
    386422                "', update_date = current_timestamp WHERE original_document_id = " + \ 
    387423                str(self._record.db_id) + " AND transformed_format = '" + docType + "';" 
    388  
     424                 
     425             
    389426            self.pgc.runSQLCommand(sqlCmd) 
    390427     
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/PostgresRecord.py

    r6364 r6544  
    66from xml.etree import cElementTree 
    77import os, sys, logging, re, pkg_resources 
    8 import csml.csml2Moles.molesReadWrite as MRW 
     8#import csml.csml2Moles.molesReadWrite as MRW 
    99from ndg.common.src.models.ndgObject import ndgObject 
    1010from ndg.common.src.lib.ndgresources import ndgResources 
    1111import ndg.common.src.lib.fileutilities as FileUtilities 
     12from Utilities import xqueryTransformation 
    1213from SpatioTemporalData import SpatioTemporalData 
    1314import keywordAdder 
     
    2728    ''' 
    2829    # TODO MDIP transforms do not work very well for lots of files - so currently hiding these 
    29     documentTypes = ['MOLES', 'DIF', 'DC', 'ISO19139']#, 'MDIP'] 
     30    #documentTypes = ['DIF', 'DC', 'ISO19139']#, 'MDIP'] 
    3031     
    3132    # vocab server - used for finding scope values in the moles files 
     
    3334         
    3435    #def __init__(self, filename, ndg_dataprovider, datacentre_groups, datacentre_namespace, discovery_id, xq, docType): 
    35     def __init__(self, filename, ndg_dataprovider, datacentre_groups, datacentre_namespace, isoDataModel, xq, docType): 
     36    def __init__(self, filename, ndg_dataprovider, datacentre_groups, datacentre_namespace, isoDataModel, xq, docType 
     37                                , xqExceptions , xqueryConversions, saxonJarFile, xqueryDocTypes, originalXML, stubIso = None): 
    3638                  
    3739                  
    3840        logging.info("Setting up Postgres record for file, " + filename) 
    3941         
    40         self.filename = filename 
    41      
     42         
    4243        self.isoDataModel = isoDataModel 
     44         
     45        self.filename = self.isoDataModel.isoFileLocation 
     46     
    4347         
    4448        #note method of extracting info from isoDataModel - nested lists, so if one value then use [0][0] 
     
    5862        self.discovery_id = discovery_id # just a single val.. 
    5963        self._xq = xq 
     64         
    6065        # simplify processing by uppercasing format at initialisation 
    6166        self.docType = docType.upper()     
    62          
    63         
     67                
    6468        #make sure we escape any special characters in this field... SJD 20/10/09         
    6569        #self.dataset_name = self.escapeSpecialCharacters(self.isoDataModel.datasetName[0]) 
    6670        self.dataset_name = self.escapeSpecialCharacters(self.isoDataModel.datasetName[0][0]) 
    6771         
     72        self.datacentre_name = self.isoDataModel.datacentreName[0][0] 
     73         
    6874        #self.dataset_lastEdit = datasetLastEditUpdateDate     
    6975        self.dataset_lastEdit = self.isoDataModel.revisionDate[0][0] 
    70          
    71         #for nominal start and end dates need to get extreme if multiple values in there 
    72         # - just create list of all values present, sort it by date then select min and max 
    73          
    74          
     76                 
    7577        #self.datasetStartNom = datasetStartDateNom 
    76         self.datasetStartNom = self.isoDataModel.boundingDates['start'] #dictionary method! 
     78        self.datasetStartNom = self.isoDataModel.boundingDatesRange['start'] #dictionary method! 
    7779         
    7880        #self.datasetEndNom = datasetEndDateNom 
    79         self.datasetEndNom = self.isoDataModel.boundingDates['end'] #dictionary method! 
    80                  
     81        self.datasetEndNom = self.isoDataModel.boundingDatesRange['end'] #dictionary method!     
     82         
     83        self.datasetTemporalData = self.isoDataModel.boundingDates # set whole list of dictionaries for this as may be multiple boxes  
     84         
     85        self.datasetSpatialData = self.isoDataModel.boundingBoxCoordinates # set whole list of dictionaries for this as may be multiple boxes 
     86         
    8187        self._molesFormat = None    # initialise this, so we can guarantee a value - to avoid using getattr 
    8288        self._allDocs = []  # array to store all the transformed docs - for easy retrieval by the DAO 
     
    8793        self.shortFilename = tmp[-1] 
    8894         
    89         # dir to store a temp copy of the moles file, when produced - for use by other transforms 
    90         self._molesDir = None 
    91         # object to hold the moles file - this will be loaded in when it is created - in order to extract 
    92         # spatiotemporal data, etc 
    93         self.dgMeta = None 
    94  
    95         # firstly load contents of file 
    96         self.originalFormat = file(filename).read() 
     95        
     96        #self.originalFormat = self.isoDataModel.originalFormat[0][0] 
     97        self.originalFormat = file(self.filename).read() 
    9798         
    9899        # escape any apostrophes  
    99100        self.originalFormat = self.escapeSpecialCharacters(self.originalFormat) 
    100  
     101                 
    101102        # initialise the various record fields 
    102103        self.db_id = None    # the DB ID of the record, for easy reference when it is created 
    103         self.molesFormat = None 
     104        #self.molesFormat = None 
    104105        self.dcFormat = None 
    105         self.mdipFormat = None 
     106        #self.mdipFormat = None 
    106107        self.iso19139Format = None 
    107108        self.scn = 1    # system change number - keeps track of number of mods to a particular row 
     
    114115        self.parameters = None 
    115116        self.scope = None 
     117         
     118        #info needed for performing xquery conversions in the MEDIN ingest stack 
     119        self._xqueryConversionsExceptions = xqExceptions         
     120        self._xqueryConversions = xqueryConversions         
     121        self._xqueryDocTypes = xqueryDocTypes         
     122        self._saxonJarFile = saxonJarFile 
     123         
     124        self.stubISO = self.escapeSpecialCharacters(stubIso) 
     125        self.originalXMLdoc = self.escapeSpecialCharacters(originalXML) 
    116126         
    117127         
     
    150160 
    151161 
    152     def createMolesFile(self): 
    153         ''' 
    154         Check if a moles file exists on the system; if not, assume the moles transform has not 
    155         been ran and then produce this file - to allow for use in the various xqueries 
    156         ''' 
    157         logging.info("Creating moles file on system - for use with other xquery transforms") 
    158         self._molesDir = self._dir + "/moles/" 
    159         FileUtilities.setUpDir(self._molesDir) 
    160          
    161         if self._molesFormat is None: 
    162             self.doMolesTransform() 
    163              
    164         FileUtilities.createFile(self._molesDir + self.shortFilename, self._molesFormat) 
    165         logging.info("Moles file created - at %s" %self._molesDir) 
    166          
    167         # now load this moles file, for use when parsing out spatiotemporal, author and parameters data later on         
    168         molesFile = self._molesDir + self.shortFilename 
    169         logging.info('Retrieving spatiotemporal info from moles file, %s' %molesFile) 
    170          
    171         # load in the moles file and put this into an object for direct access to the xml elements 
    172         
    173         self.dgMeta=MRW.dgMetadata() 
    174         try: 
    175             self.dgMeta.fromXML(cElementTree.ElementTree(file=molesFile).getroot()) 
    176         except Exception, detail: 
    177             raise SystemError, 'Cannot parse the XML moles document %s. Detail:\n%s' %(molesFile, detail) 
    178  
     162         
    179163 
    180164    def doTransform(self, xQueryType): 
     
    184168        @return: the metadata record in the required transformed format  
    185169        ''' 
    186         logging.info("Running XQuery transform, " + xQueryType + " to create transformed document") 
    187  
    188         # firstly, check if this is a moles -> something else query; if so, ensure there is a valid 
    189         # moles file available for the transform - and use the correct dir for the xquery collection 
    190         dir = self._dir 
    191         if xQueryType.find('moles2') > -1: 
    192             if self._molesDir is None: 
    193                 self.createMolesFile() 
    194                  
    195             dir = self._molesDir 
     170        logging.info("Running XQuery transform, " + xQueryType + " to create TRANSFORMED document!!") 
     171 
    196172             
    197         # get the query and set this up to use properly 
    198          
    199         #xquery = self._xq.actual(xQueryType, dir, self._repository_local_id, self._local_id) 
    200         #SJD - added this bit in (missed?) to upgrade to ndgCommon. 
    201         self.xqueryLib = ndgResources()         
    202         xquery = self.xqueryLib.createXQuery(xQueryType,dir, self._repository_local_id, self._local_id) 
    203        
    204         # sort out the input ID stuff 
    205         xquery=xquery.replace('Input_Entry_ID', self.discovery_id) 
    206         xquery=xquery.replace('repository_localid', self._repository) 
    207  
    208         # strip out the eXist reference to the libraries; these files should be available in the 
    209         # running dir - as set up by oai_ingest.py 
    210         xquery=xquery.replace('xmldb:exist:///db/xqueryLib/Vocabs/', '') 
    211         xquery=xquery.replace('xmldb:exist:///db/xqueryLib/Utilities/', '') 
    212  
    213         # write the query to file, to make it easier to input 
    214         # NB, running directly at the command line leads to problems with the interpretation of $ characters 
    215         xqFile = "currentQuery" + xQueryType + ".xq"  
    216         FileUtilities.createFile(xqFile, xquery) 
    217          
    218         # ensure the jar file is available - NB, this may be running from a different 
    219         # location - e.g. the OAIInfoEditor.lib.harvester - and this won't have the 
    220         # saxon file directly on its filesystem 
    221         jarFile = pkg_resources.resource_filename('OAIBatch', SAXON_JAR_FILE) 
    222  
    223         # Now do the transform 
    224         os.putenv ('PATH', ':/usr/java/jdk1.5.0_03/bin:/usr/java/jdk1.5.0_03:/usr/java/jdk1.5.0_03/lib/tools.jar:/usr/local/WSClients/OAIBatch:/usr/local/exist-client/bin:/bin:/usr/bin:.') 
    225         xqCommand = "java -cp %s net.sf.saxon.Query %s !omit-xml-declaration=yes" %(jarFile, xqFile) 
    226         logging.debug("Running saxon command: " + xqCommand) 
    227         pipe = os.popen(xqCommand + " 2>&1") 
    228         output = pipe.read() 
    229         status = pipe.close() 
    230  
    231         if status is not None: 
    232             raise SystemError, 'Failed at running the XQuery' 
    233  
    234         # now remove the temp xquery file 
    235         '''status = os.unlink(xqFile) 
    236         if status is not None: 
    237             raise OSError, 'Failed to remove the temporary xquery file, ' + xqFile''' 
    238          
    239         logging.info("Transform completed successfully") 
    240  
    241         return output 
    242  
    243  
    244     def doMolesTransform(self): 
    245         ''' 
    246         Set up the basic moles doc - according to the type of document first ingested 
    247         ''' 
    248         logging.info("Creating moles document - for use with other transforms") 
    249         xqName = None 
    250         if self.docType == "DIF": 
    251             xqName = "dif2moles" 
    252         elif self.docType == "MDIP": 
    253             xqName = "mdip2moles" 
    254         else: 
    255             raise TypeError, "ERROR: No XQuery exists to transform input document type, %s, into moles format" \ 
    256                      %self.docType 
    257  
    258         # now run the appropriate transform and set the attribute 
    259         setattr(self, "_molesFormat", self.doTransform(xqName)) 
    260  
    261         # add keywords, if required 
    262         if self._datacentre_groups: 
    263             self.addKeywords() 
    264          
    265         # escape any apostrophes 
    266         self._molesFormat = self.escapeSpecialCharacters(self._molesFormat) 
    267  
    268         logging.info("moles document created") 
    269          
    270  
    271     def addKeywords(self): 
    272         ''' 
    273         If datacentre groups have been specified, these need to be added as keywords 
    274         - NB, this is rather clumsy approach but uses old code to achieve the result 
    275         ''' 
    276         logging.info("Adding datacentre keywords to moles file") 
    277  
    278         # NB, use temporary directories to do the keyword additions 
    279         tmpDir = os.getcwd() + "/tmp/" 
    280         tmpKeywordsDir = os.getcwd() + "/keywordsAdded/" 
    281         FileUtilities.setUpDir(tmpDir) 
    282         FileUtilities.setUpDir(tmpKeywordsDir) 
    283         tmpFile = 'tmpFile.xml' 
    284         FileUtilities.createFile(tmpDir + tmpFile, self._molesFormat) 
    285  
    286         keywordAdder.main(tmpDir, tmpKeywordsDir, self._datacentre_groups) 
    287  
    288         # Now load in the converted file 
    289         f=open(tmpKeywordsDir + "/" + tmpFile, 'r') 
    290         self._molesFormat = f.read() 
    291         f.close 
    292          
    293         # Finally, tidy up temp dirs 
    294         FileUtilities.cleanDir(tmpDir) 
    295         FileUtilities.cleanDir(tmpKeywordsDir) 
    296         logging.info("Completed adding keywords") 
    297          
     173        #takes metadataFileLoc,repositoryName,metadataID,metadataFilename, saxonJar 
     174        #self.xqueryTransformation = xqueryTransformation(self.discovery_dir,self._repository,self.discovery_id,self._local_id,self._saxonJarFile) 
     175        self.xqueryTransformation = xqueryTransformation(self.discovery_dir,self._repository,self._local_id,self.discovery_id,self._saxonJarFile) 
     176        self.transformedXML = self.xqueryTransformation.runXquery(xQueryType) 
     177                                         
     178        return self.transformedXML 
     179 
     180 
     181 
    298182 
    299183    def getDocumentFormat(self, docType): 
     
    303187        @param docType: format of document to return  
    304188        ''' 
     189         
     190        
    305191        logging.info("Retrieving document type, " + docType) 
    306         xqName = {'DIF':'moles2dif', 'MOLES':'moles', 'DC':'moles2DC', 'MDIP':'moles2mdip', 'ISO19139':'moles2iso19139'}[docType] 
    307         attributeName = {'DIF':'_difFormat', 'MOLES':'_molesFormat', 'DC':'_dcFormat', 'MDIP':'_mdipFormat', 'ISO19139':'_iso19139Format'}[docType] 
    308          
    309         # check we have the moles format available; if not create it 
    310         if self._molesFormat is None: 
    311             self.doMolesTransform() 
    312             self.createMolesFile() 
    313          
    314         # check the document isn't already defined 
    315         try: 
    316             doc = getattr(self, attributeName) 
    317             if doc is not None: 
    318                 logging.info("Found existing document - returning this now") 
    319                 return doc 
    320         except: 
    321             logging.info("Document not available - creating new transformed document") 
    322  
     192         
    323193        # the doc type doesn't exist - so run the xquery 
    324         transformedDoc = self.doTransform(xqName) 
    325         setattr(self, attributeName, transformedDoc) 
     194        transformedDoc = self.doTransform(docType) 
     195         
     196        #not sure if we still need to do this..? 
     197        setattr(self, docType, transformedDoc) 
     198         
     199         
    326200        return transformedDoc 
    327201         
    328202     
    329     def getAllDocs(self): 
     203    def getAllDocs(self,transformationDir): 
    330204        ''' 
    331205        Return a list of all the available doc types in the record 
     
    333207        # if the stored docs array is the same size as the array of all doc types 
    334208        # assume all transforms have been done - and just return these 
    335         if len(self._allDocs) == len(self.documentTypes): 
    336             return self._allDocs 
    337          
    338         for docType in self.documentTypes: 
    339             self._allDocs.append([docType, self.getDocumentFormat(docType)]) 
    340  
     209         
     210        self.discovery_dir = transformationDir 
     211                 
     212        for docType in self._xqueryConversions: 
     213                 
     214                self._allDocs.append([self._xqueryDocTypes[docType], self.escapeSpecialCharacters(self.getDocumentFormat(docType))]) 
     215                 
     216        #remember, if a non ISO input format we need to add the stubISO intermediate format too. 
     217        #(if original format was ISO, this is covered by the self.originalXMLdoc overrider in the insertMetadata method in PostgresDAO.) 
     218         
     219        if self.stubISO is not None: 
     220                logging.info("Transient ISO intermediate format detected; adding to transformed docs!") 
     221                self._allDocs.append(['stubISO',self.stubISO]) 
     222        
     223        
    341224        return self._allDocs 
    342225         
    343226     
    344     def getTemporalData(self): 
    345         ''' 
    346         Retrieves the temporal data for the record; if this hasn't been discovered yet, 
    347         do the necessary parsing 
    348         @return: TimeRange object array with temporal data 
    349         ''' 
    350         if self.stData is None: 
    351             self.getSpatioTemporalData() 
    352          
    353         return self.stData.getTemporalData() 
    354          
    355      
    356     def getSpatialData(self): 
    357         ''' 
    358         Retrieves the spatial data for the record; if this hasn't been discovered yet, 
    359         do the necessary parsing 
    360         @return: Coords object array with spatial data 
    361         ''' 
    362         if self.stData is None: 
    363             self.getSpatioTemporalData() 
    364          
    365         return self.stData.getSpatialData() 
    366          
    367227 
    368228    def listify(self, item): 
     
    383243        Extract spatio temporal data from the original document 
    384244        ''' 
    385         logging.info('Retrieving spatiotemporal info from moles file') 
     245        logging.info('Retrieving spatiotemporal info from ISO file') 
    386246        # initialise the various spatiotemporal arrays used to extract data to 
     247         
     248         
     249        ''' 
    387250        self.stData = SpatioTemporalData() 
    388251         
     
    390253            self.createMolesFile() 
    391254             
     255            
    392256        # do quick checks to see if the relevant data exists 
    393257        if not self.dgMeta.dgMetadataRecord.dgDataEntity.dgDataSummary: 
     
    409273        else: 
    410274            self.getTimeRangeData(self.dgMeta) 
    411  
     275                ''' 
    412276     
    413277    def getAuthorsInfo(self): 
    414278        ''' 
    415         Extract authors info from the moles file 
    416         ''' 
    417         logging.info('Retrieving authors info from moles file') 
    418          
    419         if self.dgMeta is None: 
    420             self.createMolesFile() 
    421              
     279        Extract authors info from the iso object 
     280        ''' 
     281         
    422282        logging.info("Extracting author info") 
    423         creators = "" 
    424         authors = "" 
    425         try: 
    426             # TODO: check this is the correct path for author data - NB, this is not obvious from example files 
    427             # nb, if this is correct, need to escape out the %20 and %3 characters else it doesn't work - see unescape.. fn 
    428             creators = self.dgMeta.dgMetadataRecord.dgDataEntity.dgDataRoles.dgDataCreator.dgRoleHolder.dgMetadataID.localIdentifier 
    429             logging.info("Found creator information - adding this to authors record") 
    430              
    431         except Exception, detail: 
    432             logging.info("Exception thrown whilst trying to find creator information:") 
    433             logging.info(detail) 
    434             logging.info("- this suggests document does not contain creator information.") 
    435  
    436         try: 
    437             authors = self.dgMeta.dgMetadataRecord.dgMetadataDescription.abstract.abstractOnlineReference.dgCitation.authors 
    438             logging.info("Found cited author information - adding this to authors record") 
    439              
    440         except Exception, detail: 
    441             logging.info("Exception thrown whilst trying to find cited author information:") 
    442             logging.info(detail) 
    443             logging.info("- this suggests document does not contain cited author information.") 
    444          
    445         self.authors = authors + " " + creators 
     283         
     284        #simple method to generate a space delimited list of authors from isoObject 
     285         
     286        self.authors = '' 
     287         
     288        #remember the double list return style.. 
     289        if self.isoDataModel.authors[0][0] == 'None': 
     290                logging.info("No author information present") 
     291        else: 
     292                for author in self.isoDataModel.authors[0]: 
     293                        self.authors = self.authors + ' ' +author 
     294         
    446295        return self.authors 
    447      
     296        
     297         
    448298     
    449299    def getParametersInfo(self): 
     
    451301        Extract parameters info from the moles file 
    452302        ''' 
    453         logging.info('Retrieving parameters info from moles file') 
    454          
    455         if self.dgMeta is None: 
    456             self.createMolesFile() 
    457              
    458         params = "" 
    459         try: 
    460             # TODO: check this is the correct path for parameters data - NB, this is not obvious from example files 
    461             parameters = self.dgMeta.dgMetadataRecord.dgDataEntity.dgDataSummary.dgParameterSummary.dgStdParameterMeasured 
    462             parameters_list = self.listify(parameters) 
    463             for parameter in parameters_list: 
    464                 if parameters.dgValidTerm: 
    465                     logging.info("Found parameter information - adding this to record") 
    466                     params += " " + parameters.dgValidTerm 
    467              
    468              
    469         except Exception, detail: 
    470             logging.info("Exception thrown whilst trying to find parameter information:") 
    471             logging.info(detail) 
    472             logging.info("- this suggests document does not contain parameter information.") 
    473          
    474         self.parameters = params 
    475         return self.parameters 
    476      
     303        logging.info('\nRetrieving parameters info from moles file\n') 
     304         
     305        self.params = "" 
     306         
     307        #remember the double list return style.. 
     308        if self.isoDataModel.parameters[0][0] == 'None': 
     309                logging.info("No parameter information present") 
     310        else: 
     311                for param in self.isoDataModel.parameters[0]: 
     312                        self.params = self.params + ' ' + param  
     313         
     314        return self.params 
     315         
    477316     
    478317    def getScopeInfo(self): 
    479318        ''' 
    480         Extract scope info from the moles file 
     319        Extract scope info from keywords in the input file 
    481320        ''' 
    482321        logging.info('Retrieving scope info from moles file') 
    483322         
    484         if self.dgMeta is None: 
    485             self.createMolesFile() 
    486              
     323        #TODO - put this in configuration file! 
     324        acceptedScopeVals = ['NERC_DDC','DDDP','MEDIN'] 
     325         
     326        scopeVals = self.isoDataModel.keywordsList 
     327         
    487328        scope = "" 
    488         try: 
    489             keywords = self.dgMeta.dgMetadataRecord.dgStructuredKeyword 
    490             logging.info("Found keyword information - parsing this for scope") 
    491  
    492             keywords_list = self.listify(keywords) 
    493             for keyword in keywords_list: 
    494                 if keyword.dgValidTermID: 
    495                     if keyword.dgValidTermID.ParentListID.strip().startswith(self.ndg_data_provider_vocab): 
    496                         logging.info("Found scope value - adding this to record") 
    497                         scope += " " + keyword.dgValidTerm.strip() 
    498              
    499         except Exception, detail: 
    500             logging.info("Exception thrown whilst trying to find scope information:") 
    501             logging.info(detail) 
    502             logging.info("- this suggests document does not contain scope information.") 
    503  
    504         # NB, to_tsvector will remove any underscores -leading to, e.g. NERC_DDC becoming tokenised as 'NERC' and 'DDC' 
    505         # - to avoid this, use the following delimiter 
     329         
     330        for keyword in scopeVals: 
     331                if keyword in acceptedScopeVals: 
     332                        scope += " " + keyword 
     333                 
    506334        self.scope = re.sub(r'_', 'UNDERSCORE', scope) 
     335         
    507336        return self.scope 
    508              
    509              
    510     def getTimeRangeData(self, dgMeta): 
    511         ''' 
    512         Parse an xml tree and add any time range data found 
    513         @param dgMeta: xml fragment for the time range 
    514         ''' 
    515         logging.info("Extracting time range info") 
    516         try: 
    517             dates = dgMeta.dgMetadataRecord.dgDataEntity.dgDataSummary.dgDataCoverage.dgTemporalCoverage.DateRange 
    518              
    519             if not dates: 
    520                 logging.info("No temporal info found for document") 
    521                  
    522             dates_list = self.listify(dates) 
    523             for date in dates_list: 
    524                 startdate=date.DateRangeStart 
    525                 enddate= date.DateRangeEnd 
    526                 if startdate==None or startdate=='None': 
    527                     startdate="null" 
    528                 if enddate==None or enddate=='None': 
    529                     enddate="null" 
    530                      
    531                 self.stData.addTimeRange(startdate, enddate) 
    532                 logging.info("Temporal info: startdate " + \ 
    533                              startdate + ", enddate " + enddate)  
    534         except Exception, detail: 
    535             logging.info("Document does not contain temporal info.") 
    536             logging.info(detail) 
    537  
    538          
    539     def getCoordData(self, dgMeta): 
    540         ''' 
    541         Parse an xml tree and add any coord data found 
    542         @param dgMeta: xml fragment for the bounding boxes 
    543         ''' 
    544         logging.info("Extracting bounding box info") 
    545         try: 
    546  
    547             bboxes = dgMeta.dgMetadataRecord.dgDataEntity.dgDataSummary.dgDataCoverage.dgSpatialCoverage.BoundingBox 
    548              
    549             if not bboxes: 
    550                 logging.info("No bounding box info found for document") 
    551                 return 
    552                  
    553             bbox_list=self.listify(bboxes) 
    554             #parse the list of coordinates 
    555             for bbox in bbox_list: 
    556                 north = self.parseCoord(bbox.LimitNorth, 'S', 'N') 
    557                 south = self.parseCoord(bbox.LimitSouth, 'S', 'N') 
    558                 east = self.parseCoord(bbox.LimitEast, 'W', 'E') 
    559                 west = self.parseCoord(bbox.LimitWest, 'W', 'E') 
    560                 self.stData.addCoords(north, south, east, west) 
    561                 logging.info("Spatial info: west= " + west + ",south " + south + ", east " + \ 
    562                     east + ", north " + north + "") 
    563                  
    564         except Exception, detail: 
    565             logging.warning("Problem encountered whilst parsing bounding box info - this may lead \n" + \ 
    566                             "to an incomplete set of metadata being ingested. \nDetail: %s" %detail) 
    567  
    568  
    569     def parseCoord(self, coordValue, minField, maxField): 
    570         ''' 
    571         Take a coordinate value extracted from a molefile bbox limit - together with  
    572         the appropriate max/min limits and extract the correct value from it 
    573         @param coordValue: the contents of the bbox limit tage 
    574         @param minField: the expected min field of the coord range - i.e. 'W' or 'S' 
    575         @param maxField: the expected max field of the coord range - i.e. 'E' or 'N' 
    576         @return: coord - the value of the coordinate as a string    
    577         ''' 
    578         logging.debug("Parsing document coordinates") 
    579         try: 
    580             coord = coordValue.strip() 
    581             if coord.endswith(maxField): 
    582                 coord=coordValue.split(maxField)[0] 
    583             elif coord.endswith(minField): 
    584                 if coord.startswith('-'): 
    585                     coord = coordValue.split(minField)[0] 
    586                 else: 
    587                     coord = "-" + coordValue.split(minField)[0] 
    588      
    589             return '%s' % float(coord) 
    590         except: 
    591             raise SyntaxError, 'Will not process File: contains incorrect bounding box limit: ' + coordValue 
    592  
    593              
    594     def hasNullCoords(): 
    595         ''' 
    596         Checks a record to determine whether it has any coordinates set to null 
    597         ''' 
    598         if str(self.west)=='null' or \ 
    599             str(self.south)=='null' or \ 
    600             str(self.east)=='null' or \ 
    601             str(self.north)=='null': 
    602             return True; 
    603         else: 
    604             return False; 
    605          
     337      
     338        
     339    ''' 
     340    Method to parse & check temporal coverage information extracted from the original ISO object 
     341    ''' 
     342    def parseTemporalInfo(self,timeData): 
     343         
     344        logging.info("Parsing Temporal information from original ISO object") 
     345         
     346        TimeRange = [] 
     347        if len(timeData) == 0: 
     348                        logging.info("No temporal coverage elements found - assuming no temporal data available") 
     349                 
     350        else: 
     351                for time in timeData: 
     352                        start = time['start'] 
     353                        end = time['end'] 
     354                 
     355                        if start is None: 
     356                           startDate = "null" 
     357                        else: 
     358                           startDate = start 
     359                         
     360                        if end is None: 
     361                           endDate = "null" 
     362                        else: 
     363                           endDate = end 
     364                         
     365                        if (end is None) and (start is None): 
     366                           logging.info("No temporal coverage elements found - assuming no temporal data available") 
     367                        else: 
     368                                TimeRange.append({'start':startDate,'end':endDate}) 
     369                                                         
     370                         
     371                        logging.info("Time range data found; start: " + startDate + " end: " + endDate) 
     372                                 
     373                return TimeRange 
     374                                 
     375     
     376    ''' 
     377    Method to parse & check Spatial coverage information extracted from the original ISO object 
     378    ''' 
     379    def parseSpatialInfo(self,spatialData): 
     380         
     381        logging.info("Parsing Spatial information from original ISO object") 
     382         
     383        SpatialCoords = [] 
     384        if len(spatialData) == 0: 
     385                        logging.info("No spatial coverage elements found - assuming no spatial data available") 
     386                         
     387        else: 
     388                cntr = 1 
     389                for coords in spatialData: 
     390                                if (coords['north'] is None) or (coords['north'] == 'None'): 
     391                                        north = "null" 
     392                                else: 
     393                                    north = coords['north'] 
     394                                     
     395                                if (coords['south'] is None) or (coords['south'] == 'None'): 
     396                                        south = "null" 
     397                                else: 
     398                                    south = coords['south'] 
     399                                     
     400                                if (coords['east'] is None) or (coords['east'] == 'None'): 
     401                                    east = "null" 
     402                                     
     403                                else: 
     404                                    east = coords['east'] 
     405                                     
     406                                if (coords['west'] is None) or (coords['west'] == 'None'): 
     407                                    west = "null" 
     408                                     
     409                                else: 
     410                                    west = coords['west'] 
     411                                     
     412                                #check the coordinates - NOTE now using MEDIN based coords these need to be ISO defined lon/lats in decimal degrees? 
     413                                #if not JUST WARN - DIF's might have UKNG coords.. 
     414                                if (north > 90) or (north < -90) or (south > 90) or (south < -90): 
     415                                        logging.warn("*****************************************************************") 
     416                                        logging.warn("*** WARNING: latitude coordinates outside of accepted bounds! ***") 
     417                                        logging.warn("*****************************************************************") 
     418                                         
     419                                if (west > 180) or (west < -180) or (east > 180) or (east < -180): 
     420                                        logging.warn("*****************************************************************") 
     421                                        logging.warn("*** WARNING: longitude coordinates outside of accepted bounds! ***") 
     422                                        logging.warn("*****************************************************************") 
     423                                         
     424                                     
     425                                SpatialCoords.append({'west':west,'east':east,'north':north,'south':south}) 
     426                                 
     427                                logging.info("( " + str(cntr) + ") Spatial Coords found....") 
     428                                logging.info("................ east: " + east) 
     429                                logging.info("................ west: " + west) 
     430                                logging.info("................ north: " + north) 
     431                                logging.info("................ south: " + south) 
     432                                cntr += 1 
     433                                 
     434        return SpatialCoords 
     435                 
     436                         
     437         
     438        
     439        
     440         
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/Utilities.py

    r6048 r6544  
    250250                        return '{http://www.oceannet.org/mdip/xml}' 
    251251 
     252 
     253''' 
     254Class to perform a non-NDG based xquery transformation - this has been changed to a class so is accessible from all ingest classes. 
     255''' 
     256class xqueryTransformation: 
     257         
     258        def __init__(self,metadataFileLoc,repositoryName,metadataID,metadataFilename, saxonJar): 
     259                ''' 
     260                   Setup the xquery 
     261                ''' 
     262                 
     263                #this should pick up the relevant xquery in ndgCommon via that defined in the config file 
     264                 
     265                logging.info("Setting up xquery transformation object") 
     266                 
     267                                 
     268                self._repository_local_id = repositoryName #'neodc.nerc.ac.uk' 
     269                self.discovery_id = metadataID 
     270                self._local_id = metadataFilename 
     271                self._repository = repositoryName #'neodc.nerc.ac.uk' 
     272                self.metadataFileLoc = metadataFileLoc 
     273                self._saxonJarFile = saxonJar 
     274                                 
     275                 
     276        def runXquery(self, xqueryType): 
     277                ''' 
     278                run the xquery! 
     279                ''' 
     280                 
     281                self.xQueryType = xqueryType 
     282                 
     283                logging.info("Running the xquery for type: " + self.xQueryType) 
     284                 
     285                self.xqueryLib = ndgResources()          
     286                 
     287                xquery = self.xqueryLib.createXQuery(self.xQueryType,self.metadataFileLoc, self._repository_local_id, self._local_id) 
     288       
     289                # sort out the input ID stuff                            
     290                xquery=xquery.replace('Input_Entry_ID', self.discovery_id) 
     291                xquery=xquery.replace('repository_localid', self._repository) 
     292 
     293        # strip out the eXist reference to the libraries; these files should be available in the 
     294                # running dir - as set up by oai_ingest.py 
     295                xquery=xquery.replace('xmldb:exist:///db/xqueryLib/Vocabs/', '') 
     296                xquery=xquery.replace('xmldb:exist:///db/xqueryLib/Utilities/', '') 
     297 
     298        # write the query to file, to make it easier to input 
     299        # NB, running directly at the command line leads to problems with the interpretation of $ characters 
     300                xqFile = "currentQuery_" + self.xQueryType + ".xq"  
     301                 
     302                FileUtilities.createFile(xqFile, xquery) 
     303                 
     304        # Now do the transform 
     305                os.putenv ('PATH', ':/usr/java/jdk1.5.0_03/bin:/usr/java/jdk1.5.0_03:/usr/java/jdk1.5.0_03/lib/tools.jar:/usr/local/WSClients/OAIBatch:/usr/local/exist-client/bin:/bin:/usr/bin:.') 
     306                xqCommand = "java -cp %s net.sf.saxon.Query %s !omit-xml-declaration=yes" %(self._saxonJarFile, xqFile) 
     307                                 
     308                logging.debug("Running saxon command: " + xqCommand) 
     309                pipe = os.popen(xqCommand + " 2>&1") 
     310                output = pipe.read() 
     311                status = pipe.close() 
     312 
     313                if status is not None: 
     314                        logging.error("Could not execute the DIF to StubISO xquery!!!") 
     315                        raise SystemError, 'Failed at running the XQuery' 
     316                 
     317                 
     318                # now remove the temp xquery file 
     319                '''status = os.unlink(xqFile) 
     320                if status is not None: 
     321                        raise OSError, 'Failed to remove the temporary xquery file, ' + xqFile''' 
     322 
     323                logging.info("Transform completed successfully") 
     324                 
     325                return output 
     326 
     327 
    252328''' 
    253329Class operating the identity transform of new ingest docs to change all urls to include a redirect via the ndg redirect service 
    254330so can record all traffic from discovery service elsewhere.  Rewrites back to original filename so can continue with ingest 
     331 
     332**** DEPRECATED - now use elementtree methodology to do this.....  ******* 
     333 
    255334''' 
    256335class ndgRedirectTransform: 
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/abstractdocumentingester.py

    r6367 r6544  
    1212import ndg.common.src.lib.fileutilities as FileUtilities 
    1313from ndg.common.src.clients.reldb.postgres.postgresclient import PostgresClient as pgc 
    14 from Utilities import idget, IngestTracking 
    15 from Utilities import DatasetBasicParameters_MEDIN_v01,DatasetBasicParameters_Original 
    16 from Utilities import ndgRedirectTransform,redirectUrlChanger 
     14from PostgresRecord import PostgresRecord 
     15from PostgresDAO import PostgresDAO 
     16from Utilities import idget 
     17from Utilities import ndgRedirectTransform,redirectUrlChanger,xqueryTransformation 
    1718from DeleteRecord import DeleteRecord 
    1819import datetime,time 
    1920from ndg.common.src.models.ndgObject import ndgObject 
    2021from ndg.common.src.lib.ndgresources import ndgResources 
     22from ExtractISO import ExtractISO 
     23import inspect 
     24 
     25#temp 
    2126from AbstractFormatIngester_original import AbstractFormatIngesterOriginal 
    22 from ndg.common.src.models.ndgObject import ndgObject 
    23  
    24 SAXON_JAR_FILE = '/disks/glue1/sdonegan/NDG3_workspace/buildouts/oai_document_ingester_MEDIN/ingestAutomation-upgrade/OAIBatch/lib/saxon9.jar' 
    25          
    2627 
    2728class AbstractDocumentIngester(object): 
     
    3233        ''' 
    3334        lineSeparator = "------------------------------" 
    34                          
     35                 
    3536        # The directory to put things for a tape backup (should already exist) 
    36         BACKUP_DIR = '/disks/glue1/oaiBackup/' 
    37                  
    38         #keep ndg3beta service for testing MEDIN upgrades 
    39         NDG_redirect_URL = 'http://ndg3beta.badc.rl.ac.uk/URL_redirect_NDG3/ndgURLredirect/redirect?url=' 
    40          
    41          
    42         #NDG_redirect_URL = 'http://triton.badc.rl.ac.uk/URL_redirect_NDG3/ndgURLredirect/redirect?url=' 
    43          
    44          
    45  
     37        BACKUP_DIR = '/home/badc/discovery_docs/ingestDocs/backup/' 
     38         
     39        #NDG_redirect_URL = 'http://ndg3beta.badc.rl.ac.uk/URL_redirect_NDG3/ndgURLredirect/redirect?url=' 
     40                 
    4641        def _setupCmdLineOptions(self): 
    4742                ''' 
     
    5146                 
    5247                # check for verbose option 
    53                  
    5448                try: 
    5549                        opts, args = getopt.getopt(sys.argv[1:], "vd") 
     
    7468                # set up any keywords on the object 
    7569                # NB, be careful to keep the instance variables the same name as the keywords! (not also feed keywords also in here) 
     70                checkConfInArgs = False 
    7671                for arg in args: 
    7772                         
    78                         keywordArgs=['ingestFromDate','interval','individualFile','interval','ingestFromDate','eXistDBHostname','eXistPortNo','dataCentrePoll'] 
    79                          
    80                          
     73                        keywordArgs=['ingestFromDate','interval','individualFile','interval','ingestFromDate','eXistDBHostname','eXistPortNo','dataCentrePoll','ingestConfigFile']                                               
    8174                         
    8275                        bits = arg.split('=') 
     
    8679                                elif bits[0] == keywordArgs[1]: 
    8780                                        self.setPollInterval(bits[1]) 
     81                                elif bits[0] == keywordArgs[8]: 
     82                                        print " - Running with specified config file!" 
     83                                        self.setOaiConfigFile(bits[1]) 
     84                                        checkConfInArgs = True 
    8885                                elif bits[0] == keywordArgs[2]: 
    8986                                        print " - Running in single file ingestion mode!" 
     
    9592                                        setattr(self, bits[0], bits[1]) 
    9693                         
     94                if checkConfInArgs is False: 
     95                        print "\nWARNING: You must now include the ingestConfigFile arguement for successful operation" 
     96                        sys.exit(2) 
     97                 
    9798                print self.lineSeparator 
    9899                 
     
    113114                # add ch to logger 
    114115#               self.logger.addHandler(ch) 
     116                 
    115117                return args 
    116118 
     
    123125                ''' 
    124126                logging.info("Retrieving identifier for metadata record " + filename) 
     127         
    125128                xml=file(filename).read() 
     129                 
    126130                ID = idget(xml) 
     131                 
    127132                return ID 
    128133         
    129134         
    130          
    131                          
     135        def addFileToPostgresDB(self, filename): 
     136                ''' 
     137                Add a file to the postgres DB - extracting and storing all the required 
     138                data in the process 
     139                @param filename: full path of file to add to postgres DB 
     140                ''' 
     141                logging.info("Adding file, " + filename + ", to postgres DB") 
     142                 
     143                numSlash = len(filename.split('/')) 
     144                                 
     145                shortFilename = filename.split('/')[numSlash - 1] 
     146                 
     147                self.recordAttemptToIngestDiscoveryID = ""                               
     148                 
     149                # first of all create a PostgresRecord - this object represents all the data required 
     150                # for a DB entry 
     151                dao = None 
     152                 
     153                try: 
     154                         
     155                        #set up iso xml object - format indicatees the ISO profile (including dif2iso conversions)                                               
     156                        self.isoDataModel = ExtractISO(filename,self._isoClass[self._datacentre_format]) 
     157                         
     158                         
     159                        if self.isoDataModel.createISOdataStructure() is True: 
     160                                logging.info("ISO extractor worked fine!") 
     161                         
     162                         
     163                        elif self.isoDataModel.createISOdataStructure() is True: 
     164                                logging.error ("Something wrong with ISO extractor... (ExtractISO returned False: xml access problem?)")                         
     165                                #sys.exit() # TODO fix these 
     166                                return 
     167                        else: 
     168                                logging.error("Something SERIOUSELY wrong with extractor (couldnt get at ExtractISO class)")                     
     169                                #sys.exit() 
     170                                return 
     171                                 
     172                        #record whats bout to be ingestd 
     173                        self.recordAttemptToIngestDiscoveryID = self.isoDataModel.datasetID[0][0] 
     174                         
     175                        #In new ingest system all vals parsed from iso xml are returned as either lists of dictionaries 
     176                         
     177                        #record whats attempting to be ingested          
     178                        record = PostgresRecord(filename, self._NDG_dataProvider,self._datacentre_groups, self._datacentre_namespace, 
     179                                                                self.isoDataModel,self._xq, self._datacentre_format, self._xqueryConversionsExceptions,  
     180                                                                self._xqueryConversions,self._saxonJarFile, self._xqueryDocTypes, self.originalXMLdoc, stubIso = self.isoXML)                    
     181                         
     182                        # Now create the data access object to interface to the DB                       
     183                        dao = PostgresDAO(record, self.isoDataModel ,self.discovery_dir , pgClient = self.pgc ) 
     184                         
     185                        # Finally, write the new record 
     186                        # 0 if failed, 1 if update, 2 if create 
     187                        returnCode = dao.createOrUpdateRecord()  
     188                                                 
     189                        if returnCode == 2: 
     190                                self._no_files_ingested += 1 
     191                                 
     192                        elif returnCode == 1: 
     193                                self._no_files_changed += 1 
     194                                 
     195                         
     196                except: 
     197                         
     198                         
     199                        #if error encountered, add to failure lisr 
     200                        logging.error("Could not update: " + filename)                   
     201                        originalRecordFilename = self.inputFileOrigFinal[shortFilename] 
     202                        self.updateFailList.append(originalRecordFilename) 
     203                         
     204                        logging.error("Exception thrown - detail: ") 
     205                        errors = sys.exc_info() 
     206                        logging.error(errors) 
     207                        self._error_messages += "%s\n" %str(errors[1]) 
     208                         
     209                        if dao: 
     210                                logging.info("Removing record and its associated info from DB") 
     211                                logging.info("- to allow clean ingestion on rerun") 
     212                                try: 
     213                                        dao.deleteOriginalRecord() 
     214                                except: 
     215                                        logging.error("Problem encountered when removing record: ") 
     216                                        logging.error(sys.exc_info()) 
     217                                        logging.error("NB, this record will need to be cleared manually from DB to ensure all relevant data is ingested") 
     218 
     219                        self._no_problem_files += 1 
     220                         
     221                        logging.info("Continue processing other files") 
     222                         
     223                return self.recordAttemptToIngestDiscoveryID 
     224                         
     225         
     226        def getProcessingConfig(self,configFilePath): 
     227                 
     228                ''' 
     229                Fed up with messing about with hardcoded directory paths.   
     230                This method to get relevant values out of the oai_document_ingester.config file 
     231                 
     232                Returns a dictionary of values with keys: 
     233                 
     234                #directory in which the code resides 
     235                code_directory /home/badc/buildouts/oai_document_ingester/ingestAutomation-upgrade/OAIBatch/ 
     236 
     237                #base directory in which metadata is extracted to and converted to 
     238                base_directory /home/badc/discovery_docs/ingestDocs/ 
     239 
     240                #directory in which to write reports to 
     241                reporting_directory /home/badc/discovery_docs/ingestDocs/data/ 
     242 
     243                #path to the passwords file 
     244                passwords_file /home/badc/buildouts/oai_document_ingester/ingestAutomation-upgrade/OAIBatch/passwords.txt 
     245 
     246                #datacentre config file directory path 
     247                datcentre_configs /home/badc/buildouts/oai_document_ingester/ingestAutomation-upgrade/OAIBatch/datacentre_config/ 
     248                ''' 
     249                 
     250                # Check this file exists; if not, assume an invalid datacentre has been specified 
     251                 
     252                if not os.path.isfile(configFilePath): 
     253                    sys.exit("ERROR: Could not find the processing config file") 
     254                     
     255                processingConfig = {} 
     256                     
     257                processing_config_file = open(configFilePath, "r") 
     258                 
     259                for line in processing_config_file.readlines(): 
     260                        words  = string.split(line) 
     261                        if len(words) == 0: 
     262                                continue 
     263                        elif words[0] == 'code_directory': 
     264                                processingConfig['code_directory'] = words[1] 
     265                                                                                                 
     266                        elif words[0] == 'base_directory': 
     267                                processingConfig['base_directory'] = words[1] 
     268                                 
     269                        elif words[0] == 'reporting_directory': 
     270                                processingConfig['reporting_directory'] = words[1] 
     271                                 
     272                        elif words[0] == 'passwords_file': 
     273                                processingConfig['passwords_file'] = words[1] 
     274                                 
     275                        elif words[0] == 'datcentre_configs': 
     276                                processingConfig['datcentre_configs'] = words[1] 
     277                                         
     278                        elif words[0] == 'NDG_redirect_URL': 
     279                                processingConfig['NDG_redirect_URL'] = words[1] 
     280                                 
     281                        elif words[0] == 'ingestConfig': 
     282                                if not os.path.isfile(words[1]): 
     283                                        sys.exit("ERROR: Could not find the Database configuration file (ingest.config)!!") 
     284                                else: 
     285                                        processingConfig['ingestConfig'] = words[1] 
     286                                 
     287                        elif words[0] == 'acceptedFormats': 
     288                                processingConfig['acceptedFormats'] = words[1] 
     289                                 
     290                        elif words[0] == 'saxonJarFile': 
     291                                if not os.path.isfile(words[1]): 
     292                                        sys.exit("ERROR: Could not find the SAXON JAR file!!") 
     293                                else: 
     294                                        processingConfig['saxonJarFile'] = words[1] 
     295                        elif words[0] == 'xpathIsoClass': 
     296                                 
     297                                #build a dictionary with format as the key                               
     298                                isoClass = words[1].split(":")                           
     299                                 
     300                                if 'xpathIsoClass' not in processingConfig.keys(): 
     301                                        processingConfig['xpathIsoClass'] = {isoClass[0]:isoClass[1]} 
     302                                else: 
     303                                        temp = processingConfig['xpathIsoClass']                                         
     304                                        temp.update({isoClass[0]:isoClass[1]}) 
     305                                        processingConfig['xpathIsoClass'] = temp 
     306                                 
     307                        elif words[0] == 'xqueryStubIsoGen': 
     308                                 
     309                                #build a dictionary with format as the key 
     310                                isoClass = words[1].split(":") 
     311                                processingConfig['xqueryStubIsoGen'] = {isoClass[0]:isoClass[1]}   
     312                                 
     313                        elif words[0] == 'xqueryConversions': 
     314                                 
     315                                #build a list of acceptable formats to convert into from ISO (except where format matches input format 
     316                                processingConfig['xqueryConversions'] = words[1].split(",") 
     317                                 
     318                        elif words[0] == 'exceptXqConv': 
     319                                 
     320                                #build a dictionary with format as the key 
     321                                xqClass = words[1].split(":") 
     322                                processingConfig['exceptXqConv'] = {xqClass[0]:xqClass[1]}  
     323                                 
     324                        elif words[0] == 'xqDocTypes': 
     325                                 
     326                                #build a dictionary with format as the key 
     327                                xqClass = words[1].split(":") 
     328                                 
     329                                if 'xqDocTypes' not in processingConfig.keys(): 
     330                                        processingConfig['xqDocTypes'] = {xqClass[0]:xqClass[1]} 
     331                                else: 
     332                                        temp = processingConfig['xqDocTypes']                                    
     333                                        temp.update({xqClass[0]:xqClass[1]}) 
     334                                        processingConfig['xqDocTypes'] = temp 
     335                                         
     336                processing_config_file.close() 
     337                         
     338                return processingConfig 
     339         
    132340         
    133341        def getConfigDetails(self, datacentre): 
     
    147355                self._datacentre_namespace = "" 
    148356                self._NDG_dataProvider = False 
    149  
    150                 datacentre_config_filename = 'datacentre_config/' + datacentre + "_config.properties" 
    151                 logging.info("Retrieving data from datacentre config file, " + datacentre_config_filename) 
    152                  
    153  
     357                self._IngestViaFeed = False # need to distinguish between oai and feed ingest 
     358                 
     359                 
     360                #note changed to production buildout path 
     361                #self._datacentre_config_filename = '/home/badc/buildouts/oai_document_ingester/ingestAutomation-upgrade/OAIBatch/datacentre_config/' + datacentre + "_config.properties" 
     362                 
     363                #fed up with this rubbish causing problems - use a normal file opener. 
    154364                #file = pkg_resources.resource_string('OAIBatch', datacentre_config_filename) 
    155                 file = open(datacentre_config_filename,"r") 
    156                  
    157                 for line in file.readlines(): 
    158                         words = line.split() 
     365                 
     366                 
     367                self._datacentre_config_filename = self._code_dir + 'datacentre_config/' + datacentre + "_config.properties" 
     368                logging.info("Retrieving data from datacentre config file, " + self._datacentre_config_filename) 
     369                 
     370                # Check this file exists; if not, assume an invalid datacentre has been specified 
     371                if not os.path.isfile(self._datacentre_config_filename): 
     372                    sys.exit("ERROR: Could not find the config file; either this doesn't exist or the datacentre " \ 
     373                        "specified (%s) is invalid\n" %datacentre) 
     374                     
     375                 
     376                datacentre_config_file = open(self._datacentre_config_filename, "r") 
     377                 
     378                for line in datacentre_config_file.readlines(): 
     379                        words  = string.split(line) 
    159380                        if len(words) == 0: 
    160381                                continue 
     
    169390                        elif words[0] == 'NDG_dataProvider': 
    170391                                self._NDG_dataProvider = True 
    171                  
     392                        elif words[0] == 'feed': 
     393                                self._IngestViaFeed = True 
     394                         
     395                datacentre_config_file.close() 
     396                 
     397                #stop ingest on this datacentre if process thread is OAI and the config says FEED 
     398                if ((self.processThread == 'OAI') and self._IngestViaFeed): 
     399                        sys.exit("Trying to ingest a FEED based centre.  Better stop now before it all gets a bit tricky!") 
     400                                                 
    172401                if self._harvest_home == "": 
    173402                    sys.exit("Failed at getting harvested records directory stage. datacentre config file tried = %s" %datacentre_config_filename) 
     
    195424                        logging.info("Datacentre is not classified as an NDG data provider") 
    196425                logging.info(self.lineSeparator) 
    197  
    198  
    199         def convertDIFtoISO(self,metadataFileLoc,repositoryName,metadataID,metadataFilename): 
    200                 ''' 
    201                    New to MEDIN ingest Upgrade: 
    202                    This converts the still supported DIF to ISO format - all extractions will come from ISO,  
    203                    whether original ISO format or conversions to ISO.  
    204                     
    205                    Uses the new "dif2stubISO" xquery 
    206                 ''' 
    207                 xQueryType = 'dif2stubISO' 
    208                  
    209                 self._repository_local_id = repositoryName #'neodc.nerc.ac.uk' 
    210                 self.discovery_id = metadataID 
    211                 self._local_id = metadataFilename 
    212                 self._repository = repositoryName #'neodc.nerc.ac.uk' 
    213                                  
    214                 self.xqueryLib = ndgResources()                                                  
    215                 xquery = self.xqueryLib.createXQuery(xQueryType,metadataFileLoc, self._repository_local_id, self._local_id) 
    216        
    217                 # sort out the input ID stuff 
    218                 xquery=xquery.replace('Input_Entry_ID', self.discovery_id) 
    219                 xquery=xquery.replace('repository_localid', self._repository) 
    220  
    221         # strip out the eXist reference to the libraries; these files should be available in the 
    222                 # running dir - as set up by oai_ingest.py 
    223                 xquery=xquery.replace('xmldb:exist:///db/xqueryLib/Vocabs/', '') 
    224                 xquery=xquery.replace('xmldb:exist:///db/xqueryLib/Utilities/', '') 
    225  
    226         # write the query to file, to make it easier to input 
    227         # NB, running directly at the command line leads to problems with the interpretation of $ characters 
    228                 xqFile = "currentQuery" + xQueryType + ".xq"  
    229                  
    230                 FileUtilities.createFile(xqFile, xquery) 
    231                                  
    232                 # ensure the jar file is available - NB, this may be running from a different 
    233         # location - e.g. the OAIInfoEditor.lib.harvester - and this won't have the 
    234         # saxon file directly on its filesystem 
    235                  
    236                 #jarFile = pkg_resources.resource_filename('OAIBatch', SAXON_JAR_FILE) 
    237                 jarFile = SAXON_JAR_FILE 
    238         # Now do the transform 
    239                 os.putenv ('PATH', ':/usr/java/jdk1.5.0_03/bin:/usr/java/jdk1.5.0_03:/usr/java/jdk1.5.0_03/lib/tools.jar:/usr/local/WSClients/OAIBatch:/usr/local/exist-client/bin:/bin:/usr/bin:.') 
    240                 xqCommand = "java -cp %s net.sf.saxon.Query %s !omit-xml-declaration=yes" %(jarFile, xqFile) 
    241                                  
    242                 logging.debug("Running saxon command: " + xqCommand) 
    243                 pipe = os.popen(xqCommand + " 2>&1") 
    244                 output = pipe.read() 
    245                 status = pipe.close() 
    246  
    247                 if status is not None: 
    248                         raise SystemError, 'Failed at running the XQuery' 
    249                  
    250                  
    251                 # now remove the temp xquery file 
    252                 '''status = os.unlink(xqFile) 
    253                 if status is not None: 
    254                         raise OSError, 'Failed to remove the temporary xquery file, ' + xqFile''' 
    255  
    256                 logging.info("Transform completed successfully") 
    257  
    258                 return output 
    259                                  
    260  
    261  
    262         def _convertIngestFiles(self, originals_dir, discovery_dir, stubIso_dir, format): 
     426                 
     427                 
     428        def _convertIngestFiles(self, originals_dir, discovery_dir, format): 
    263429                ''' 
    264430                Processes/renames the files (changed 08/01/07 to get id from inside file) 
     
    284450                        original_filename = originals_dir + filename 
    285451                         
    286                                                  
    287                         #convert urls within original xml input file to NDG redirect URLS                                                
    288                         #call new class in Utilities.py --will replace original file... 
    289                         redirectUrlChanger(original_filename,original_filename,self._datacentre_format, self.NDG_redirect_URL) 
    290                          
    291                         if format == 'DIF': 
    292                                  
    293                                 #NOTE MDIP now deprecated!!  easier to leave all those crappy dif or mdip code but will mainly be replaced anyway 
    294                                  
    295                                 logging.info("Converting DIF to stub ISO...") 
    296                                                                  
     452                        #if importing old dif format need to do a few extra things: 1. deal with urls to be redirected.  2. Convert to stub ISO so can continue with ISO ingest! 
     453                        if format == 'DIF_9.4': 
     454                                                         
     455                                logging.info("Converting DIF to stub ISO...")                                    
     456                                 
     457                                #if DIF still need to convert URL's using the old method so when requesting DIF in original format we still have correct redirect urls.... 
     458                                redirectUrlChanger(original_filename,original_filename,self._datacentre_format, self._ndgRedirectURL) 
     459                                                                                                                 
    297460                                #gets the metadata id from the xml 
    298461                                metadataID=self.getID(original_filename) 
    299                                  
     462                                                                 
    300463                                repositoryName = self._datacentre_namespace 
    301464                                 
    302465                                #get the name of the file to be used in the xquery 
    303466                                metadataFilename = filename.replace('.xml', '') 
    304                                  
     467                                                                 
    305468                                #where is the file to be ingested located? 
    306469                                metadataFileLoc = originals_dir 
    307470                                 
    308471                                #generate a new stubISO filename 
    309                                 isoFormat= "stubISO" 
    310                                  
     472                                self.isoFormat= "stubISO" 
     473                                                                 
     474                                #self.isoXML = self.convertDIFtoISO(metadataFileLoc,repositoryName,metadataID,metadataFilename) 
     475                                self.xqueryTransformation = xqueryTransformation(metadataFileLoc,repositoryName,metadataID,metadataFilename,self._saxonJarFile) 
     476                                 
     477                                #get hold of the xml for the transformed ISO 
     478                                self.isoXML = self.xqueryTransformation.runXquery(self._dif2isoXquery) 
     479                                 
     480                                #need to get hold original format XML too (so can put directly into "transformed" docs section... 
     481                                self.originalXMLdoc = '' 
     482                                 
     483                                try: 
     484                                        logging.info("Extracting original input file into variable for input into original format in transformed docs table") 
     485                                        self.originalXMLdoc = file(original_filename).read() 
     486                                         
     487                                except: 
     488                                        logging.warn("Could not extract original file to local variable!") 
     489                                 
     490                                 
     491                                #Back to main stream of ISO ingest 
     492                                if self._NDG_dataProvider: 
     493                                                                 
     494                                        #changed so new new NDG3 discovery can pick up Discoveru View URL's correctly?  (why should it be different to previous?) 
     495                                        new_filename = discovery_dir + self._datacentre_namespace + "__" + self.isoFormat + "__"+ metadataFilename.replace(":", "-")+".xml" 
     496                                        new_filename_short = self._datacentre_namespace + "__" + self.isoFormat + "__" + metadataFilename.replace(":", "-")+".xml" 
     497                                 
     498                                else: 
     499                                 
     500                                        ident = ident.replace(":", "-") 
     501                                        ident = ident.replace("/", "-") 
     502                                 
     503                                        new_filename = discovery_dir + "/" +self._datacentre_namespace+ "__"+ self.isoFormat + "__"+ ident +".xml" 
     504                                        new_filename_short = self._datacentre_namespace+ "__"+ self.isoFormat + "__"+ ident +".xml" 
     505                                 
     506                                 
     507                                #now create this stub ISO file on system so can access it 
     508                                self.stubIsoFile = discovery_dir + new_filename_short    
     509                                                                 
     510                                FileUtilities.createFile(self.stubIsoFile, self.isoXML) 
     511                                 
     512                                logging.info("Stub ISO file created - at %s" %discovery_dir) 
     513                                 
     514                         
     515                        #all other ISO formats/profiles to deal with. 
     516                        else:                            
     517                                isoFormat = format 
     518                                 
     519                                #Back to main stream of ISO ingest 
    311520                                if self._NDG_dataProvider: 
    312521                                                                 
     
    324533                                 
    325534                                 
    326                                 self.isoXML = self.convertDIFtoISO(metadataFileLoc,repositoryName,metadataID,metadataFilename) 
    327                                  
    328                                 #now create this stub ISO file on system so can access it 
    329                                 self.stubIsoFile = stubIso_dir + new_filename_short 
    330                                 FileUtilities.createFile(self.stubIsoFile, self.isoXML) 
    331                         logging.info("Stub ISO file created - at %s" %stubIso_dir) 
    332                          
    333                         #elif format == 'MEDIN_v0.1': 
    334                  
    335                                 #basicParameters=DatasetBasicParameters_MEDIN_v01(original_filename,self._datacentre_format) 
    336                               
    337                                  
    338535                        logging.info("original file = " + original_filename) 
    339536                        logging.info("newfile = " + new_filename) 
     
    344541                        self.inputFileOrigFinal[new_filename_short]=filename 
    345542                         
     543                        ''' 
     544                        TODO: do we need this namespace corrector anymore as not using MOLES? 
     545                 
    346546                        # now correct any namespace issues 
    347547                        try: 
     
    352552                                logging.info("Continue with next file") 
    353553                                continue 
     554                        ''' 
    354555                        numfilesproc += 1 
    355556                 
     557                         
    356558                logging.info("File renaming and converting completed") 
    357559                logging.info(self.lineSeparator) 
     560                 
    358561                         
    359562                return numfilesproc 
    360  
    361                  
     563         
     564         
    362565        def _getPostgresDBConnection(self): 
    363566                ''' 
     
    366569                 
    367570                logging.debug("Setting up connection to postgres DB") 
    368                 self.pgc = pgc(configFile = '/usr/local/ndg-oai-info-editor/ingest.config') 
     571                #self.pgc = pgc(configFile = '/usr/local/ndg-oai-info-editor/ingest.config')  
     572                 
     573                 
     574                self.pgc = pgc(configFile = self._databaseConfigurationFile) 
    369575                logging.info("Postgres DB connection now set up") 
    370576 
     
    393599                ''' 
    394600                logging.info("Setting up ingest directories for data centre, '%s'" %self.dataCentre) 
     601                 
     602                 
    395603                data_dir = self._base_dir + "data/" + self.dataCentre  # dir relating to the specified dataCentre docs 
    396604                 
    397605                # the following dirs define where the specific documents should go 
    398                 self.originals_dir = data_dir + "/oai/originals/" 
     606                self.originals_dir = data_dir + "/oai/originals/" # copy of original 
    399607                self.discovery_dir = data_dir + "/discovery/" 
    400                 self.stubISO_dir = data_dir + "/stub_iso/" 
     608                #self.stubISO_dir = data_dir + "/stub_iso/" 
    401609                 
    402610                # Create/clear the 'in' and 'out' directories 
    403611                FileUtilities.setUpDir(self.originals_dir) 
    404612                FileUtilities.setUpDir(self.discovery_dir) 
    405                 FileUtilities.setUpDir(self.stubISO_dir) 
    406613                 
    407614                logging.info("Ingest directories for data centre set up") 
     
    416623                @param feed: boolean, False if calling func is feedDocumentIngester, True - all other 
    417624                ''' 
    418                                  
    419                 numfilesproc = self._convertIngestFiles(self.originals_dir, self.discovery_dir, self.stubISO_dir, format) 
    420                                  
     625                 
     626                 
     627                numfilesproc = self._convertIngestFiles(self.originals_dir, self.discovery_dir, format) 
     628                 
     629                 
    421630                filenames = os.listdir(self.discovery_dir) 
    422                  
     631                                 
    423632                #generate a list of files ALREADY in database so can compare with what has been ingested 
    424633                sqlCmd = "select discovery_id from original_document where discovery_id like '%" + self._datacentre_namespace + "%'"             
    425                  
    426                  
     634                                 
    427635                filePresentListArr = self.pgc.runSQLCommand(sqlCmd) 
    428636                filesPresentList=[] 
     637         
     638                 
    429639                if filePresentListArr: 
    430640                        for fileArr in filePresentListArr: 
     
    434644         
    435645                #create list to to hold files ingest failed on. 
    436                 self.thisIngestMonitor = IngestTracking() 
    437                  
    438                 #self.updateFailList = [] 
    439                 #self.deletedFailList = [] 
    440                 #no_problem_files = 0 
     646                self.updateFailList = [] 
     647                self.deletedFailList = []                                
    441648                 
    442649                for filename in filenames: 
     
    444651                         
    445652                        if os.path.isfile(fullPath): 
    446  
    447                                 #ingest file intelligently according to input formatfilename,datacentre_format,datacentre_groups,datacentre_groups                               
    448                                 if format == 'DIF' or format == 'MDIP': 
    449                                               
    450                                         #thisIngestedID = ingestOriginal.addFileToPostgresDB_original(fullPath) 
    451                                          
    452                                          
    453                                         thisIngest = AbstractFormatIngesterOriginal() 
    454                                         thisIngestedID = thisIngest.ingest(fullPath,format,self._datacentre_groups,self._datacentre_namespace,self._xq,self.pgc,self.inputFileOrigFinal,self.thisIngestMonitor, self._NDG_dataProvider,self.stubIsoFile) 
    455                                         sys.exit() 
    456                                          
    457                                                                                                          
    458                                 elif format == 'MEDIN_v0.1': 
    459                                         thisIngestedID, errorMsg = AbstractFormatIngester.addFileToPostgresDB_Medin_v01(fullPath) 
     653                                                 
     654                                logging.info("********************************************************************** sjd1 " + fullPath) 
     655                                                 
     656                                thisIngestedID = self.addFileToPostgresDB(fullPath) 
     657                                 
     658                                logging.info("********************************************************************** sjd2 " + thisIngestedID) 
    460659                                 
    461660                                #remove this filename from the list of files for this DC already in list (whats left over is to be deleted)  
     
    463662                                        if thisIngestedID in filesPresentList:   
    464663                                                filesPresentList.remove(thisIngestedID)                  
    465                                                  
     664                                 
    466665                #test loop through remaining items in filePresentList - in order to synchronise with ingest directory - these 
    467666                #will need to be removed. 
     
    472671                                logging.info("NEED to DELETE : " + item + " IN ORDER TO SYNCHRONISE INGEST DIRECTORY WITH DATABASE CONTENTS")                    
    473672                                DeleteRecord(item) 
    474                                  
    475                                 #self.deletedFailList.append(item) 
    476                                 #self._no_files_deleted += 1 
    477                                 self.thisIngestMonitor.appendDeletedList(item) 
    478                                 self.thisIngestMonitor.incrementDeletedFile() 
     673                                self.deletedFailList.append(item) 
     674                                self._no_files_deleted += 1 
    479675                         
    480676                         
     
    493689                message = message + "Ingest date: " + str(datetime.datetime.now()) + "\n" 
    494690                message = message + "Original metadata directory: " + self._harvest_home + "\n\n" 
    495                 message = message + "TOTAL PROCESSED " + str(numfilesproc) + "\n" 
    496                 message = message + "INGESTED (Created) " + str(self.thisIngestMonitor.getIngestedFileNum())  + "\n" 
    497                 message = message + "INGESTED (Updated) " + str(self.thisIngestMonitor.getChangedFileNum())  + "\n" 
    498                 message = message + "DELETED " + str(self.thisIngestMonitor.getDeletedFileNum())  + "\n" 
    499                 message = message + "PROBLEM FILES " + str(self.thisIngestMonitor.getProblemFileNum())  + "\n" 
    500                  
    501                 '''recOpFile.write("Ingest report for data centre: " + datacentre + "\n") 
    502                 recOpFile.write("Ingest date: " + str(datetime.datetime.now()) + "\n") 
    503                 recOpFile.write("Original metadata directory: " + self._harvest_home + "\n\n") 
    504                 recOpFile.write("TOTAL PROCESSED " + str(numfilesproc) + "\n") 
    505                 recOpFile.write("INGESTED (Created) " + str(self._no_files_changed)  + "\n") 
    506                 recOpFile.write("INGESTED (Updated) " + str(self._no_files_ingested)  + "\n") 
    507                 recOpFile.write("DELETED " + str(self._no_files_deleted)  + "\n") 
    508                 recOpFile.write("PROBLEM FILES " + str(self._no_problem_files)  + "\n")''' 
    509                  
    510                  
    511                 #for badFile in self.updateFailList: 
    512                 for badFile in self.thisIngestMonitor.getFailList(): 
     691                message = message + "TOTAL_PROCESSED " + str(numfilesproc) + "\n" 
     692                message = message + "INGESTED_Created " + str(self._no_files_changed)  + "\n" 
     693                message = message + "INGESTED_Updated " + str(self._no_files_ingested)  + "\n" 
     694                message = message + "DELETED " + str(self._no_files_deleted)  + "\n" 
     695                message = message + "PROBLEM_FILES " + str(self._no_problem_files)  + "\n" 
     696                 
     697                 
     698                for badFile in self.updateFailList: 
    513699                        #recOpFile.write("PROBLEM_FILE " + badFile + "\n") 
    514700                        message = message +"PROBLEM_FILE " + badFile + "\n" 
  • TI01-discovery-Ingest/trunk/v4n_MEDIN/ingestAutomation-upgrade/OAIBatch/feeddocumentingester.py

    r5603 r6544  
    6565                else: 
    6666                        raise ValueError(self.INTERVAL_ERROR %str(interval)) 
    67  
     67                 
     68        def setOaiConfigFile(self, configFilePath): 
     69                ''' 
     70                Set the path to the OAI configuration file - directories etc used for data & reporting etc etc 
     71                ''' 
     72                print "**********************************************************************" 
     73                if configFilePath: 
     74                        self.oaiEditorConfig = configFilePath 
     75                        logging.info("Using configuration file at: " + configFilePath) 
     76                 
    6877         
    6978        def setIngestFromDate(self, ingestFromDate): 
     
    125134                                      targetCollection=dc.DIF_COLLECTION_PATH + no.repository)                   
    126135                         
    127                         FileUtilities.createFile(difFilename, doc)                               
     136                        FileUtilities.createFile(difFilename, doc) 
     137                        print "*****************************************************************************   1"                        
    128138                        numfilesproc, processingReport = self._convertAndIngestFiles(self.originals_dir, self.discovery_dir, self.dataCentre, False)                             
    129                          
     139                        print "*****************************************************************************   2" 
    130140                        if numfilesproc != 0: 
    131141                                reportLine = " Successfully obtained " + no.localID + "from feed and ingested document into database\n" 
     
    166176                 
    167177                #setup log file for checking history of ingests etc 
    168                 self.summaryFileName = "data/FeedIngestSummary.txt"         
     178                #self.summaryFileName = "/home/badc/discovery_docs/ingestDocs/data/FeedIngestSummary.txt"        
     179                self.summaryFileName = self.processingDict['reporting_directory'] + 'FeedIngestSummary.txt' 
     180                        
    169181                self.summaryFile = open(self.summaryFileName,'a')     
    170182                 
     
    259271                                 eXistPortNo = '8080', 
    260272                                 configFileName = 'passwords.txt',  
    261                                  dataCentrePoll = None): 
     273                                 dataCentrePoll = None, 
     274                                 oaiConfigFileName = 'oai_document_ingester.config'): 
    262275                ''' 
    263276                Set up object 
     
    295308                self._error_messages = '' 
    296309                 
     310                self.processThread = 'FEED' 
     311                 
    297312                self.deName = VTD().TERM_DATA[VTD.DE_TERM].title 
    298313 
    299                 self._base_dir = os.getcwd() + "/" # this is the base dir that the script is ran from 
    300                  
     314                #self._base_dir = os.getcwd() + "/" # this is the base dir that the script is ran from 
     315                 
     316                #now use config info 
     317                ''' 
     318                self.processingDict = self.getProcessingConfig('oai_document_ingester.config') 
     319                 
     320                #self._code_dir = "/home/badc/buildouts/oai_document_ingester/ingestAutomation-upgrade/OAIBatch/" # this is the base dir that the script is ran from 
     321                #self._base_dir = "/home/badc/discovery_docs/ingestDocs/" 
     322                 
     323                self._code_dir = self.processingDict['code_directory'] 
     324                self._base_dir = self.processingDict['base_directory'] 
     325                 
     326                self._databaseConfigurationFile = self.processingDict['ingestConfig'] 
     327                self._ndgRedirectURL = self.processingDict['NDG_redirect_URL'] 
     328                                 
     329                ''' 
     330                #initialise these for now. 
     331                self._code_dir = None 
     332                self._base_dir = None 
     333                 
     334                self._databaseConfigurationFile = None 
     335                self._ndgRedirectURL = None 
    301336                 
    302337        def runPoll(self, feedURL): 
     
    318353                # doing this via document retrieve xmlrpc interface 
    319354                #self.__setupFeedClient() 
     355                #set up the configuration needed for running everything else 
     356                self.processingDict = self.getProcessingConfig(self.oaiEditorConfig) 
     357                 
     358                self._code_dir = self.processingDict['code_directory'] 
     359                self._base_dir = self.processingDict['base_directory'] 
     360                 
     361                self._databaseConfigurationFile = self.processingDict['ingestConfig'] 
     362                self._ndgRedirectURL = self.processingDict['NDG_redirect_URL'] 
     363                self._existPassWordFile = self.processingDict['passwords_file'] 
     364                 
    320365                self._getPostgresDBConnection() 
    321                 self.__getDBConnection(self.eXistDBHostname, self.configFileName) 
     366                #self.__getDBConnection(self.eXistDBHostname, self.configFileName) 
     367                self.__getDBConnection(self.eXistDBHostname, self._existPassWordFile) 
    322368                self._setupXQueries() 
     369                 
     370                 
     371                 
    323372         
    324373if __name__=="__main__": 
    325374        print "=================================" 
    326375        print "RUNNING: FeedDocumentIngester.py" 
    327         ingester = FeedDocumentIngester() 
     376        ingester = FeedDocumentIngester()        
    328377        args = ingester._setupCmdLineOptions() 
    329378        ingester.runPoll(args[0]) 
Note: See TracChangeset for help on using the changeset viewer.