private async Task <int> StoreReport(PackageLicenseReport report)
        {
            using (var connection = await PackageDatabase.ConnectTo())
                using (SqlCommand command = connection.CreateCommand())
                {
                    command.CommandText = "AddPackageLicenseReport";
                    command.CommandType = CommandType.StoredProcedure;

                    DataTable licensesNames = new DataTable();
                    licensesNames.Columns.Add("Name", typeof(string));
                    foreach (string license in report.Licenses.Select(l => l.Trim()).Distinct(StringComparer.OrdinalIgnoreCase))
                    {
                        licensesNames.Rows.Add(license);
                    }
                    command.Parameters.AddWithValue("@licenseNames", licensesNames);

                    command.Parameters.AddWithValue("@sequence", report.Sequence);
                    command.Parameters.AddWithValue("@packageId", report.PackageId);
                    command.Parameters.AddWithValue("@version", report.Version);
                    command.Parameters.AddWithValue("@reportUrl", report.ReportUrl ?? string.Empty);
                    command.Parameters.AddWithValue("@comment", report.Comment);

                    return((int)(await command.ExecuteScalarAsync()));
                }
        }
        private static PackageLicenseReport CreateReport(JObject messageEvent)
        {
            PackageLicenseReport report = new PackageLicenseReport(messageEvent["sequence"].Value <int>());

            report.PackageId = messageEvent.Value <string>("packageId");
            report.Version   = messageEvent.Value <string>("version");
            report.ReportUrl = messageEvent.Value <string>("reportUrl");
            report.Comment   = messageEvent.Value <string>("comment");
            foreach (JValue l in messageEvent["licenses"])
            {
                report.Licenses.Add(l.Value <string>());
            }
            return(report);
        }
        private async Task <bool> ProcessReports(Uri nextLicenseReport)
        {
            HttpWebResponse response = null;
            int             tries    = 0;

            Trace.TraceInformation(string.Format("Downloading license report {0}", nextLicenseReport.AbsoluteUri));
            while (tries < RetryCount.Value && response == null)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(nextLicenseReport);
                if (LicenseReportCredentials != null)
                {
                    request.Credentials = LicenseReportCredentials;
                }

                WebException thrown = null;
                try
                {
                    response = (HttpWebResponse)(await request.GetResponseAsync());
                }
                catch (WebException ex)
                {
                    response = null;
                    if (ex.Status == WebExceptionStatus.Timeout || ex.Status == WebExceptionStatus.ConnectFailure)
                    {
                        // Try again in 10 seconds
                        tries++;
                        if (tries < RetryCount.Value)
                        {
                            thrown = ex;
                        }
                        else
                        {
                            throw;
                        }
                    }
                    else
                    {
                        throw;
                    }
                }
                if (thrown != null)
                {
                    Trace.TraceInformation(string.Format("Error downloading report {0}, retrying. {1}", nextLicenseReport.AbsoluteUri, thrown.ToString()));
                    await Task.Delay(10 * 1000);
                }
            }
            Trace.TraceInformation(string.Format("Downloaded license report {0}", nextLicenseReport.AbsoluteUri));

            Trace.TraceInformation(string.Format("Processing license report {0}", nextLicenseReport.AbsoluteUri));
            using (response)
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Trace.TraceInformation(string.Format("Reading license report {0}", nextLicenseReport.AbsoluteUri));
                    string content;
                    using (var reader = new StreamReader(response.GetResponseStream()))
                    {
                        content = await reader.ReadToEndAsync();
                    }
                    Trace.TraceInformation(string.Format("Read license report {0}", nextLicenseReport.AbsoluteUri));

                    JObject sonatypeMessage = JObject.Parse(content);
                    if (!sonatypeMessage.IsValid(sonatypeSchema))
                    {
                        Trace.TraceInformation(string.Format("Invalid license report in {0}. {1}", nextLicenseReport.AbsoluteUri, Strings.UpdateLicenseReportsJob_JsonDoesNotMatchSchema));
                        return(false);
                    }

                    var events = sonatypeMessage["events"].Cast <JObject>().ToList();
                    for (int i = 0; i < events.Count; i++)
                    {
                        var messageEvent            = events[i];
                        PackageLicenseReport report = CreateReport(messageEvent);
                        Trace.TraceInformation(string.Format("Storing license report for {0} {1}", report.PackageId, report.Version));

                        if (await StoreReport(report) == -1)
                        {
                            Trace.TraceInformation(string.Format("Unable to store report for {0} {1}. Package does not exist in database.", report.PackageId, report.Version));
                        }
                        else
                        {
                            Trace.TraceInformation(string.Format("Stored license report for {0} {1}", report.PackageId, report.Version));
                        }
                    }

                    // Store the next URL
                    if (sonatypeMessage["next"].Value <string>().Length > 0)
                    {
                        var nextReportUrl = sonatypeMessage["next"].Value <string>();
                        if (!Uri.TryCreate(nextReportUrl, UriKind.Absolute, out nextLicenseReport))
                        {
                            Trace.TraceInformation(string.Format("Invalid next report URL: {0}", nextReportUrl));
                            return(false);
                        }
                        Trace.TraceInformation(string.Format("Storing next license report URL: {0}", nextLicenseReport.AbsoluteUri));

                        // Record the next report to the database so we can check it again if we get aborted before finishing.

                        using (var connection = await PackageDatabase.ConnectTo())
                        {
                            await connection.QueryAsync <int>(@"
                                        UPDATE GallerySettings
                                        SET NextLicenseReport = @nextLicenseReport",
                                                              new { nextLicenseReport = nextLicenseReport.AbsoluteUri });
                        }
                        return(true); // Continue and read the next report later
                    }
                    else
                    {
                        nextLicenseReport = null;
                    }
                    Trace.TraceInformation(string.Format("Processing license report {0}", nextLicenseReport.AbsoluteUri));
                }
                else if (response.StatusCode != HttpStatusCode.NoContent)
                {
                    Trace.TraceInformation(string.Format("No report for {0} yet.", nextLicenseReport.AbsoluteUri));
                }
                else
                {
                    Trace.TraceInformation(string.Format("HTTP {1} error requesting {0}: {2}", nextLicenseReport.AbsoluteUri, (int)response.StatusCode, response.StatusDescription));
                }
                return(false);
            }
        }