package gw.job.sxs uses com.guidewire.commons.entity.type.ThreadLocalBundleProvider uses com.guidewire.pl.system.dependency.PLDependencies uses gw.api.extension.ExtensionInterfaces uses gw.api.job.JobProcessLogger uses gw.api.locale.DisplayKey uses gw.api.system.PCConfigParameters uses gw.api.util.DisplayableException uses gw.util.Pair uses gw.lang.Deprecated uses java.util.concurrent.Callable uses java.util.concurrent.ExecutorService uses java.util.concurrent.Executors uses java.util.concurrent.FutureTask /** * Methods used in side by side quoting */ @ReadOnly class SideBySideProcess { static class ParallelQuoteCallable implements Callable { var _policyPeriod : PolicyPeriod var _validationLevel: ValidationLevel var _ratingStyle : RatingStyle var _user : User var _validationResult : gw.validation.PCValidationResult construct(period : PolicyPeriod, user : User, valLevel : ValidationLevel, ratingStyle : RatingStyle) { _policyPeriod = period _user = user; _validationLevel = valLevel _ratingStyle = ratingStyle _validationResult = ExtensionInterfaces.IPolicyPeriodExtensions.getJobProcess(_policyPeriod).JobProcessValidator.LastResult } override function call() : Pair { // New thread has no security context. Take the user passed in the constructor to create a security token. var origToken = PLDependencies.getCommonDependencies().getServiceToken() var newToken = PLDependencies.getServiceTokenManager().createAuthenticatedToken(_user?.ID) try { // Set language and locale as requesting user's language and locale PLDependencies.getCommonDependencies().setServiceToken(newToken) // Set thread local bundle provider to new bundle as a defensive measure // against any entities created during quote that doesn't provide a bundle to // use (e.g. - passing the associated period into the entity's constructor) var bundle = gw.transaction.Transaction.newBundle() ThreadLocalBundleProvider.set(bundle); var p = bundle.loadBean(_policyPeriod.ID) as PolicyPeriod var jobProcess = ExtensionInterfaces.IPolicyPeriodExtensions.getJobProcess(p) //Copy the previous validation result to the new loaded bean ExtensionInterfaces.IPolicyPeriodExtensions.getJobProcess(p).JobProcessValidator.LastResult = _validationResult var quoteBlockedByWarnings = PCConfigParameters.SideBySideQuoteBlockedByWarnings.getValue() try { if (PCConfigParameters.SideBySideTwoStepQuotingEnabled.Value) { jobProcess.requestRate(null, _validationLevel, _ratingStyle, quoteBlockedByWarnings) } else { jobProcess.requestQuote(null, _validationLevel, _ratingStyle, quoteBlockedByWarnings) } } catch (e: Exception) { return new Pair(p, e) } return new Pair(p, p.ValidRate ? null : new DisplayableException(DisplayKey.get("Web.Job.SideBySide.Errors.InvalidQuote"))) } catch (e : Exception) { return new Pair(_policyPeriod, e) } finally { ThreadLocalBundleProvider.clear() PLDependencies.getCommonDependencies().setServiceToken(origToken) PLDependencies.getServiceTokenManager().removeToken(newToken) } } } /** * Get quotes for a list of policy periods. Quoting is done in parallel where threads are drawn from * a thread pool of fixed size. This call will wait until all quoting threads complete before returning * NOTE: policy periods are explicitly committed before and after quote calculation * * @param policyPeriods list of policy periods to quote * @return Returns a list of policyperiod and exception pairs for each policyperiod for which quote was attempted. * if the quote completes without incident, is returned. */ static function getQuotes(policyPeriods : Set) : List> { return getQuotes(policyPeriods, true) } /** * Get quotes for a list of policy periods. Quoting is done in parallel where threads are drawn from * a thread pool of fixed size. This call will wait until all quoting threads complete before returning * NOTE: autocommit flag is no longer used and will always commit * * * @param policyPeriods list of policy periods to quote * @return Returns a list of policyperiod and exception pairs for each policyperiod for which quote was attempted. * if the quote completes without incident, is returned. */ @Deprecated("PC9.0.4 Use getQuotes(policyPeriods) instead.") static function getQuotes(policyPeriods : Set, autoCommit : Boolean) : List> { JobProcessLogger.logInfo("Side by side parallel quote requested.") if (null!=policyPeriods and policyPeriods.Count > 0) { // Filter out: // 1) Already rated or quoted policy periods // 2) Periods with unhandled preemptions // 3) Unresolved OOS conflicts var copyOfPeriods = policyPeriods.copy() copyOfPeriods.each(\ p -> { if (p.Status == TC_RATED or p.Status == TC_QUOTED or p.OOSConflicts.HasElements or p.hasAnyUnhandledPreemptions()) { policyPeriods.remove(p) } else { // Period is explicitly committed as internal threads will reload a copy // of the policy period into a new bundle for quoting p.Bundle.commit() } }) if (policyPeriods.Empty) { JobProcessLogger.logDebug("All policy periods are already quoted.") return {} } // Grab the current user to pass to each thread var currentUser = User.util.CurrentUser var maxNumParallelQuoteThreads = PCConfigParameters.MaxParallelQuotingThreads.getValue() var numWorkerThreads = policyPeriods.Count >= maxNumParallelQuoteThreads ? maxNumParallelQuoteThreads : policyPeriods.Count var quoteCallables = new ArrayList(policyPeriods.Count) var quoteExecutors : ExecutorService var quoteIssues : List> = {} try { // Used to ensure we clean up our threadpool quoteExecutors = Executors.newFixedThreadPool(numWorkerThreads) policyPeriods.each(\ period -> { var callable : Callable = new ParallelQuoteCallable(period, currentUser, ExtensionInterfaces.IPolicyPeriodExtensions.getValidationLevel(period), ExtensionInterfaces.IPolicyPeriodExtensions.getRatingStyle(period)) quoteCallables.add(new FutureTask(callable)) }) quoteCallables.each(\ ft -> quoteExecutors.submit(ft)) // Not really looking at the future, just using it to wait for all the results to complete quoteCallables.each(\ ft -> { var quoteIssue : Pair try { // NOTE: get() will return a policy period, exception pair for each period for which quote was attempted // If the exception == null, the quote succeeded with no issues. If exception != null, then exception // will hold whatever was thrown to indicate the cause of the failed quote attempt. quoteIssue = ft.get() as Pair var period = quoteIssue.First period.Bundle.commit() policyPeriods.singleWhere(\pp -> pp.ID == period.ID).refresh() if (null!=quoteIssue) { quoteIssues.add(quoteIssue) } } catch ( ie : InterruptedException) { JobProcessLogger.logInfo("Caught InterruptedException while waiting for getQuotes() to complete.", ie) } }) } finally { quoteExecutors.shutdown() } quoteIssues.where(\qi -> qi.Second != null).each(\qi -> {JobProcessLogger.logInfo(qi.First.BranchName + " issue: ", qi.Second)}) return quoteIssues } return {} } }