protected override bool ProcessWorkItem(SPContentDatabase contentDatabase, SPWorkItemCollection workItems, SPWorkItem workItem, SPJobState jobState) { Stopwatch sw = Stopwatch.StartNew(); //used to time how long the export took bool processingAlready = false; try { if (workItem != null) { //process the workItem using (SPSite site = new SPSite(workItem.SiteId)) { using (SPWeb web = site.OpenWeb(workItem.WebId)) { // processing logic // 1. SET GlymaExport list Item to ExportStatus.Processing // 2. START export based on type in GlymaExport list item // 3. STORE the export in the GlymaExport list against the item as an attachment // 4. SET GlymaExport list item to ExportStatus.Completed SPList exportsList = null; SPListItem exportItem = null; try { exportsList = web.Lists[workItem.ParentId]; exportItem = exportsList.GetItemByUniqueId(workItem.ItemGuid); if (exportItem != null) { string exportStatus = exportItem["ExportStatus"] as string; if (exportStatus == ExportStatus.Scheduled.ToString()) { // If the export was still marked as scheduled then set it to processing WriteExportStatus(workItem, ExportStatus.Processing); exportItem = exportsList.GetItemByUniqueId(workItem.ItemGuid); if (exportItem != null) { // read the type of export that we should produce ExportType exportType = (ExportType)Enum.Parse(typeof(ExportType), exportItem["ExportType"] as string); MapType mapType = (MapType)Enum.Parse(typeof(MapType), exportItem["MapType"] as string); Dictionary<string, string> exportProperties = null; string exportPropertiesStr = exportItem["ExportProperties"] as string; if (!string.IsNullOrEmpty(exportPropertiesStr) && exportPropertiesStr.Trim() != string.Empty) { try { ExportPropertiesDictionary exportDict = new ExportPropertiesDictionary(exportPropertiesStr); exportProperties = exportDict as Dictionary<string, string>; } catch (XmlSchemaValidationException) { exportProperties = null; } } bool useVerboseLogging = false; if (exportProperties != null) { if (exportProperties.ContainsKey("Verbose")) { if (exportProperties["Verbose"].ToLower() == "true") { useVerboseLogging = true; } } } if (useVerboseLogging) { LogMessage(workItem, "Creating Map Manager for the web: {0}.", web.Url); } // create the appropriate IExportUtility for the ExportType MapManagerFactory mapManagerFactory = new MapManagerFactory(); IMapManager mapManager = mapManagerFactory.GetMapManager(web); if (mapManager != null) { if (useVerboseLogging) { LogMessage(workItem, "Created Map Manager for the web: {0}.", web.Url); } ExportUtilityFactory exportUtilityFactory = new ExportUtilityFactory(mapManager); IExportUtility exportUtility = exportUtilityFactory.CreateExportUtility(mapType, exportType); if (exportUtility != null) { if (useVerboseLogging) { LogMessage(workItem, "Created Export Utility for {0} map type to {1}.", mapType.ToString(), exportType.ToString()); } exportItem = exportsList.GetItemByUniqueId(workItem.ItemGuid); if (exportItem != null) { Guid rootMapUid = Guid.Empty; Guid domainUid = Guid.Empty; try { string rootMapUidValue = exportItem["RootMapUid"] as string; string domainUidValue = exportItem["DomainUid"] as string; domainUid = new Guid(domainUidValue); rootMapUid = new Guid(rootMapUidValue); } catch (Exception ex) { //The GUIDs were not parsed correctly } if (rootMapUid != Guid.Empty && domainUid != Guid.Empty) { //The export utility will do the grunt work and provide a URL to the temp file created GlymaExportUserState userState = new GlymaExportUserState(workItem); userState.UseVerboseLogging = useVerboseLogging; //store the level of logging to use in the event handlers exportUtility.ExportCompleted += exportUtility_ExportCompleted; exportUtility.ProgressChanged += exportUtility_ProgressChanged; exportUtility.ExceptionRaised += exportUtility_ExceptionRaised; if (useVerboseLogging) { LogMessage(workItem, "Starting export."); } exportUtility.ExportMap(domainUid, rootMapUid, exportProperties, new List<Guid>(), userState); if (useVerboseLogging) { LogMessage(workItem, "Waiting for export to complete."); } // Wait for the export to complete (up to the timeout) bool signalled = userState.Completed.WaitOne(TIMEOUT_MS); if (!signalled) { if (useVerboseLogging) { LogMessage(workItem, "The export timed out after {0}ms", TIMEOUT_MS); } // The timeout occurred so don't process the completed or progress changed events exportUtility.ExportCompleted -= exportUtility_ExportCompleted; exportUtility.ProgressChanged -= exportUtility_ProgressChanged; exportUtility.ExceptionRaised -= exportUtility_ExceptionRaised; } } else { throw new Exception(string.Format("The DomainUid and/or RootMapUid were not valid Guid's. DomainUid: {0} RootMapUid: {1}.", domainUid.ToString(), rootMapUid.ToString())); } } } else { throw new Exception(string.Format("Unable to create export utility for the export type: {0}.", exportType.ToString())); } } else { throw new Exception(string.Format("Unable to build an IMapManager for the current SPWeb. {0}", mapManagerFactory.ErrorMessage)); } } } else if (exportStatus == ExportStatus.Processing.ToString()) { //shouldn't do anything unless it's scheduled. processingAlready = true; } } else { throw new Exception("The Export Job did not exist in the list."); } } catch (TargetInvocationException tiex) { if (workItem != null) { WriteExportStatus(workItem, ExportStatus.Error); LogMessage(workItem, "Error during export: {0}", tiex.Message); if (tiex.InnerException != null) { LogMessage(workItem, "Inner Exception({0}): {1}.\r\nStackTrace: {2}", tiex.InnerException.GetType().ToString(), tiex.InnerException.Message, tiex.InnerException.StackTrace); } } } catch (Exception ex) { //exception handling if (workItem != null) { WriteExportStatus(workItem, ExportStatus.Error); LogMessage(workItem, "Error during export: {0}.", ex.Message); } } finally { if (!processingAlready) { // delete the workItem after we've processed it workItems.SubCollection(site, web, 0, (uint)workItems.Count).DeleteWorkItem(workItem.Id); } //Update the progress of the timer job Progress += (100 / workItems.Count); //estimate only, some maps will export faster than others and different types may export faster if (Progress > 100) { Progress = 100; } this.UpdateProgress(Progress); //The base classes timer job's overall progress if (!processingAlready) //this is if the timer job ran and started processing the item that was already being processed { exportItem = exportsList.GetItemByUniqueId(workItem.ItemGuid); if (exportItem != null) { string exportStatus = exportItem["ExportStatus"] as string; if (exportStatus == ExportStatus.Processing.ToString()) { //if it's still processing and at this point then something has failed. WriteExportStatus(workItem, ExportStatus.Error); LogMessage(workItem, "The export failed as it was still in a processing state when it had apparently completed."); } LogMessage(workItem, "Completed in {0:0.000}s.", sw.Elapsed.TotalSeconds);//add in a metric for how long the export took (successful or failure) } } } } } } } catch (Exception ex) { //exception handling throw new Exception("Failed to while processing Glyma Export Work Item Timer Job.", ex); } return true; }
private void OnInitialiseMapManagerCompleted(object sender, InitialiseMapManagerEventArgs e) { if (e.IsInitialised) { ProgressRecord progressRecord = new ProgressRecord(0, "Exporting Glyma Map", string.Format("Initialising {0} export processor", ExportFormat.ToString())); progressRecord.SecondsRemaining = -1; progressRecord.PercentComplete = 5; progressRecord.RecordType = ProgressRecordType.Processing; lock (pr_lock) { this.ProgressRecord = progressRecord; ProgressEvent.Set(); //notify of change to progress } ExportUtilityFactory exportFactory = new ExportUtilityFactory(MapManager); IExportUtility exportUtil = null; switch (MapSchema) { case "IBIS": switch (ExportFormat) { case "Compendium": exportUtil = exportFactory.CreateExportUtility(MapType.IBIS, ExportType.Compendium); break; case "Word": exportUtil = exportFactory.CreateExportUtility(MapType.IBIS, ExportType.Word); break; case "PDF": exportUtil = exportFactory.CreateExportUtility(MapType.IBIS, ExportType.PDF); break; case "GlymaXML": //exportUtil = exportFactory.CreateExportUtility(MapType.IBIS, ExportType.GlymaXml); lock (msg_lock) { Message = "Exporting to GlymaXML format is currently not supported"; LogMessageEvent.Set(); } break; } break; } exportUtil.ExportCompleted += OnExportCompleted; exportUtil.ProgressChanged += OnProgressChanged; ExportPropertiesDictionary exportProps = CreateExportProperties(); GlymaExportUserState userState = new GlymaExportUserState(Output); progressRecord = new ProgressRecord(0, "Exporting Glyma Map", "Export Progress: 0%"); progressRecord.SecondsRemaining = -1; progressRecord.PercentComplete = 10; progressRecord.RecordType = ProgressRecordType.Processing; lock (pr_lock) { this.ProgressRecord = progressRecord; ProgressEvent.Set(); //notify of change to progress } exportUtil.ExportMap(Domain, Map, exportProps, null, userState); bool signalled = userState.Completed.WaitOne(Timeout.Infinite); //wait for the export to completed if (!signalled) { Completed.Set(); //since it's inifinite timeout this shouldn't happen } } else { lock (msg_lock) { this.Message = string.Format("Failed to initialise the web service client: {0}", e.ErrorMessage); LogMessageEvent.Set(); } Completed.Set(); } }