ws_wudetails.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2017 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <set>
  14. #include "ws_workunitsService.hpp"
  15. #include "ws_wudetails.hpp"
  16. #include "jlib.hpp"
  17. #include "workunit.hpp"
  18. #include "jset.hpp"
  19. #include "jstatcodes.h"
  20. typedef std::pair<WuAttr, StringBuffer> AttribValuePair;
  21. bool operator==(const AttribValuePair & p1, const AttribValuePair & p2)
  22. {
  23. return p1.first==p2.first;
  24. }
  25. class WUDetailsVisitor : public IWuScopeVisitor
  26. {
  27. public:
  28. WUDetailsVisitor(IConstWUPropertyOptions & _propertyOptions, IConstWUPropertiesToReturn & _propertiesToReturn);
  29. virtual ~WUDetailsVisitor(){};
  30. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value, IConstWUStatistic & extra) override;
  31. virtual void noteAttribute(WuAttr attr, const char * value) override;
  32. virtual void noteHint(const char * kind, const char * value) override;
  33. void resetScope();
  34. void noteScopeType(const StatisticScopeType _sst);
  35. IArrayOf<IEspWUResponseProperty> & getResponseProperties() { endListAttr(); return EspWUResponseProperties;}
  36. unsigned __int64 getMaxTimestamp() const { return maxTimestamp;}
  37. private:
  38. static const unsigned StatisticFilterMaskSize = StatisticKind::StMax;
  39. static const unsigned AttributeFilterMaskSize = WuAttr::WaMax-WaNone;
  40. bool includeName = false;
  41. bool includeRawValue = false;
  42. bool includeFormatted = false;
  43. bool includeMeasure = false;
  44. bool includeCreator = false;
  45. bool includeCreatorType = false;
  46. bool statisticsPostFilterRequired = false; // Does statistics have be filtered in the visited method (noteStatistic)
  47. // Only when true, does the following 3 variables have valid values
  48. std::set<StatisticKind> extraStatistics[SSTmax]; // Extra statistics returned for a given scope type
  49. const std::set<StatisticKind> * extraStatisticsForCurScope = nullptr; // Tracks statistics required for current scope type
  50. Owned<IBitSet> propertiesToReturnStats; // Statistic to be returned for every scope/scope type
  51. bool attributesPostFilterRequired = false; // Does attributes have be filtered in the visited method (noteAttribute)
  52. // Only when true, does the following 3 variables have valid values
  53. std::set<WuAttr> extraAttributes[SSTmax]; // Extra attributes returned for a given scope type
  54. const std::set<WuAttr> * extraAttributesForCurScope = nullptr; // Tracks attributes required for current scope type
  55. Owned<IBitSet> propertiesToReturnAttribs; // Attributes to be returned for every scope/scope type
  56. unsigned __int64 maxTimestamp = 0;
  57. IArrayOf<IEspWUResponseProperty> EspWUResponseProperties;
  58. StatisticScopeType currentStatisticScopeType = SSTnone;
  59. class MultiListValues
  60. {
  61. public:
  62. void add(WuAttr attr, const char *value)
  63. {
  64. AttribValuePair tmp(attr,"");
  65. auto cur = find(attribValuePairs.begin(), attribValuePairs.end(), tmp);
  66. if (cur!=attribValuePairs.end())
  67. {
  68. cur->second.appendf(", \"%s\"", value);
  69. }
  70. else
  71. {
  72. tmp.second.appendf("[\"%s\"", value);
  73. attribValuePairs.emplace_back(tmp);
  74. }
  75. }
  76. void flushListAttributes(WUDetailsVisitor & parent)
  77. {
  78. for(AttribValuePair & ap: attribValuePairs)
  79. {
  80. parent.addAttribToResp(ap.first, ap.second.append("]").str());
  81. }
  82. attribValuePairs.clear();
  83. }
  84. private:
  85. std::vector<AttribValuePair> attribValuePairs;
  86. } multiListValues;
  87. void addAttribToResp(WuAttr attr, const char * value)
  88. {
  89. Owned<IEspWUResponseProperty> EspWUResponseProperty = createWUResponseProperty("","");
  90. EspWUResponseProperty->setName(queryWuAttributeName(attr));
  91. if (includeFormatted)
  92. EspWUResponseProperty->setFormatted(value);
  93. if (includeRawValue)
  94. EspWUResponseProperty->setRawValue(value);
  95. EspWUResponseProperties.append(*EspWUResponseProperty.getClear());
  96. }
  97. void endListAttr()
  98. {
  99. multiListValues.flushListAttributes(*this);
  100. }
  101. bool includeAttribute(WuAttr w);
  102. void buildAttribListToReturn(IConstWUPropertiesToReturn & propertiesToReturn);
  103. };
  104. WUDetailsVisitor::WUDetailsVisitor(IConstWUPropertyOptions & propertyOptions, IConstWUPropertiesToReturn & propertiesToReturn)
  105. {
  106. includeName = propertyOptions.getIncludeName();
  107. includeRawValue = propertyOptions.getIncludeRawValue();
  108. includeFormatted = propertyOptions.getIncludeFormatted();
  109. includeMeasure = propertyOptions.getIncludeMeasure();
  110. includeCreator = propertyOptions.getIncludeCreator();
  111. includeCreatorType = propertyOptions.getIncludeCreatorType();
  112. buildAttribListToReturn(propertiesToReturn);
  113. }
  114. void WUDetailsVisitor::noteStatistic(StatisticKind kind, unsigned __int64 value, IConstWUStatistic & extra)
  115. {
  116. endListAttr();
  117. // This section handles the special case where there are Statistics in ExtraProperties.
  118. // When ExtraProperties are provided, this filter handles both PropertiesToReturn
  119. // and ExtraProperties. (In all other cases, the scope iterator will filter before visiting
  120. if (statisticsPostFilterRequired)
  121. {
  122. // Check first if the StatisticKind is listed in the main list (propertiesToReturnStats)
  123. // If there's no match there, check if the StatisticKind is in the scope type specific list
  124. if (!propertiesToReturnStats->test(kind))
  125. {
  126. // If it's not in propertiesToReturnStats, then check the extraStatisticsForCurScope
  127. if (extraStatisticsForCurScope==nullptr ||
  128. extraStatisticsForCurScope->find(kind)==extraStatisticsForCurScope->end())
  129. {
  130. return; // It is in neither list so filter out
  131. }
  132. }
  133. }
  134. Owned<IEspWUResponseProperty> EspWUResponseProperty = createWUResponseProperty("","");
  135. if (includeName)
  136. EspWUResponseProperty->setName(queryStatisticName(kind));
  137. if (includeRawValue)
  138. {
  139. StringBuffer rawValue;
  140. rawValue.append(value);
  141. EspWUResponseProperty->setRawValue(rawValue);
  142. }
  143. SCMStringBuffer tmpStr;
  144. if (includeFormatted)
  145. EspWUResponseProperty->setFormatted(extra.getFormattedValue(tmpStr).str());
  146. if (includeMeasure && extra.getMeasure()!=SMeasureNone)
  147. EspWUResponseProperty->setMeasure(queryMeasureName(extra.getMeasure()));
  148. if (includeCreator)
  149. EspWUResponseProperty->setCreator(extra.getCreator(tmpStr).str());
  150. if (includeCreatorType && extra.getCreatorType()!=SCTnone)
  151. EspWUResponseProperty->setCreatorType(queryCreatorTypeName(extra.getCreatorType()));
  152. EspWUResponseProperties.append(*EspWUResponseProperty.getClear());
  153. if (extra.getTimestamp()>maxTimestamp)
  154. maxTimestamp = extra.getTimestamp();
  155. }
  156. bool WUDetailsVisitor::includeAttribute(WuAttr attr)
  157. {
  158. if (propertiesToReturnAttribs->test(attr-WaNone))
  159. return true;
  160. if (extraAttributesForCurScope!=nullptr &&
  161. extraAttributesForCurScope->find(attr)!=extraAttributesForCurScope->end())
  162. return true;
  163. return false;
  164. }
  165. void WUDetailsVisitor::noteAttribute(WuAttr attr, const char * value)
  166. {
  167. // Note: For attributes that may have its values as MultiList, return it as
  168. // a MultiList only. That is unless the Single kind is specifically requested
  169. // as there is no reason to provide both.
  170. // Try to get the MultiList equivalent. If it can't, listAttr==WaNone
  171. // e.g. if attr==WaDefinition, then listAttr==WaDefinitionList
  172. WuAttr listAttr = getListAttribute(attr);
  173. // If values may be returned as MultiList (listAttr!=WaNone), set flag to
  174. // assuming that values will be returned as MultiList
  175. bool returnAttrAsMultiList = (listAttr!=WaNone);
  176. bool returnAttrAsSingleValue = true;
  177. if (attributesPostFilterRequired)
  178. {
  179. if (includeAttribute(attr)) // Single item specifically requested
  180. {
  181. if (isListAttribute(attr)) // Check to see if attr is multilist type
  182. {
  183. returnAttrAsMultiList = true;
  184. returnAttrAsSingleValue = false;
  185. listAttr=attr;
  186. }
  187. else
  188. returnAttrAsMultiList = false; // so don't return as MultiList value
  189. }
  190. else
  191. {
  192. returnAttrAsSingleValue = false; // Attribute as single value not selected
  193. if (returnAttrAsMultiList && !includeAttribute(listAttr))
  194. return;
  195. }
  196. }
  197. if (!returnAttrAsMultiList && !returnAttrAsSingleValue)
  198. return;
  199. StringBuffer encoded;
  200. encodeXML(value, encoded);
  201. if (returnAttrAsMultiList)
  202. multiListValues.add(listAttr,encoded.str());
  203. else
  204. addAttribToResp(attr, encoded.str());
  205. }
  206. void WUDetailsVisitor::noteHint(const char * kind, const char * value)
  207. {
  208. endListAttr();
  209. Owned<IEspWUResponseProperty> EspWUResponseProperty = createWUResponseProperty("","");
  210. StringBuffer hint("hint:");
  211. hint.append(kind);
  212. EspWUResponseProperty->setName(hint);
  213. StringBuffer encoded;
  214. if (includeFormatted || includeRawValue)
  215. {
  216. encodeXML(value, encoded);
  217. value = encoded.str();
  218. }
  219. if (includeFormatted)
  220. EspWUResponseProperty->setFormatted(value);
  221. if (includeRawValue)
  222. EspWUResponseProperty->setRawValue(value);
  223. EspWUResponseProperties.append(*EspWUResponseProperty.getClear());
  224. }
  225. // Get StatisticKind or WuAttr from property name and return true
  226. // When neither possible, return false.
  227. static bool getPropertyIdFromName(const char *propName, StatisticKind & sk, WuAttr & wa )
  228. {
  229. wa = WaNone;
  230. sk = queryStatisticKind(propName, StKindNone);
  231. if (sk!=StKindNone)
  232. return true;
  233. wa = queryWuAttribute(propName, WaNone);
  234. if (wa!=WaNone)
  235. return true;
  236. return false;
  237. }
  238. void WUDetailsVisitor::buildAttribListToReturn(IConstWUPropertiesToReturn & propertiesToReturn)
  239. {
  240. bool returnAllStatistic = propertiesToReturn.getAllStatistics();
  241. bool returnAllAttributes = propertiesToReturn.getAllAttributes();
  242. if ( (returnAllStatistic && returnAllAttributes) || propertiesToReturn.getAllProperties())
  243. return;
  244. // ScopeType specific properties (extra properties specific to given scope types)
  245. IArrayOf<IConstWUExtraProperties> & extraProperties = propertiesToReturn.getExtraProperties();
  246. ForEachItemIn(idx, extraProperties)
  247. {
  248. IConstWUExtraProperties & cur = extraProperties.item(idx);
  249. const char * scopeTypeWithAdditionalProps = cur.getScopeType();
  250. if (!scopeTypeWithAdditionalProps || !*scopeTypeWithAdditionalProps)
  251. continue;
  252. StatisticScopeType sst = queryScopeType(scopeTypeWithAdditionalProps, SSTnone);
  253. if (sst==SSTnone)
  254. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid ScopeType (%s) in ExtraProperties",scopeTypeWithAdditionalProps);
  255. // Generate list of properties for this Scope Type
  256. const StringArray & props = cur.getProperties();
  257. ForEachItemIn(idx2, props)
  258. {
  259. StatisticKind sk;
  260. WuAttr wa;
  261. const char *propName = props[idx2];
  262. if (!getPropertyIdFromName(propName, sk, wa))
  263. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid property name (%s) in ExtraProperties",propName);
  264. if (sk!=StKindNone)
  265. {
  266. if (!returnAllStatistic)
  267. {
  268. extraStatistics[sst].insert(sk);
  269. statisticsPostFilterRequired = true;
  270. }
  271. }
  272. else
  273. {
  274. if (!returnAllAttributes)
  275. {
  276. extraAttributes[sst].insert(wa);
  277. attributesPostFilterRequired = true;
  278. }
  279. }
  280. }
  281. }
  282. // Examine propertiesToReturn to see if any thing there will require a post filter
  283. if (!attributesPostFilterRequired)
  284. {
  285. // If single kind list is requested, it must be handled by post filter as the default behaviour
  286. // is to only return multi list kind. (Scope iterator's filtering is not able to handle this
  287. // and like with any other filtering that cannot be handled by the scope iterator it must be
  288. // handled by the post filter. By adding the single kind item to the post filter, noteAttribute
  289. // is forced to return the single kind.)
  290. //
  291. // Note: if attributesPostFilterRequired is set to true, then the second propertiesToReturnList
  292. // loop is processed to add the single kind list items as well as all other attibutes required.
  293. StringArray & propertiesToReturnList = propertiesToReturn.getProperties();
  294. ForEachItemIn(idx1,propertiesToReturnList)
  295. {
  296. const char * propName = propertiesToReturnList[idx1];
  297. WuAttr wa = queryWuAttribute(propName, WaNone);
  298. if (wa!=WaNone)
  299. {
  300. if (getListAttribute(wa)!=WaNone)
  301. {
  302. attributesPostFilterRequired = true;
  303. break;
  304. }
  305. }
  306. }
  307. }
  308. // Post Filtering (filtering within in visited method) required if statistics or attributes requested in ExtraProperties
  309. if (!statisticsPostFilterRequired && !attributesPostFilterRequired)
  310. return;
  311. if (statisticsPostFilterRequired)
  312. propertiesToReturnStats.set(createBitSet(StatisticFilterMaskSize));
  313. if (attributesPostFilterRequired)
  314. propertiesToReturnAttribs.set(createBitSet(AttributeFilterMaskSize));
  315. StringArray & propertiesToReturnList = propertiesToReturn.getProperties();
  316. ForEachItemIn(idx1,propertiesToReturnList)
  317. {
  318. const char * propName = propertiesToReturnList[idx1];
  319. if (!propName || *propName==0) continue;
  320. StatisticKind sk;
  321. WuAttr wa;
  322. if (!getPropertyIdFromName(propName, sk, wa))
  323. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid property name (%s) in PropertiesToReturn",propName);
  324. if (sk!=StKindNone)
  325. {
  326. if (statisticsPostFilterRequired)
  327. propertiesToReturnStats->set(sk, true);
  328. }
  329. else
  330. {
  331. if (attributesPostFilterRequired)
  332. propertiesToReturnAttribs->set(wa-WaNone,true);
  333. }
  334. }
  335. }
  336. void WUDetailsVisitor::resetScope()
  337. {
  338. currentStatisticScopeType = SSTnone;
  339. extraStatisticsForCurScope = nullptr;
  340. extraAttributesForCurScope = nullptr;
  341. EspWUResponseProperties.clear();
  342. endListAttr();
  343. }
  344. void WUDetailsVisitor::noteScopeType(const StatisticScopeType _sst)
  345. {
  346. currentStatisticScopeType = _sst;
  347. extraStatisticsForCurScope = & extraStatistics[currentStatisticScopeType];
  348. extraAttributesForCurScope = & extraAttributes[currentStatisticScopeType];
  349. }
  350. WUDetails::WUDetails(IConstWorkUnit *_workunit, const char *_wuid)
  351. : workunit(_workunit), wuid(_wuid)
  352. {
  353. }
  354. void WUDetails::processRequest(IEspWUDetailsRequest &req, IEspWUDetailsResponse &resp)
  355. {
  356. IConstWUScopeOptions & scopeOptions = req.getScopeOptions();
  357. const bool includeScope = scopeOptions.getIncludeScope();
  358. const bool includeScopeType = scopeOptions.getIncludeScopeType();
  359. const bool includeId = scopeOptions.getIncludeId();
  360. buildWuScopeFilter(req.getScopeFilter(), req.getNestedFilter(), req.getPropertiesToReturn(),
  361. req.getFilter(), scopeOptions);
  362. IArrayOf<IEspWUResponseScope> respScopes;
  363. WUDetailsVisitor wuDetailsVisitor(req.getPropertyOptions(), req.getPropertiesToReturn());
  364. Owned<IConstWUScopeIterator> iter = &workunit->getScopeIterator(wuScopeFilter);
  365. ForEach(*iter)
  366. {
  367. StatisticScopeType scopeType = iter->getScopeType();
  368. const char * scope = iter->queryScope();
  369. assertex(scope);
  370. wuDetailsVisitor.noteScopeType(scopeType);
  371. iter->playProperties(wuDetailsVisitor);
  372. Owned<IEspWUResponseScope> respScope = createWUResponseScope("","");
  373. if (includeScope)
  374. respScope->setScopeName(scope);
  375. if (includeScopeType)
  376. respScope->setScopeType(queryScopeTypeName(scopeType));
  377. if (includeId)
  378. respScope->setId(queryScopeTail(scope));
  379. IArrayOf<IEspWUResponseProperty> & properties = wuDetailsVisitor.getResponseProperties();
  380. if (!properties.empty())
  381. respScope->setProperties(properties);
  382. respScopes.append(*respScope.getClear());
  383. wuDetailsVisitor.resetScope();
  384. }
  385. StringBuffer maxVersion;
  386. maxVersion.append(wuDetailsVisitor.getMaxTimestamp());
  387. resp.setWUID(wuid.str());
  388. resp.setMaxVersion(maxVersion.str());
  389. resp.setScopes(respScopes);
  390. }
  391. void WUDetails::buildWuScopeFilter(IConstWUScopeFilter & requestScopeFilter, IConstWUNestedFilter & nestedFilter,
  392. IConstWUPropertiesToReturn & propertiesToReturn, const char * filter,
  393. IConstWUScopeOptions & scopeOptions)
  394. {
  395. wuScopeFilter.addFilter(filter);
  396. wuScopeFilter.setDepth(0, requestScopeFilter.getMaxDepth());
  397. const char * measure = propertiesToReturn.getMeasure();
  398. if (measure && *measure)
  399. wuScopeFilter.setMeasure(measure);
  400. wuScopeFilter.setIncludeNesting(nestedFilter.getDepth());
  401. wuScopeFilter.setIncludeMatch(scopeOptions.getIncludeMatchedScopesInResults());
  402. StringArray & scopes = requestScopeFilter.getScopes();
  403. ForEachItemIn(idx1,scopes)
  404. if (*scopes.item(idx1))
  405. wuScopeFilter.addScope(scopes.item(idx1));
  406. StringArray & ids = requestScopeFilter.getIds();
  407. ForEachItemIn(idx2,ids)
  408. if (*ids.item(idx2))
  409. wuScopeFilter.addId(ids.item(idx2));
  410. StringArray & scopeTypes = requestScopeFilter.getScopeTypes();
  411. ForEachItemIn(idx3,scopeTypes)
  412. if (*scopeTypes.item(idx3))
  413. wuScopeFilter.addScopeType(scopeTypes.item(idx3));
  414. buildPropertyFilter(requestScopeFilter.getPropertyFilters());
  415. StringArray & nestedScopeTypes = nestedFilter.getScopeTypes();
  416. ForEachItemIn(idx4,nestedScopeTypes)
  417. if (*nestedScopeTypes.item(idx4))
  418. wuScopeFilter.setIncludeScopeType(nestedScopeTypes.item(idx4));
  419. const char * minVersion = propertiesToReturn.getMinVersion();
  420. if (minVersion && *minVersion)
  421. {
  422. StringBuffer sMinVersion("version[");
  423. sMinVersion.append(propertiesToReturn.getMinVersion()).append("]");
  424. wuScopeFilter.addFilter(sMinVersion);
  425. }
  426. StringArray & properties = propertiesToReturn.getProperties();
  427. ForEachItemIn(idx5,properties)
  428. {
  429. const char * propName = properties.item(idx5);
  430. if (propName && *propName)
  431. wuScopeFilter.addOutput(propName);
  432. }
  433. IArrayOf<IConstWUExtraProperties> & extraProperties= propertiesToReturn.getExtraProperties();
  434. ForEachItemIn(idx6, extraProperties)
  435. {
  436. IConstWUExtraProperties & cur = extraProperties.item(idx6);
  437. const char * scopeTypeWithExtraProps = cur.getScopeType();
  438. if (!scopeTypeWithExtraProps || !*scopeTypeWithExtraProps) continue;
  439. StringArray & properties = cur.getProperties();
  440. ForEachItemIn(idx7, properties)
  441. {
  442. wuScopeFilter.addOutput(properties.item(idx7));
  443. }
  444. }
  445. WuPropertyTypes wuPropertyTypeMask = PTnone;
  446. if (propertiesToReturn.getAllProperties())
  447. {
  448. wuPropertyTypeMask = PTall;
  449. }
  450. else
  451. {
  452. if (propertiesToReturn.getAllStatistics())
  453. wuPropertyTypeMask |= PTstatistics;
  454. if (propertiesToReturn.getAllAttributes())
  455. wuPropertyTypeMask |= PTattributes;
  456. if (propertiesToReturn.getAllHints())
  457. wuPropertyTypeMask |= PThints;
  458. if (propertiesToReturn.getAllScopes())
  459. wuPropertyTypeMask |= PTscope;
  460. }
  461. wuScopeFilter.addOutputProperties(wuPropertyTypeMask);
  462. wuScopeFilter.finishedFilter();
  463. }
  464. void WUDetails::buildPropertyFilter(IArrayOf<IConstWUPropertyFilter> & reqPropertyFilter)
  465. {
  466. ForEachItemIn(idx,reqPropertyFilter)
  467. {
  468. IConstWUPropertyFilter & attribFilterItem = reqPropertyFilter.item(idx);
  469. const char * propertyName = attribFilterItem.getName();
  470. if ( !propertyName || *propertyName==0 ) continue;
  471. const char *exactValue = attribFilterItem.getExactValue();
  472. const char *minValue = attribFilterItem.getMinValue();
  473. const char *maxValue = attribFilterItem.getMaxValue();
  474. const bool hasExactValue = *exactValue!=0;
  475. const bool hasMinValue = *minValue!=0;
  476. const bool hasMaxValue = *maxValue!=0;
  477. if (hasExactValue && (hasMinValue||hasMaxValue))
  478. throw MakeStringException(ECLWATCH_INVALID_INPUT,
  479. "Invalid Property Filter ('%s') - ExactValue may not be used with MinValue or MaxValue",
  480. propertyName);
  481. const StatisticKind sk = queryStatisticKind(propertyName, StKindNone);
  482. if (sk==StKindAll || sk==StKindNone)
  483. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Property Name ('%s') in Property Filter", propertyName);
  484. if (hasExactValue)
  485. {
  486. stat_type exactVal = atoi64(exactValue);
  487. wuScopeFilter.addRequiredStat(sk,exactVal,exactVal);
  488. }
  489. else if (hasMinValue||hasMaxValue)
  490. {
  491. stat_type minVal = atoi64(minValue);
  492. stat_type maxVal = atoi64(maxValue);
  493. wuScopeFilter.addRequiredStat(sk,minVal,maxVal);
  494. }
  495. else
  496. wuScopeFilter.addRequiredStat(sk);
  497. }
  498. }