private void ProcessScore(HttpContext context)
        {
            Interlocked.Increment(ref RequestCount);

            // GET RESPONSE
            ItemScoreResponse itemScoreResponse;

            // Get XML
            using (XmlReader reader = XmlReader.Create(context.Request.InputStream))
            {
                itemScoreResponse = HttpWebHelper.DeserializeXml <ItemScoreResponse>(reader);
                reader.Close();
            }

            // get the context token and deserialize it
            string decryptedToken = GetContextToken(itemScoreResponse);
            ItemScoreRequestContextToken tokenData = null;

            // get test data
            try
            {
                tokenData = JsonHelper.Deserialize <ItemScoreRequestContextToken>(decryptedToken);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(String.Format("Could not read contextToken: {0},  Error: {1}.", decryptedToken ?? "(null)", ex.Message));
            }

            // create response
            ScoredResponse scoredResponse = new ScoredResponse()
            {
                ItemKey         = tokenData.ItemKey,
                OppKey          = tokenData.oppKey,
                Sequence        = tokenData.reportingVersion ?? -1,
                Score           = itemScoreResponse.Score.ScoreInfo.Points,
                ScoreStatus     = itemScoreResponse.Score.ScoreInfo.Status.ToString(),
                ScoreRationale  = null,
                ScoreDimensions = HttpWebHelper.SerializeXml(itemScoreResponse.Score.ScoreInfo)
            };

            string hubDBIP     = tokenData.TISIP;
            string hubDBName   = tokenData.TISDbName;
            string clientName  = tokenData.clientName;
            string environment = tokenData.environment;

            // create function for submitting scores
            Action submitScore = delegate
            {
                Interlocked.Increment(ref ProgressCount);

                try
                {
                    if (String.IsNullOrEmpty(hubDBIP))
                    {
                        // must be sending items for scoring in the TDSReport format where we don't send
                        //  this information in the context token.  In this case, we can only support a single configured hub.
                        //  Grab the info from that hub.
                        IAdminRepository     cloudRepository = ServiceLocator.Resolve <IAdminRepository>();
                        List <DataStoreInfo> hubs            = cloudRepository.GetMonitoredDataStores(ScoringDaemonSettings.MachineName);
                        hubs = hubs.FindAll(h => h.ClientName == clientName).ToList <DataStoreInfo>();
                        if (hubs.Count == 0)
                        {
                            throw new ApplicationException(String.Format("No hubs are configured for client: {0} on machine: {1}", clientName, ScoringDaemonSettings.MachineName));
                        }
                        if (hubs.Count > 1)
                        {
                            throw new ApplicationException(String.Format("TIS item scoring callback handler only supports a single hub per client for this type of request.  {0} are configured for client: {1}.", hubs.Count, clientName));
                        }
                        hubDBIP     = ScoringDaemonSettings.HubIP(hubs[0]);
                        hubDBName   = hubs[0].DBName;
                        clientName  = hubs[0].ClientName;
                        environment = hubs[0].Environment;
                    }

                    // Save score to DB
                    IResponseRepository responseRepo = ServiceLocator.Resolve <IResponseRespositoryFactory>()
                                                       .Create(ScoringDaemonSettings.HubConnectionString(hubDBIP, hubDBName), clientName, environment);

                    if (responseRepo == null)
                    {
                        // this is really unusual. We got a item score response for an unknown hub.
                        string errorMessage =
                            String.Format(
                                "Got a score response for a hub that we dont monitor. oppKey:{0}, itemKey: {1}, sequence:{2}, clientName: {3}, environment: {4}",
                                scoredResponse.OppKey, scoredResponse.ItemKey, scoredResponse.Sequence, clientName, environment);
                        throw new InvalidDataException(errorMessage);
                    }

                    //run resolution rule if there is one
                    //Zach 12/11/2014 TODO: Add checks or try/catches around each part of running the rule to give more specific error messages?
                    TISItemResolutionRule rule = TISItemResolutionRule.CreateRule(tokenData.itemType, scoredResponse.ItemKey, clientName);
                    if (rule != null)
                    {
                        TDSQASystemAPI.TestResults.ItemScoreInfo resolvedScore = rule.ResolveItemScore(Serialization.DeserializeXml <TDSQASystemAPI.TestResults.ItemScoreInfo>(scoredResponse.ScoreDimensions));
                        scoredResponse.Score           = (int)resolvedScore.Points;
                        scoredResponse.ScoreStatus     = resolvedScore.Status == TDSQASystemAPI.TestResults.ScoringStatus.Scored ? ScoringStatus.Scored.ToString() : ScoringStatus.ScoringError.ToString();
                        scoredResponse.ScoreDimensions = HttpWebHelper.SerializeXml(resolvedScore);
                    }

                    responseRepo.UpdateItemScore(scoredResponse);
                }
                catch (Exception ex)
                {
                    Interlocked.Decrement(ref ProgressCount);
                    Interlocked.Increment(ref ErrorCount);

                    LastError = String.Format("{0} ({1})", ex.Message, DateTime.Now);

                    // wasn't logging the exception.  See TDS.Shared.Logging.TraceLog.ToString()
                    string id = tokenData == null ? "Unknown" : tokenData.ToString();
                    TDSLogger.Application.Error(new ApplicationException(String.Format("Error submitting callback score for: {0}", id), ex));
                    //TDSLogger.Application.Error(new TraceLog("Error submitting callback score.", ex));

                    return;
                }

                Interlocked.Decrement(ref ProgressCount);
                Interlocked.Increment(ref SuccessCount);
            };

            // check if thread pooling is enabled for callbacks
            if (WorkerPool != null)
            {
                // async
                if (!WorkerPool.Enqueue(submitScore))
                {
                    Interlocked.Increment(ref RejectCount);
                }
            }
            else
            {
                // sync
                submitScore();
            }
        }
 public ReponseRepoMonitor(string clientName, string environment, String dbIP, String dbName)
 {
     ClientName         = clientName;
     Environment        = environment;
     DBIP               = dbIP;
     DBName             = dbName;
     ResponseRepository = ServiceLocator.Resolve <IResponseRespositoryFactory>().Create(ScoringDaemonSettings.HubConnectionString(DBIP, DBName), clientName, environment);
     ScoreRequestSender = new ItemScoringClient(new BoundedThreadPool(
                                                    ScoringDaemonSettings.ScoreRequestThreadPoolCount, String.Format("Score Request Thread Pool{0}:{1}", ClientName, Environment),
                                                    ScoringDaemonSettings.ScoreRequestThreadPoolHighWaterMark, ScoringDaemonSettings.ScoreRequestThreadPoolLowWaterMark));
 }
        public void Start(WindowsIdentity identity, Action initializeCallback)
        {
            if (_started) return;

            ScoringDaemonSettings.AppStartTime = DateTime.Now;

            if (initializeCallback == null)
                // create the thread pool and assign it to the callback handler
                ItemScoringCallbackHandler.WorkerPool = new BoundedThreadPool(
                    ScoringDaemonSettings.CallbackThreadPoolCount, "Item Scoring Callback",
                    ScoringDaemonSettings.CallbackThreadPoolHighWaterMark, ScoringDaemonSettings.CallbackThreadPoolLowWaterMark);
            else
                initializeCallback();

            // Check that the cloud DB connection string is provisioned. If not, nothing we can do here
            if (ScoringDaemonSettings.CloudConnectionString == null)
            {
                throw new InvalidDataException("Connection String for the Cloud DB not provided");
            }

            // Setup the timer to scan the cloud db for hubs to manage
            long interval = (ScoringDaemonSettings.CloudTimerIntervalSeconds * 1000);
            const long startup = 100;
            _cloudTimer = new Timer(delegate
            {
                WindowsImpersonationContext wi = null;
                try
                {
                    wi = identity.Impersonate();

                    IAdminRepository cloudRepository = ServiceLocator.Resolve<IAdminRepository>();
                    List<DataStoreInfo> hubs = cloudRepository.GetMonitoredDataStores(ScoringDaemonSettings.MachineName);
                    ScoringDaemonSettings.CloudLastPollTime = DateTime.Now;

                    // Dispose of any hubs that are no longer present
                    foreach (ReponseRepoMonitor hub in MonitorCollection.GetAll())
                    {
                        bool found = false;
                        foreach (var cloudServiceInfo in hubs)
                        {
                            if (cloudServiceInfo.ClientName == hub.ClientName &&
                                cloudServiceInfo.Environment == hub.Environment &&
                                cloudServiceInfo.DBName == hub.DBName &&
                                ScoringDaemonSettings.HubIP(cloudServiceInfo) == hub.DBIP)
                            {
                                found = true; // OK - so this hub should still be retained
                            }
                        }
                        if (!found)
                        {
                            // Now we have a hub that used to be registered in the cloud and is no longer there. Get rid of it.
                            MonitorCollection.Remove(hub.ClientName, hub.Environment);
                            hub.Dispose();
                            TDSLogger.Application.Info(String.Format("Disposing ReponseRepoMonitor {0}:{1}:{2}:{3}", hub.ClientName, hub.Environment, hub.DBIP, hub.DBName));
                        }
                    }

                    // Add any new hubs that need to be added
                    foreach (DataStoreInfo hubInfo in hubs)
                    {
                        ReponseRepoMonitor reponseRepoMonitor = MonitorCollection.Lookup(hubInfo.ClientName, hubInfo.Environment);
                        if (reponseRepoMonitor == null)
                        {
                            reponseRepoMonitor = new ReponseRepoMonitor(hubInfo.ClientName, hubInfo.Environment, ScoringDaemonSettings.HubIP(hubInfo), hubInfo.DBName);
                            MonitorCollection.Add(reponseRepoMonitor);
                            reponseRepoMonitor.Activate();
                            TDSLogger.Application.Info(String.Format("Adding ReponseRepoMonitor {0}:{1}:{2}:{3}", reponseRepoMonitor.ClientName, reponseRepoMonitor.Environment, reponseRepoMonitor.DBIP, reponseRepoMonitor.DBName));
                        }
                    }

                }
                catch (Exception ex)
                {
                    string errorMessage = String.Format("CloudTimer: Fatal exception occured on Cloud Timer thread");
                    TDSLogger.Application.Fatal(new TraceLog("Application: " + errorMessage, ex));
                }
                finally
                {
                    if (wi != null) wi.Undo();
                }

            }, null, startup, interval);

            _started = true;
        }
        private void ProcessScore(HttpContext context)
        {
            Interlocked.Increment(ref RequestCount);

            // GET RESPONSE
            ItemScoreResponse itemScoreResponse;

            // Get XML
            using (XmlReader reader = XmlReader.Create(context.Request.InputStream))
            {
                itemScoreResponse = HttpWebHelper.DeserializeXml <ItemScoreResponse>(reader);
                reader.Close();
            }

            // decrypt token
            string decryptedToken = EncryptionHelper.DecryptFromBase64(itemScoreResponse.Score.ContextToken);

            // get test data
            WebValueCollection tokenData = new WebValueCollection();

            tokenData.FillFromString(decryptedToken);

            // parse test data and collect up the information needed to persist this score
            ScoredResponse scoredResponse = new ScoredResponse
            {
                OppKey          = tokenData.Get <Guid>("oppKey"),
                ItemKey         = tokenData.Get("itemKey"),
                Position        = tokenData.Get <int>("position"),
                Sequence        = tokenData.Get <int>("sequence"),
                ScoreMark       = tokenData.Get <Guid>("scoremark"),
                Score           = itemScoreResponse.Score.ScoreInfo.Points,
                ScoreStatus     = itemScoreResponse.Score.ScoreInfo.Status.ToString(),
                ScoreRationale  = HttpWebHelper.SerializeXml(itemScoreResponse.Score.ScoreInfo),
                ScoreDimensions = GetDimensionsXmlForSP(itemScoreResponse.Score.ScoreInfo)
            };

            string hubDBIP     = tokenData.Get <String>("hubDBIP");
            string hubDBName   = tokenData.Get <String>("hubDBName");
            string clientName  = tokenData.Get <String>("clientName");
            string environment = tokenData.Get <String>("environment");

            // create function for submitting scores
            Action submitScore = delegate
            {
                Interlocked.Increment(ref ProgressCount);

                try
                {
                    // Save score to DB
                    IResponseRepository responseRepo = ServiceLocator.Resolve <IResponseRespositoryFactory>()
                                                       .Create(ScoringDaemonSettings.HubConnectionString(hubDBIP, hubDBName), clientName, environment);

                    if (responseRepo != null)
                    {
                        responseRepo.UpdateItemScore(scoredResponse);
                    }
                    else
                    {
                        // this is really unusual. We got a item score response for an unknown hub.
                        string errorMessage =
                            String.Format(
                                "Got a score response for a hub that we dont monitor. oppKey:{0}, itemKey: {1}, position: {2}, sequence:{3}, scoreMark: {4}, clientName: {5}, environment: {6}",
                                scoredResponse.OppKey, scoredResponse.ItemKey, scoredResponse.Position,
                                scoredResponse.Sequence, scoredResponse.ScoreMark, clientName, environment);
                        throw new InvalidDataException(errorMessage);
                    }
                }
                catch (Exception ex)
                {
                    Interlocked.Decrement(ref ProgressCount);
                    Interlocked.Increment(ref ErrorCount);

                    LastError = String.Format("{0} ({1})", ex.Message, DateTime.Now);
                    TDSLogger.Application.Error(new TraceLog("Item Scoring: Error submitting callback score.", ex));

                    return;
                }

                Interlocked.Decrement(ref ProgressCount);
                Interlocked.Increment(ref SuccessCount);
            };

            // check if thread pooling is enabled for callbacks
            if (WorkerPool != null)
            {
                // async
                if (!WorkerPool.Enqueue(submitScore))
                {
                    Interlocked.Increment(ref RejectCount);
                }
            }
            else
            {
                // sync
                submitScore();
            }
        }