package gw.rating uses gw.api.database.Query uses gw.api.database.QuerySelectColumns uses gw.api.domain.financials.PCFinancialsLogger uses java.math.BigDecimal uses gw.api.path.Paths uses gw.util.LRUCache uses java.util.ArrayList uses java.util.Collections uses java.lang.Double uses java.util.Date uses java.util.List uses gw.api.database.IQueryBeanResult uses gw.api.upgrade.Coercions /** * Search critera that can find rating factors in the rate_adj_factors system table. * See match and matchInRange methods for the full details */ @Export class RateAdjFactorSearchCriteria { static var _rangeCache = Collections.synchronizedMap(new LRUCache(100)) static var _lookupCache = Collections.synchronizedMap(new LRUCache>(100)) var _factorName : String var _findDate : Date // For testing static internal function clearCaches() { _rangeCache.clear() _lookupCache.clear() } construct( factorName : String, findDate : Date ) { if ( factorName == null or findDate == null ) { // Throw because, while the match code will work (typically returning 1.0) passing in nulls is probably indicative of a bug. throw "RateAdjFactorSearchCriteria requires both factorName and findDate " + this } _factorName = factorName _findDate = Coercions.makeDateFrom(findDate.clone()) } /** * Find a factor from the rating_adj_factors system table best matching this criteria such that * * If it is unable to find a factor matching all criteria, it then looks for a full default * factor match. * It returns null if it is unable match anything. */ function match( factorState : Jurisdiction ) : BigDecimal { return match( null, null, factorState ) } /** * Find a factor from the rating_adj_factors system table best matching this criteria such that * * If it is unable to find a factor matching all criteria, it then looks for a factor for all * states, and finally, a full default factor. * It returns null if it is unable match anything. */ function match( lookup : String, factorState : Jurisdiction ) : BigDecimal { return match( lookup, null, factorState ) } /** * Find a factor from the rating_adj_factors system table best matching this criteria such that * * If it is unable to find a factor matching all criteria, it then looks for a factor for all * states, a lookup2 default factor, and finally, a full default factor. * It returns null if it is unable match anything. */ function match( lookup : String, lookup2 : String, factorState : Jurisdiction ) : BigDecimal { var factor = findByLookups( lookup, lookup2, factorState ) // find with all criteria if ( factor == null ) { factor = findByLookups( lookup, lookup2, null ) // find "all states" default } if ( factor == null ) { factor = findByLookups( lookup, null, null ) // find lookup2 default } if ( factor == null ) { factor = findByLookups( null, null, null ) // find default logDefault( factor, "matchFactor(lookup=" + lookup + ", lookup2=" + lookup2 + ", factorState=" + factorState + ")" ) } return safeFactor( factor, "match(lookup=" + lookup + ", lookup2=" + lookup2 + ", factorState=" + factorState + ")" ) } /** * Find a factor from the rating_adj_factors system table matching the criteria such that * * It returns null if there are no matches. If there are multiple matches, * then it returns the one with the latest effective date, and if those are equal, * then the one with a PublicID later in the alphabet. */ function findByLookups( lookup : String, lookup2 : String, factorState : Jurisdiction ) : RateAdjFactorExt { var result = findAllByLookups( lookup, lookup2, factorState ) if (result.HasElements) { return result.first() } else { return null } } /** * Return a query that finds all factors from the rating_adj_factors system table best matching this criteria such that * the factorState matches. If it is unable to find any factors matching the state, it then looks for the * factors for all states. */ function matchAll( factorState : Jurisdiction ) : List { var result = findAllByLookups( null, null, factorState ) if ( result.Empty ) // find "all states" defaults { result = findAllByLookups( null, null, null ) } return result } function matchInRange( findNumber : Double, factorState : Jurisdiction ) : BigDecimal { return matchInRange( null, findNumber, factorState ) } function matchInRange( lookup : String, findNumber : Double, factorState : Jurisdiction ) : BigDecimal { var extraDesc = "matchInRange(lookup=" + lookup + ", findNumber=" + findNumber + ", factorState=" + factorState + ")" var factor = findInRange( lookup, findNumber, factorState ) // find with all criteria if ( factor == null ) { factor = findInRange( lookup, findNumber, null ) // find "all states" default } if ( factor == null ) { factor = findInRange( null, findNumber, null ) // find default logDefault( factor, extraDesc ) } return safeFactor( factor, extraDesc ) } private function logDefault( factor : RateAdjFactorExt, extraDesc : String ) { if ( factor != null ) { PCFinancialsLogger.logDebug( "Could only match default rating factor. Using " + factor.factor + " for " + this + extraDesc ) } } private function safeFactor( factor : RateAdjFactorExt, extraDesc : String ) : BigDecimal { if ( factor == null ) { PCFinancialsLogger.logDebug( "Could not match any rating factor. Using 1.0 for " + this + extraDesc ) return 1.0 } return factor.factor } /** * Return all factors from the rating_adj_factors system table matching the criteria such that *
    *
  • factorName matches *
  • factorState matches *
  • lookup matches the stringOption *
  • lookup2 matches the stringOption2 *
  • findDate falls within the [effDate, expDate) range. * If either dates is null, then that side of the range is considered unbound. *
*/ private function findAllByLookups( lookup : String, lookup2 : String, factorState : Jurisdiction ) : List { var result : List var queryElems = new Object[]{lookup, lookup2, factorState, _factorName, _findDate}.toList() if (_lookupCache.containsKey( queryElems )) { result = _lookupCache.get( queryElems ) } else { var query = Query.make(RateAdjFactorExt) .compare(RateAdjFactorExt#factorName, Equals, _factorName) .compare(RateAdjFactorExt#factorState, Equals, factorState.Code) .compare(RateAdjFactorExt#stringOption, Equals, lookup) .compare(RateAdjFactorExt#stringOption2, Equals, lookup2) .and(\ andRestriction -> andRestriction .or(\orRestriction -> { orRestriction.compare(RateAdjFactorExt#effDate, Equals, null) orRestriction.compare(RateAdjFactorExt#effDate, LessThanOrEquals, _findDate) }) .or(\orRestriction -> { orRestriction.compare(RateAdjFactorExt#expDate, Equals, null) orRestriction.compare(RateAdjFactorExt#expDate, GreaterThan, _findDate) }) ).select() result = query.toList() _lookupCache.put(queryElems, result) } return result } /** * Find a factor from the rating_adj_factors system table matching the criteria such that *
    *
  • factorName matches *
  • factorState matches *
  • lookup matches the stringOption *
  • findNumber falls within the [minNumber, maxNumber] range *
  • findDate falls within the [effDate, expDate) range. If either dates is null, then that side of the range is considered unbound. *
* It returns null if there are no matches. If there are multiple matches, * then it returns the one with the latest effective date, and if those are equal, * then the one with a PublicID later in the alphabet. */ private function findInRange( lookup : String, findNumber : Double, factorState : Jurisdiction ) : RateAdjFactorExt { var result : RateAdjFactorExt var queryElems = new Object[]{lookup, findNumber, factorState, _factorName, _findDate}.toList() if (_rangeCache.containsKey( queryElems )) { result = _rangeCache.get( queryElems ) } else { var factorQuery = Query.make(RateAdjFactorExt) .compare(RateAdjFactorExt#factorName, Equals, _factorName) .compare(RateAdjFactorExt#factorState, Equals, factorState.Code) .compare(RateAdjFactorExt#stringOption, Equals, lookup) .compare(RateAdjFactorExt#minNumber, LessThanOrEquals, findNumber as BigDecimal) .compare(RateAdjFactorExt#maxNumber, GreaterThanOrEquals, findNumber as BigDecimal) .and(\andRestriction -> andRestriction .or(\orRestriction -> { orRestriction.compare(RateAdjFactorExt#effDate, Equals, null) orRestriction.compare(RateAdjFactorExt#effDate, LessThanOrEquals, _findDate) }) .or(\orRestriction -> { orRestriction.compare(RateAdjFactorExt#expDate, Equals, null) orRestriction.compare(RateAdjFactorExt#expDate, GreaterThan, _findDate) }) ).select() result = getFirstResult( factorQuery ) _rangeCache.put(queryElems, result) } return result } private function getFirstResult( factorQuery : IQueryBeanResult ) : RateAdjFactorExt { if ( factorQuery != null ) { // get first the latest one, with the earliest PublicID factorQuery.orderByDescending(QuerySelectColumns.path(Paths.make(RateAdjFactorExt#effDate))).thenBy(QuerySelectColumns.path(Paths.make(RateAdjFactorExt#PublicID))) factorQuery.setPageSize(2) var factors = factorQuery.iterator() if (factors.hasNext()) { var factor = factors.next() if (factors.hasNext()) { PCFinancialsLogger.logDebug("Found more than one matching rating factor. Possible duplicates? " + this) } return factor } } return null } override function toString() : String { return "{_factorName=" + _factorName + ", findDate=" + _findDate + "}" } }